@zzzen/pyright-internal 1.2.0-dev.20260920 → 1.2.0-dev.20260927
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer/checker.d.ts +2 -1
- package/dist/analyzer/checker.js +15 -1
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/codeFlowEngine.js +9 -3
- package/dist/analyzer/codeFlowEngine.js.map +1 -1
- package/dist/analyzer/operations.js +1 -1
- package/dist/analyzer/operations.js.map +1 -1
- package/dist/analyzer/overloadResult.d.ts +15 -0
- package/dist/analyzer/overloadResult.js +233 -0
- package/dist/analyzer/overloadResult.js.map +1 -0
- package/dist/analyzer/overloadResultAdmission.d.ts +20 -0
- package/dist/analyzer/overloadResultAdmission.js +448 -0
- package/dist/analyzer/overloadResultAdmission.js.map +1 -0
- package/dist/analyzer/overloadResultController.d.ts +227 -0
- package/dist/analyzer/overloadResultController.js +904 -0
- package/dist/analyzer/overloadResultController.js.map +1 -0
- package/dist/analyzer/overloadResultSelector.d.ts +24 -0
- package/dist/analyzer/overloadResultSelector.js +131 -0
- package/dist/analyzer/overloadResultSelector.js.map +1 -0
- package/dist/analyzer/parseTreeUtils.d.ts +1 -0
- package/dist/analyzer/parseTreeUtils.js +4 -0
- package/dist/analyzer/parseTreeUtils.js.map +1 -1
- package/dist/analyzer/program.d.ts +13 -2
- package/dist/analyzer/program.js +98 -46
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/protocols.d.ts +1 -0
- package/dist/analyzer/protocols.js +286 -6
- package/dist/analyzer/protocols.js.map +1 -1
- package/dist/analyzer/sourceFile.d.ts +6 -2
- package/dist/analyzer/sourceFile.js +9 -3
- package/dist/analyzer/sourceFile.js.map +1 -1
- package/dist/analyzer/tracePrinter.js +4 -0
- package/dist/analyzer/tracePrinter.js.map +1 -1
- package/dist/analyzer/typeCacheUtils.d.ts +4 -0
- package/dist/analyzer/typeCacheUtils.js +36 -0
- package/dist/analyzer/typeCacheUtils.js.map +1 -1
- package/dist/analyzer/typeComplexity.js +2 -0
- package/dist/analyzer/typeComplexity.js.map +1 -1
- package/dist/analyzer/typeEvaluator.d.ts +10 -1
- package/dist/analyzer/typeEvaluator.js +351 -11
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +30 -1
- package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
- package/dist/analyzer/typeGuards.d.ts +1 -1
- package/dist/analyzer/typePrinter.js +8 -0
- package/dist/analyzer/typePrinter.js.map +1 -1
- package/dist/analyzer/typeUtils.d.ts +1 -1
- package/dist/analyzer/typeUtils.js +29 -26
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typeWalker.d.ts +2 -1
- package/dist/analyzer/typeWalker.js +12 -0
- package/dist/analyzer/typeWalker.js.map +1 -1
- package/dist/analyzer/typedDicts.js +1 -0
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +16 -2
- package/dist/analyzer/types.js +94 -2
- package/dist/analyzer/types.js.map +1 -1
- package/dist/common/configOptions.d.ts +1 -0
- package/dist/common/configOptions.js +2 -0
- package/dist/common/configOptions.js.map +1 -1
- package/dist/languageServerBase.js +2 -2
- package/dist/languageServerBase.js.map +1 -1
- package/dist/languageService/callHierarchyProvider.js +3 -2
- package/dist/languageService/callHierarchyProvider.js.map +1 -1
- package/dist/languageService/completionProvider.js +4 -1
- package/dist/languageService/completionProvider.js.map +1 -1
- package/dist/tests/config.test.js +48 -0
- package/dist/tests/config.test.js.map +1 -1
- package/dist/tests/fourslash/showcallhierarchy.incomingCalls.aliasedFunction.fourslash.js +10 -6
- package/dist/tests/fourslash/showcallhierarchy.incomingCalls.aliasedFunction.fourslash.js.map +1 -1
- package/dist/tests/fourslash/showcallhierarchy.incomingCalls.function.fourslash.js +16 -10
- package/dist/tests/fourslash/showcallhierarchy.incomingCalls.function.fourslash.js.map +1 -1
- package/dist/tests/harness/fourslash/testState.js +10 -9
- package/dist/tests/harness/fourslash/testState.js.map +1 -1
- package/dist/tests/languageServer.test.js +129 -0
- package/dist/tests/languageServer.test.js.map +1 -1
- package/dist/tests/overloadResult.test.d.ts +1 -0
- package/dist/tests/overloadResult.test.js +182 -0
- package/dist/tests/overloadResult.test.js.map +1 -0
- package/dist/tests/overloadResultController.test.d.ts +1 -0
- package/dist/tests/overloadResultController.test.js +2146 -0
- package/dist/tests/overloadResultController.test.js.map +1 -0
- package/dist/tests/protocolRequirement.test.d.ts +1 -0
- package/dist/tests/protocolRequirement.test.js +122 -0
- package/dist/tests/protocolRequirement.test.js.map +1 -0
- package/dist/tests/protocolRequirementAdversarial.test.d.ts +1 -0
- package/dist/tests/protocolRequirementAdversarial.test.js +92 -0
- package/dist/tests/protocolRequirementAdversarial.test.js.map +1 -0
- package/dist/tests/protocolRequirementBoundary.test.d.ts +1 -0
- package/dist/tests/protocolRequirementBoundary.test.js +119 -0
- package/dist/tests/protocolRequirementBoundary.test.js.map +1 -0
- package/dist/tests/protocolRequirementComplexity.test.d.ts +1 -0
- package/dist/tests/protocolRequirementComplexity.test.js +159 -0
- package/dist/tests/protocolRequirementComplexity.test.js.map +1 -0
- package/dist/tests/protocolRequirementCycles.test.d.ts +1 -0
- package/dist/tests/protocolRequirementCycles.test.js +160 -0
- package/dist/tests/protocolRequirementCycles.test.js.map +1 -0
- package/dist/tests/protocolRequirementGeneral.test.d.ts +1 -0
- package/dist/tests/protocolRequirementGeneral.test.js +120 -0
- package/dist/tests/protocolRequirementGeneral.test.js.map +1 -0
- package/dist/tests/protocolRequirementInstances.test.d.ts +1 -0
- package/dist/tests/protocolRequirementInstances.test.js +164 -0
- package/dist/tests/protocolRequirementInstances.test.js.map +1 -0
- package/dist/tests/protocolRequirementListStub.test.d.ts +1 -0
- package/dist/tests/protocolRequirementListStub.test.js +244 -0
- package/dist/tests/protocolRequirementListStub.test.js.map +1 -0
- package/dist/tests/protocolRequirementPopulated.test.d.ts +1 -0
- package/dist/tests/protocolRequirementPopulated.test.js +172 -0
- package/dist/tests/protocolRequirementPopulated.test.js.map +1 -0
- package/dist/tests/protocolRequirementRecursive.test.d.ts +1 -0
- package/dist/tests/protocolRequirementRecursive.test.js +118 -0
- package/dist/tests/protocolRequirementRecursive.test.js.map +1 -0
- package/dist/tests/protocolRequirementSpeculative.test.d.ts +1 -0
- package/dist/tests/protocolRequirementSpeculative.test.js +200 -0
- package/dist/tests/protocolRequirementSpeculative.test.js.map +1 -0
- package/dist/tests/protocolRequirementState.test.d.ts +1 -0
- package/dist/tests/protocolRequirementState.test.js +161 -0
- package/dist/tests/protocolRequirementState.test.js.map +1 -0
- package/dist/tests/testState.test.js +64 -0
- package/dist/tests/testState.test.js.map +1 -1
- package/dist/tests/testUtils.d.ts +6 -1
- package/dist/tests/testUtils.js +11 -6
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/tests/typeCacheIsolation.test.d.ts +1 -0
- package/dist/tests/typeCacheIsolation.test.js +109 -0
- package/dist/tests/typeCacheIsolation.test.js.map +1 -0
- package/dist/tests/typeCacheUtils.test.js +59 -0
- package/dist/tests/typeCacheUtils.test.js.map +1 -1
- package/dist/tests/typeEvaluator1.test.js +5 -1
- package/dist/tests/typeEvaluator1.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +6 -2
- package/dist/tests/typeEvaluator4.test.js.map +1 -1
- package/dist/tests/typeEvaluator5.test.js +25 -0
- package/dist/tests/typeEvaluator5.test.js.map +1 -1
- package/dist/tests/typeEvaluator6.test.js +7 -23
- package/dist/tests/typeEvaluator6.test.js.map +1 -1
- package/dist/tests/typeEvaluator7.test.js +237 -2
- package/dist/tests/typeEvaluator7.test.js.map +1 -1
- package/dist/tests/typeServer/typeServer.inProc.test.js +86 -0
- package/dist/tests/typeServer/typeServer.inProc.test.js.map +1 -1
- package/dist/tests/typeUtils.test.js +36 -0
- package/dist/tests/typeUtils.test.js.map +1 -1
- package/dist/trace/nativeAdapter.js +1 -5
- package/dist/trace/nativeAdapter.js.map +1 -1
- package/dist/typeServer/protocol/typeServerProtocol.d.ts +8 -2
- package/dist/typeServer/protocol/typeServerProtocol.js +1 -0
- package/dist/typeServer/protocol/typeServerProtocol.js.map +1 -1
- package/dist/typeServer/typeServerConversionUtils.js +9 -0
- package/dist/typeServer/typeServerConversionUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,904 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* overloadResultController.ts
|
|
4
|
+
* Copyright (c) Microsoft Corporation.
|
|
5
|
+
* Licensed under the MIT license.
|
|
6
|
+
*
|
|
7
|
+
* Bounded local overload alternatives and operation control.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ExperimentalOverloadResultController = void 0;
|
|
11
|
+
const debug_1 = require("../common/debug");
|
|
12
|
+
const diagnosticSink_1 = require("../common/diagnosticSink");
|
|
13
|
+
const parseNodes_1 = require("../parser/parseNodes");
|
|
14
|
+
const analyzerNodeInfo_1 = require("./analyzerNodeInfo");
|
|
15
|
+
const overloadResultAdmission_1 = require("./overloadResultAdmission");
|
|
16
|
+
const overloadResultSelector_1 = require("./overloadResultSelector");
|
|
17
|
+
const types_1 = require("./types");
|
|
18
|
+
const defaultLimits = {
|
|
19
|
+
nodes: 4096,
|
|
20
|
+
records: 256,
|
|
21
|
+
rootNodes: 256,
|
|
22
|
+
graphUnits: 32768,
|
|
23
|
+
candidates: 32,
|
|
24
|
+
calls: 256,
|
|
25
|
+
proofUnits: 512,
|
|
26
|
+
};
|
|
27
|
+
class CandidateCutoff extends Error {
|
|
28
|
+
}
|
|
29
|
+
class ActivationRestart extends Error {
|
|
30
|
+
}
|
|
31
|
+
class ExperimentalOverloadResultController {
|
|
32
|
+
constructor(_options, _evaluator, reader) {
|
|
33
|
+
this._options = _options;
|
|
34
|
+
this._evaluator = _evaluator;
|
|
35
|
+
this.roots = new Map();
|
|
36
|
+
this._generations = new Map();
|
|
37
|
+
this._emptyModules = new WeakSet();
|
|
38
|
+
this._expiredModules = new WeakSet();
|
|
39
|
+
this._disposed = false;
|
|
40
|
+
this._activationBoundary = false;
|
|
41
|
+
this._activationCanRestart = false;
|
|
42
|
+
this._discovering = false;
|
|
43
|
+
this._activationChecked = new WeakSet();
|
|
44
|
+
this._activated = new WeakSet();
|
|
45
|
+
this._pendingActivation = new Set();
|
|
46
|
+
this._automaticWork = {
|
|
47
|
+
modules: 0,
|
|
48
|
+
nodes: 0,
|
|
49
|
+
scanCutoffs: 0,
|
|
50
|
+
seeds: 0,
|
|
51
|
+
graphAdmitted: 0,
|
|
52
|
+
selections: 0,
|
|
53
|
+
selected: 0,
|
|
54
|
+
proofUnits: 0,
|
|
55
|
+
activationArgumentChecks: 0,
|
|
56
|
+
activationProbes: 0,
|
|
57
|
+
activationProofUnits: 0,
|
|
58
|
+
activations: 0,
|
|
59
|
+
reasons: new Map(),
|
|
60
|
+
};
|
|
61
|
+
this.installCacheIsolation = (isolation) => {
|
|
62
|
+
(0, debug_1.assert)(!this._cacheIsolation && !this._disposed);
|
|
63
|
+
this._cacheIsolation = isolation;
|
|
64
|
+
};
|
|
65
|
+
this.installSelector = (select) => {
|
|
66
|
+
this._select = select;
|
|
67
|
+
};
|
|
68
|
+
this.installActivationBoundary = (canActivate, flush) => {
|
|
69
|
+
this._canActivate = canActivate;
|
|
70
|
+
this._flushActivation = flush;
|
|
71
|
+
};
|
|
72
|
+
this.installQueryCache = (capture) => {
|
|
73
|
+
this._captureQueryCache = capture;
|
|
74
|
+
};
|
|
75
|
+
this.installCheckerHandoff = (handoff) => {
|
|
76
|
+
this._checkerHandoff = handoff;
|
|
77
|
+
};
|
|
78
|
+
this.dispose = () => {
|
|
79
|
+
for (const generation of this._generations.values()) {
|
|
80
|
+
this._retire(generation);
|
|
81
|
+
}
|
|
82
|
+
this._generations.clear();
|
|
83
|
+
this._pendingActivation.clear();
|
|
84
|
+
this._disposed = true;
|
|
85
|
+
};
|
|
86
|
+
this.dispatch = (_node, _flags, _context) => undefined;
|
|
87
|
+
this.route = (request) => {
|
|
88
|
+
(0, debug_1.assert)(!this._disposed, 'Retired overload-result controller');
|
|
89
|
+
if (request.kind !== 'statement') {
|
|
90
|
+
const result = this._query(request.node, request.kind === 'expression' ? request.flags : 0 /* EvalFlags.None */, request.kind === 'expression' ? request.context : undefined, request.kind === 'query');
|
|
91
|
+
return result ? { result } : undefined;
|
|
92
|
+
}
|
|
93
|
+
const generation = this._ensure(request.node);
|
|
94
|
+
const record = generation?.admission.byNode.get(request.node);
|
|
95
|
+
if (!generation ||
|
|
96
|
+
!record ||
|
|
97
|
+
!this._isEnabled(generation, record) ||
|
|
98
|
+
record.assignment !== request.node ||
|
|
99
|
+
this._active?.record === record) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
(0, debug_1.assert)(!generation.building.has(record));
|
|
103
|
+
const outcome = this._build(generation, record);
|
|
104
|
+
const selected = record.annotated ? outcome.successes[0] : undefined;
|
|
105
|
+
this._trial(generation, record, selected ? 'materialize-witness' : 'materialize-baseline', outcome.inputs, selected?.candidate, request.evaluate, true);
|
|
106
|
+
return {};
|
|
107
|
+
};
|
|
108
|
+
this.project = (node, result) => {
|
|
109
|
+
const active = this._active;
|
|
110
|
+
if (!active) {
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
if (active.record.seed?.node === node && active.candidate) {
|
|
114
|
+
result = { ...result, type: active.candidate };
|
|
115
|
+
}
|
|
116
|
+
const use = active.inputs.get(node);
|
|
117
|
+
// Contextual requests use ordinary assignment restoration, not value
|
|
118
|
+
// substitution that could overwrite a flag-sensitive Name failure.
|
|
119
|
+
if (use && !active.record.reader && active.mode !== 'context') {
|
|
120
|
+
const value = use.value.type;
|
|
121
|
+
result = {
|
|
122
|
+
...result,
|
|
123
|
+
type: (0, types_1.isOverloadResult)(value) ? active.candidate ?? value.priv.baselineType : value,
|
|
124
|
+
};
|
|
125
|
+
this._emit({ kind: 'project', node, source: value, result, mode: active.mode });
|
|
126
|
+
}
|
|
127
|
+
if (active.record.ids.has(node.id)) {
|
|
128
|
+
active.seen.set(node, result);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
this.beforeCall = (node) => {
|
|
133
|
+
const active = this._active;
|
|
134
|
+
if (!active) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this._emit({ kind: 'beforeCall', node, mode: active.mode, seen: active.seen });
|
|
138
|
+
if (active.mode === 'candidate') {
|
|
139
|
+
const reservation = active.reservation;
|
|
140
|
+
if (reservation.used >= reservation.limit) {
|
|
141
|
+
throw new CandidateCutoff();
|
|
142
|
+
}
|
|
143
|
+
reservation.used++;
|
|
144
|
+
active.generation.work.candidateCalls++;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
active.generation.work.ordinaryCalls++;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
this.check = (module) => {
|
|
151
|
+
const initialGeneration = this._ensure(module);
|
|
152
|
+
if (!initialGeneration && !this._options.automatic) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
initialGeneration?.published.clear();
|
|
156
|
+
const walk = (node, callback) => {
|
|
157
|
+
if (node.nodeType === 47 /* ParseNodeType.StatementList */ && this.needsActivationBoundary()) {
|
|
158
|
+
return this.runWithActivation(() => walk(node, callback));
|
|
159
|
+
}
|
|
160
|
+
const generation = this._ensure(module);
|
|
161
|
+
const record = generation?.admission.records.get(node);
|
|
162
|
+
if (this._active || !generation || !record || !this._isEnabled(generation, record)) {
|
|
163
|
+
callback();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
let handedOff;
|
|
167
|
+
const canHandoff = this._options.automatic &&
|
|
168
|
+
this._options.checkerHandoff === true &&
|
|
169
|
+
!this._options.observe &&
|
|
170
|
+
!record.assignment &&
|
|
171
|
+
!record.seed &&
|
|
172
|
+
!record.reader &&
|
|
173
|
+
!record.context &&
|
|
174
|
+
!record.flags &&
|
|
175
|
+
record.root.nodeType === 47 /* ParseNodeType.StatementList */ &&
|
|
176
|
+
record.statement === record.expression &&
|
|
177
|
+
record.expression.nodeType === 9 /* ParseNodeType.Call */;
|
|
178
|
+
const output = this._build(generation, record, canHandoff
|
|
179
|
+
? (inputs, candidate, result, diagnostics) => {
|
|
180
|
+
if (diagnostics.length || result.typeErrors || result.isIncomplete) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
this._checkerHandoff?.(record.root, record.expression, result, () => {
|
|
184
|
+
handedOff = this._trial(generation, record, 'check-candidate', inputs, candidate, callback, false, undefined, undefined, true);
|
|
185
|
+
generation.work.checkerHandoffs++;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
: undefined);
|
|
189
|
+
const selected = output.successes[0];
|
|
190
|
+
const mode = record.reader ? 'reader' : selected ? 'check-candidate' : 'check-baseline';
|
|
191
|
+
const committed = handedOff ?? this._trial(generation, record, mode, output.inputs, selected?.candidate, callback);
|
|
192
|
+
(0, debug_1.assert)(!generation.published.has(record));
|
|
193
|
+
generation.published.add(record);
|
|
194
|
+
committed.diagnostics.forEach((d) => generation.file.diagnosticSink.addDiagnostic(d));
|
|
195
|
+
this._emit({ kind: 'publish', root: record.root, diagnostics: committed.diagnostics });
|
|
196
|
+
};
|
|
197
|
+
return {
|
|
198
|
+
walk,
|
|
199
|
+
dispose: () => { },
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
this._limits = { ...defaultLimits, ..._options.limits };
|
|
203
|
+
(0, debug_1.assert)(!_options.automatic || !_options.seeds, 'Automatic discovery cannot use injected seeds');
|
|
204
|
+
for (const key of Object.keys(defaultLimits)) {
|
|
205
|
+
const value = this._limits[key];
|
|
206
|
+
(0, debug_1.assert)(Number.isInteger(value) && value >= 0 && value <= defaultLimits[key], `Invalid ${key} limit`);
|
|
207
|
+
}
|
|
208
|
+
for (const value of [_options.producerCalls, _options.consumerCalls]) {
|
|
209
|
+
(0, debug_1.assert)(value === undefined || (Number.isInteger(value) && value >= 0 && value <= defaultLimits.calls));
|
|
210
|
+
}
|
|
211
|
+
this._info = (0, analyzerNodeInfo_1.createAnalyzerNodeInfoAccessor)(reader);
|
|
212
|
+
}
|
|
213
|
+
get isAutomatic() {
|
|
214
|
+
return !!this._options.automatic;
|
|
215
|
+
}
|
|
216
|
+
get hasPendingActivation() {
|
|
217
|
+
return this._pendingActivation.size > 0;
|
|
218
|
+
}
|
|
219
|
+
getAutomaticStats() {
|
|
220
|
+
return { ...this._automaticWork, reasons: Object.fromEntries(this._automaticWork.reasons) };
|
|
221
|
+
}
|
|
222
|
+
getDiagnosticSink(node) {
|
|
223
|
+
const active = this._active;
|
|
224
|
+
const record = active?.generation.admission.byNode.get(node);
|
|
225
|
+
if (!active ||
|
|
226
|
+
!record ||
|
|
227
|
+
this._isEnabled(active.generation, record) ||
|
|
228
|
+
record.fn !== active.record.fn ||
|
|
229
|
+
record.root.start >= active.record.root.start) {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
// Earlier ordinary flow prerequisites keep their native caches. Their
|
|
233
|
+
// diagnostics must likewise outlive this operation's private trial.
|
|
234
|
+
let outer = active;
|
|
235
|
+
while (outer.parent?.generation === active.generation) {
|
|
236
|
+
outer = outer.parent;
|
|
237
|
+
}
|
|
238
|
+
return outer.previousSink;
|
|
239
|
+
}
|
|
240
|
+
needsActivationBoundary() {
|
|
241
|
+
return this._options.automatic && !this._activationBoundary && !this._active;
|
|
242
|
+
}
|
|
243
|
+
runWithActivation(callback) {
|
|
244
|
+
(0, debug_1.assert)(!this._disposed, 'Retired overload-result controller');
|
|
245
|
+
(0, debug_1.assert)(!this._activationBoundary);
|
|
246
|
+
this._activationBoundary = true;
|
|
247
|
+
try {
|
|
248
|
+
this._activationCanRestart = this._canActivate();
|
|
249
|
+
while (true) {
|
|
250
|
+
try {
|
|
251
|
+
if (this._activationCanRestart && this.hasPendingActivation) {
|
|
252
|
+
this._flushActivation();
|
|
253
|
+
}
|
|
254
|
+
return callback();
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
if (!(error instanceof ActivationRestart)) {
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
finally {
|
|
264
|
+
this._activationBoundary = false;
|
|
265
|
+
this._activationCanRestart = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
considerActivation(node, args) {
|
|
269
|
+
if (!this._options.automatic ||
|
|
270
|
+
(this._active &&
|
|
271
|
+
(!this._activationCanRestart ||
|
|
272
|
+
this._active.parent ||
|
|
273
|
+
this._active.mode !== 'baseline' ||
|
|
274
|
+
this._active.record.ids.has(node.id))) ||
|
|
275
|
+
this._discovering ||
|
|
276
|
+
!this._activationBoundary ||
|
|
277
|
+
this._activationChecked.has(node) ||
|
|
278
|
+
!(0, overloadResultSelector_1.isAutomaticOverloadSeedSyntax)(node)) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this._automaticWork.activationArgumentChecks++;
|
|
282
|
+
if (!args.some((arg) => (0, types_1.isClassInstance)(arg.argType) &&
|
|
283
|
+
arg.argType.priv.typeArgs?.length &&
|
|
284
|
+
(0, overloadResultSelector_1.isFixedOverloadArgumentShape)(arg.argType, new overloadResultSelector_1.OverloadSelectionBudget(this._limits.proofUnits)) &&
|
|
285
|
+
(0, overloadResultSelector_1.hasNestedOverloadAny)(arg.argType))) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
this._discovering = true;
|
|
289
|
+
try {
|
|
290
|
+
if (!(0, overloadResultSelector_1.findAutomaticOverloadSeeds)([node], this._evaluator()).length) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const selection = this._select(node, this._limits.candidates, this._limits.proofUnits);
|
|
294
|
+
this._automaticWork.activationProbes++;
|
|
295
|
+
this._automaticWork.activationProofUnits += selection.units;
|
|
296
|
+
this._emit({ kind: 'activationProbe', node, selection });
|
|
297
|
+
if (selection.reason === 'selected') {
|
|
298
|
+
this._activationChecked.add(node);
|
|
299
|
+
this._pendingActivation.add(node);
|
|
300
|
+
// Unwind native speculation before it can publish or cache
|
|
301
|
+
// further uses of the provisional ordinary result.
|
|
302
|
+
if (this._activationCanRestart) {
|
|
303
|
+
throw new ActivationRestart();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
finally {
|
|
308
|
+
this._discovering = false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
finishActivation() {
|
|
312
|
+
if (this._active || this._discovering || !this._pendingActivation.size) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
let activated = false;
|
|
316
|
+
this._discovering = true;
|
|
317
|
+
try {
|
|
318
|
+
for (const node of this._pendingActivation) {
|
|
319
|
+
this._activated.add(node);
|
|
320
|
+
const generation = this._ensure(node, true);
|
|
321
|
+
const record = generation?.admission.byNode.get(node);
|
|
322
|
+
if (generation && record?.admitted && record.seed?.node === node) {
|
|
323
|
+
this._reserveGeneration(generation);
|
|
324
|
+
this._automaticWork.activations++;
|
|
325
|
+
activated = true;
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
this._activated.delete(node);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
this._pendingActivation.clear();
|
|
332
|
+
}
|
|
333
|
+
finally {
|
|
334
|
+
this._discovering = false;
|
|
335
|
+
}
|
|
336
|
+
if (activated) {
|
|
337
|
+
throw new ActivationRestart();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
evict(module) {
|
|
341
|
+
(0, debug_1.assert)(!this._active);
|
|
342
|
+
const generation = this._ensure(module);
|
|
343
|
+
generation?.admission.records.forEach((record) => {
|
|
344
|
+
if (this._isEnabled(generation, record)) {
|
|
345
|
+
this._cacheIsolation.evict(record.root);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
getStats(module) {
|
|
350
|
+
if (this._disposed) {
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
const generation = this._generations.get(this._info.getFileInfo(module).fileUri.key);
|
|
354
|
+
if (!generation || generation.module !== module) {
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
...generation.work,
|
|
359
|
+
records: generation.admission.records.size,
|
|
360
|
+
outcomes: generation.outcomes.size,
|
|
361
|
+
variants: [...generation.variants.values()].reduce((n, v) => n + v.size, 0),
|
|
362
|
+
slots: generation.slots.size,
|
|
363
|
+
candidateCallCeiling: [...generation.slots.values()].reduce((n, s) => n + s.limit, 0),
|
|
364
|
+
interruptedSlots: generation.interrupted.size,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
_emit(event) {
|
|
368
|
+
this._options.observe?.(event);
|
|
369
|
+
}
|
|
370
|
+
_retire(generation) {
|
|
371
|
+
this._emit({ kind: 'retire', module: generation.module, outcomes: generation.outcomes.size });
|
|
372
|
+
this._expiredModules.add(generation.module);
|
|
373
|
+
generation.admission.records.forEach((record) => this.roots.delete(record.root));
|
|
374
|
+
generation.variants.forEach((_, node) => this.roots.delete(node));
|
|
375
|
+
generation.outcomes.clear();
|
|
376
|
+
generation.variants.clear();
|
|
377
|
+
generation.slots.clear();
|
|
378
|
+
generation.interrupted.clear();
|
|
379
|
+
generation.ordinaryQueryCaches.clear();
|
|
380
|
+
}
|
|
381
|
+
_ensure(node, activate = false) {
|
|
382
|
+
if (this._options.automatic && !activate && !this._generations.size) {
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
let root = node;
|
|
386
|
+
while (root.parent) {
|
|
387
|
+
root = root.parent;
|
|
388
|
+
}
|
|
389
|
+
if (root.nodeType !== 36 /* ParseNodeType.Module */ || this._emptyModules.has(root)) {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
(0, debug_1.assert)(!this._expiredModules.has(root), 'Expired overload-result parse generation');
|
|
393
|
+
const file = this._info.getFileInfo(root);
|
|
394
|
+
const old = this._generations.get(file.fileUri.key);
|
|
395
|
+
if (old?.module === root) {
|
|
396
|
+
return old;
|
|
397
|
+
}
|
|
398
|
+
if (old) {
|
|
399
|
+
this._retire(old);
|
|
400
|
+
this._generations.delete(file.fileUri.key);
|
|
401
|
+
}
|
|
402
|
+
if (this._options.automatic && !activate) {
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
let seeds = this._options.seeds?.(root) ?? [];
|
|
406
|
+
if (this._options.automatic) {
|
|
407
|
+
let nodes = [];
|
|
408
|
+
let cutoff = false;
|
|
409
|
+
try {
|
|
410
|
+
nodes = (0, overloadResultAdmission_1.collectOverloadResultNodes)(root, this._limits.nodes);
|
|
411
|
+
seeds = (0, overloadResultSelector_1.findAutomaticOverloadSeeds)(nodes, this._evaluator()).map((node) => ({
|
|
412
|
+
node,
|
|
413
|
+
uncertainty: 2 /* TypeCategory.Any */,
|
|
414
|
+
automatic: true,
|
|
415
|
+
candidates: () => {
|
|
416
|
+
const selection = this._select(node, this._limits.candidates, this._limits.proofUnits);
|
|
417
|
+
this._automaticWork.selections++;
|
|
418
|
+
this._automaticWork.selected += selection.reason === 'selected' ? 1 : 0;
|
|
419
|
+
this._automaticWork.proofUnits += selection.units;
|
|
420
|
+
const reasons = this._automaticWork.reasons;
|
|
421
|
+
reasons.set(selection.reason, (reasons.get(selection.reason) ?? 0) + 1);
|
|
422
|
+
this._emit({ kind: 'selection', node, selection });
|
|
423
|
+
return selection.candidates;
|
|
424
|
+
},
|
|
425
|
+
}));
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
if (!(error instanceof overloadResultAdmission_1.OverloadResultAdmissionLimit)) {
|
|
429
|
+
throw error;
|
|
430
|
+
}
|
|
431
|
+
cutoff = true;
|
|
432
|
+
}
|
|
433
|
+
this._automaticWork.modules++;
|
|
434
|
+
this._automaticWork.nodes += cutoff ? this._limits.nodes + 1 : nodes.length;
|
|
435
|
+
this._automaticWork.seeds += seeds.length;
|
|
436
|
+
this._automaticWork.scanCutoffs += cutoff ? 1 : 0;
|
|
437
|
+
this._emit({ kind: 'scan', module: root, nodes: nodes.length, seeds: seeds.length, cutoff });
|
|
438
|
+
}
|
|
439
|
+
if (!seeds.length) {
|
|
440
|
+
this._emptyModules.add(root);
|
|
441
|
+
return undefined;
|
|
442
|
+
}
|
|
443
|
+
const admission = (0, overloadResultAdmission_1.admitLocalOverloadResults)(root, seeds, this._evaluator(), this._info, this._limits);
|
|
444
|
+
if (this._options.automatic) {
|
|
445
|
+
this._automaticWork.graphAdmitted += [...admission.records.values()].filter((r) => r.seed && r.admitted).length;
|
|
446
|
+
for (const decision of admission.decisions.values()) {
|
|
447
|
+
for (const reason of decision) {
|
|
448
|
+
const key = `admission:${reason}`;
|
|
449
|
+
this._automaticWork.reasons.set(key, (this._automaticWork.reasons.get(key) ?? 0) + 1);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (!admission.complete) {
|
|
453
|
+
const key = `admission:${admission.reason}`;
|
|
454
|
+
this._automaticWork.reasons.set(key, (this._automaticWork.reasons.get(key) ?? 0) + 1);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const generation = {
|
|
458
|
+
module: root,
|
|
459
|
+
file,
|
|
460
|
+
admission,
|
|
461
|
+
outcomes: new Map(),
|
|
462
|
+
variants: new Map(),
|
|
463
|
+
slots: new Map(),
|
|
464
|
+
interrupted: new Set(),
|
|
465
|
+
building: new Set(),
|
|
466
|
+
preparing: false,
|
|
467
|
+
published: new Set(),
|
|
468
|
+
ordinaryQueryCaches: new Map(),
|
|
469
|
+
work: {
|
|
470
|
+
candidateCalls: 0,
|
|
471
|
+
candidateTrials: 0,
|
|
472
|
+
ordinaryCalls: 0,
|
|
473
|
+
ordinaryRequests: 0,
|
|
474
|
+
projectionSetup: 0,
|
|
475
|
+
contextualRequests: 0,
|
|
476
|
+
retryReservations: 0,
|
|
477
|
+
checkerHandoffs: 0,
|
|
478
|
+
},
|
|
479
|
+
};
|
|
480
|
+
this._emit({ kind: 'admission', module: root, admission });
|
|
481
|
+
this._generations.set(file.fileUri.key, generation);
|
|
482
|
+
this._reserveGeneration(generation);
|
|
483
|
+
return generation;
|
|
484
|
+
}
|
|
485
|
+
_isEnabled(generation, record) {
|
|
486
|
+
return (record.admitted &&
|
|
487
|
+
(!this._options.automatic ||
|
|
488
|
+
[...(generation.admission.dependencies.get(record) ?? [])].every((origin) => !!origin.seed && this._activated.has(origin.seed.node))));
|
|
489
|
+
}
|
|
490
|
+
_reserveGeneration(generation) {
|
|
491
|
+
const reserve = (node, flags, seed) => {
|
|
492
|
+
const key = this._key(node, flags);
|
|
493
|
+
if (!generation.slots.has(key)) {
|
|
494
|
+
generation.slots.set(key, {
|
|
495
|
+
used: 0,
|
|
496
|
+
attempts: 0,
|
|
497
|
+
limit: (seed ? this._options.producerCalls : this._options.consumerCalls) ?? this._limits.calls,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
for (const record of generation.admission.records.values()) {
|
|
502
|
+
if (!this._isEnabled(generation, record)) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
this.roots.set(record.root, record.ids);
|
|
506
|
+
reserve(record.root, 0 /* EvalFlags.None */, !!record.seed);
|
|
507
|
+
for (const value of record.valueNodes) {
|
|
508
|
+
if ((0, parseNodes_1.isExpressionNode)(value)) {
|
|
509
|
+
const seed = record.seed?.node;
|
|
510
|
+
const containsSeed = !!seed && seed.start >= value.start && seed.start + seed.length <= value.start + value.length;
|
|
511
|
+
reserve(value, 0 /* EvalFlags.None */, containsSeed);
|
|
512
|
+
reserve(value, 2 /* EvalFlags.NoSpecialize */, containsSeed);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
_key(node, flags = 0 /* EvalFlags.None */) {
|
|
518
|
+
return `${node.id}:${flags}`;
|
|
519
|
+
}
|
|
520
|
+
_definition(generation, node) {
|
|
521
|
+
return generation.admission.definitions.get(node) ?? generation.admission.reaching.get(node);
|
|
522
|
+
}
|
|
523
|
+
_inputs(generation, record) {
|
|
524
|
+
const uses = [];
|
|
525
|
+
for (const node of record.nodes) {
|
|
526
|
+
if (node.nodeType !== 38 /* ParseNodeType.Name */ || node === record.target) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
const producer = this._definition(generation, node);
|
|
530
|
+
if (!producer || !this._isEnabled(generation, producer) || producer === record) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
const value = this._build(generation, producer).value;
|
|
534
|
+
if (value) {
|
|
535
|
+
uses.push({ node, value });
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
const alternatives = uses.filter((use) => (0, types_1.isOverloadResult)(use.value.type));
|
|
539
|
+
(0, debug_1.assert)(alternatives.length <= 1, 'Prepublication admission invariant');
|
|
540
|
+
return { uses, alternative: alternatives[0] };
|
|
541
|
+
}
|
|
542
|
+
_trial(generation, record, mode, inputs, candidate, callback, retain = false, reservation, continuation, liveCheckerCache = false) {
|
|
543
|
+
const evaluator = this._evaluator();
|
|
544
|
+
const parent = this._active;
|
|
545
|
+
const previousSink = generation.file.diagnosticSink;
|
|
546
|
+
const sink = new diagnosticSink_1.TextRangeDiagnosticSink(generation.file.lines);
|
|
547
|
+
const nestedSpeculative = !!parent && evaluator.isSpeculativeModeInUse(undefined);
|
|
548
|
+
(0, debug_1.assert)(!nestedSpeculative || retain);
|
|
549
|
+
(0, debug_1.assert)(!liveCheckerCache ||
|
|
550
|
+
(parent?.record === record &&
|
|
551
|
+
parent.mode === 'candidate' &&
|
|
552
|
+
mode === 'check-candidate' &&
|
|
553
|
+
!nestedSpeculative &&
|
|
554
|
+
!retain &&
|
|
555
|
+
!reservation));
|
|
556
|
+
const projections = new Map(inputs.uses.map((use) => [use.node, use]));
|
|
557
|
+
generation.work.projectionSetup += projections.size;
|
|
558
|
+
(0, debug_1.assert)(projections.size <= this._limits.rootNodes);
|
|
559
|
+
const active = {
|
|
560
|
+
generation,
|
|
561
|
+
record,
|
|
562
|
+
parent,
|
|
563
|
+
previousSink,
|
|
564
|
+
mode,
|
|
565
|
+
inputs: projections,
|
|
566
|
+
candidate,
|
|
567
|
+
reservation,
|
|
568
|
+
seen: new Map(),
|
|
569
|
+
};
|
|
570
|
+
if (mode === 'candidate') {
|
|
571
|
+
generation.work.candidateTrials++;
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
generation.work.ordinaryRequests++;
|
|
575
|
+
}
|
|
576
|
+
this._active = active;
|
|
577
|
+
generation.file.diagnosticSink = sink;
|
|
578
|
+
let result;
|
|
579
|
+
let diagnostics = [];
|
|
580
|
+
let completed = false;
|
|
581
|
+
try {
|
|
582
|
+
this._emit({ kind: 'enter', module: generation.module, root: record.root, mode });
|
|
583
|
+
const evaluate = () => {
|
|
584
|
+
if (callback) {
|
|
585
|
+
callback();
|
|
586
|
+
}
|
|
587
|
+
else if (record.assignment) {
|
|
588
|
+
evaluator.evaluateTypesForStatement(record.assignment);
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
return evaluator.getTypeOfExpression(record.expression, record.flags ?? 0 /* EvalFlags.None */, record.context);
|
|
592
|
+
}
|
|
593
|
+
return evaluator.getTypeOfExpression(record.expression, record.flags ?? 0 /* EvalFlags.None */, record.context);
|
|
594
|
+
};
|
|
595
|
+
const evaluateAndContinue = () => {
|
|
596
|
+
const value = evaluate();
|
|
597
|
+
if (continuation) {
|
|
598
|
+
diagnostics = sink.fetchAndClear();
|
|
599
|
+
continuation(value, diagnostics);
|
|
600
|
+
}
|
|
601
|
+
return value;
|
|
602
|
+
};
|
|
603
|
+
result =
|
|
604
|
+
nestedSpeculative || liveCheckerCache
|
|
605
|
+
? evaluateAndContinue()
|
|
606
|
+
: this._cacheIsolation.isolate(record.root, evaluateAndContinue, retain);
|
|
607
|
+
completed = true;
|
|
608
|
+
}
|
|
609
|
+
finally {
|
|
610
|
+
diagnostics.push(...sink.fetchAndClear());
|
|
611
|
+
generation.file.diagnosticSink = previousSink;
|
|
612
|
+
this._active = parent;
|
|
613
|
+
this._emit({
|
|
614
|
+
kind: 'trial',
|
|
615
|
+
root: record.root,
|
|
616
|
+
mode,
|
|
617
|
+
result,
|
|
618
|
+
diagnostics,
|
|
619
|
+
failed: !!result?.typeErrors || diagnostics.some((d) => d.category === 0 /* DiagnosticCategory.Error */),
|
|
620
|
+
retained: retain,
|
|
621
|
+
nestedSpeculative,
|
|
622
|
+
exception: !completed,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
result,
|
|
627
|
+
diagnostics,
|
|
628
|
+
failed: !!result.typeErrors || diagnostics.some((d) => d.category === 0 /* DiagnosticCategory.Error */),
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
_build(generation, record, checkerContinuation) {
|
|
632
|
+
const cached = generation.outcomes.get(record);
|
|
633
|
+
if (cached) {
|
|
634
|
+
return cached;
|
|
635
|
+
}
|
|
636
|
+
if (!this._active && !generation.building.size && !generation.preparing) {
|
|
637
|
+
// A cold read can ask code flow about earlier calls that do not
|
|
638
|
+
// return. Their speculative checks may restore earlier assignments.
|
|
639
|
+
// Complete those static local records before entering a trial, so
|
|
640
|
+
// reentry restores owned outcomes rather than discovering new ones
|
|
641
|
+
// inside somebody else's speculative context.
|
|
642
|
+
generation.preparing = true;
|
|
643
|
+
try {
|
|
644
|
+
for (const prior of generation.admission.records.values()) {
|
|
645
|
+
if (this._isEnabled(generation, prior) &&
|
|
646
|
+
prior.fn === record.fn &&
|
|
647
|
+
prior.root.start < record.root.start) {
|
|
648
|
+
this._build(generation, prior);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
finally {
|
|
653
|
+
generation.preparing = false;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (!this._active && !generation.building.size) {
|
|
657
|
+
for (const slot of generation.interrupted) {
|
|
658
|
+
slot.used = 0;
|
|
659
|
+
slot.attempts = 0;
|
|
660
|
+
generation.work.retryReservations++;
|
|
661
|
+
}
|
|
662
|
+
generation.interrupted.clear();
|
|
663
|
+
}
|
|
664
|
+
const reservation = generation.slots.get(this._key(record.root, record.flags));
|
|
665
|
+
(0, debug_1.assert)(reservation && !generation.interrupted.has(reservation));
|
|
666
|
+
(0, debug_1.assert)(!generation.building.has(record));
|
|
667
|
+
generation.building.add(record);
|
|
668
|
+
try {
|
|
669
|
+
const inputs = this._inputs(generation, record);
|
|
670
|
+
const baseline = this._trial(generation, record, 'baseline', inputs);
|
|
671
|
+
const alias = !!record.target &&
|
|
672
|
+
!record.annotated &&
|
|
673
|
+
record.expression === inputs.alternative?.node &&
|
|
674
|
+
!baseline.failed;
|
|
675
|
+
const successes = [];
|
|
676
|
+
let cutoff = false;
|
|
677
|
+
if (!alias &&
|
|
678
|
+
!record.reader &&
|
|
679
|
+
(!record.target || !baseline.failed || record.annotated) &&
|
|
680
|
+
!baseline.result.isIncomplete) {
|
|
681
|
+
const alternative = inputs.alternative?.value.type;
|
|
682
|
+
try {
|
|
683
|
+
let candidates = [];
|
|
684
|
+
if (record.seed && !baseline.failed) {
|
|
685
|
+
if (record.seed.automatic) {
|
|
686
|
+
// Discovery runs inside the same private ordinary cache
|
|
687
|
+
// and diagnostic transaction as the complete operation.
|
|
688
|
+
const discovery = this._trial(generation, record, 'candidate', inputs, undefined, () => {
|
|
689
|
+
candidates = record.seed.candidates(this._evaluator());
|
|
690
|
+
}, false, reservation);
|
|
691
|
+
if (discovery.failed || discovery.result.isIncomplete) {
|
|
692
|
+
candidates = [];
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
candidates = record.seed.candidates(this._evaluator());
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
else if (alternative && (0, types_1.isOverloadResult)(alternative)) {
|
|
700
|
+
candidates = alternative.priv.candidates;
|
|
701
|
+
}
|
|
702
|
+
if (candidates.length > this._limits.candidates) {
|
|
703
|
+
throw new CandidateCutoff();
|
|
704
|
+
}
|
|
705
|
+
for (const [index, candidate] of candidates.entries()) {
|
|
706
|
+
(0, debug_1.assert)(!(0, types_1.isOverloadResult)(candidate), 'Fixed seeds must be ordinary root alternatives');
|
|
707
|
+
if (reservation.used >= reservation.limit) {
|
|
708
|
+
throw new CandidateCutoff();
|
|
709
|
+
}
|
|
710
|
+
(0, debug_1.assert)(reservation.attempts < this._limits.candidates);
|
|
711
|
+
reservation.attempts++;
|
|
712
|
+
const outcome = this._trial(generation, record, 'candidate', inputs, candidate, undefined, false, reservation, checkerContinuation && !successes.length && index === candidates.length - 1
|
|
713
|
+
? (result, diagnostics) => checkerContinuation(inputs, candidate, result, diagnostics)
|
|
714
|
+
: undefined);
|
|
715
|
+
if (outcome.result.isIncomplete) {
|
|
716
|
+
throw new CandidateCutoff();
|
|
717
|
+
}
|
|
718
|
+
if (!outcome.failed) {
|
|
719
|
+
successes.push({ candidate, outcome });
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
catch (error) {
|
|
724
|
+
if (!(error instanceof CandidateCutoff)) {
|
|
725
|
+
throw error;
|
|
726
|
+
}
|
|
727
|
+
successes.length = 0;
|
|
728
|
+
cutoff = true;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
let canonical = baseline.result;
|
|
732
|
+
if (record.reader) {
|
|
733
|
+
canonical = this._trial(generation, record, 'reader', inputs).result;
|
|
734
|
+
}
|
|
735
|
+
else if (alias) {
|
|
736
|
+
canonical = inputs.alternative.value;
|
|
737
|
+
}
|
|
738
|
+
else if (successes.length) {
|
|
739
|
+
const source = inputs.alternative?.value.type;
|
|
740
|
+
const uncertainty = record.seed?.uncertainty ??
|
|
741
|
+
(source && (0, types_1.isOverloadResult)(source) ? source.priv.uncertaintyKind : 2 /* TypeCategory.Any */);
|
|
742
|
+
canonical = {
|
|
743
|
+
...baseline.result,
|
|
744
|
+
type: types_1.OverloadResultType.create(successes.map((s) => s.outcome.result.type), baseline.result.type, uncertainty),
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
let value;
|
|
748
|
+
if (record.target) {
|
|
749
|
+
value =
|
|
750
|
+
record.annotated && successes.length
|
|
751
|
+
? successes[0].outcome.result
|
|
752
|
+
: !baseline.failed
|
|
753
|
+
? canonical
|
|
754
|
+
: undefined;
|
|
755
|
+
}
|
|
756
|
+
const outcome = { baseline, canonical, value, inputs, successes };
|
|
757
|
+
generation.outcomes.set(record, outcome);
|
|
758
|
+
this._emit({ kind: 'value', root: record.root, canonical, baseline: baseline.result, cutoff });
|
|
759
|
+
return outcome;
|
|
760
|
+
}
|
|
761
|
+
catch (error) {
|
|
762
|
+
generation.interrupted.add(reservation);
|
|
763
|
+
throw error;
|
|
764
|
+
}
|
|
765
|
+
finally {
|
|
766
|
+
generation.building.delete(record);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
_variant(generation, record, node, flags) {
|
|
770
|
+
let variants = generation.variants.get(node);
|
|
771
|
+
if (!variants) {
|
|
772
|
+
variants = new Map();
|
|
773
|
+
generation.variants.set(node, variants);
|
|
774
|
+
}
|
|
775
|
+
let variant = variants.get(flags);
|
|
776
|
+
if (!variant) {
|
|
777
|
+
variant = this._expressionRecord(record, node, flags);
|
|
778
|
+
variants.set(flags, variant);
|
|
779
|
+
this.roots.set(node, variant.ids);
|
|
780
|
+
}
|
|
781
|
+
return variant;
|
|
782
|
+
}
|
|
783
|
+
_expressionRecord(record, node, flags, context) {
|
|
784
|
+
const nodes = (0, overloadResultAdmission_1.collectOverloadResultNodes)(node, this._limits.rootNodes);
|
|
785
|
+
const ordinaryContext = context &&
|
|
786
|
+
((0, types_1.isOverloadResult)(context.expectedType) ||
|
|
787
|
+
(context.returnTypeOverride && (0, types_1.isOverloadResult)(context.returnTypeOverride)))
|
|
788
|
+
? {
|
|
789
|
+
...context,
|
|
790
|
+
expectedType: (0, types_1.isOverloadResult)(context.expectedType)
|
|
791
|
+
? context.expectedType.priv.baselineType
|
|
792
|
+
: context.expectedType,
|
|
793
|
+
returnTypeOverride: context.returnTypeOverride && (0, types_1.isOverloadResult)(context.returnTypeOverride)
|
|
794
|
+
? context.returnTypeOverride.priv.baselineType
|
|
795
|
+
: context.returnTypeOverride,
|
|
796
|
+
}
|
|
797
|
+
: context;
|
|
798
|
+
return {
|
|
799
|
+
...record,
|
|
800
|
+
root: node,
|
|
801
|
+
statement: node,
|
|
802
|
+
expression: node,
|
|
803
|
+
nodes,
|
|
804
|
+
ids: new Set(nodes.map((n) => n.id)),
|
|
805
|
+
assignment: undefined,
|
|
806
|
+
target: undefined,
|
|
807
|
+
annotated: false,
|
|
808
|
+
reader: record.reader && node === record.expression,
|
|
809
|
+
seed: record.seed && nodes.includes(record.seed.node) ? record.seed : undefined,
|
|
810
|
+
flags,
|
|
811
|
+
context: ordinaryContext,
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
_queryOutcome(generation, record, queryNode) {
|
|
815
|
+
const outcome = this._build(generation, record);
|
|
816
|
+
if (!(0, types_1.isOverloadResult)(outcome.canonical.type) && !outcome.inputs.alternative) {
|
|
817
|
+
if (queryNode && generation.ordinaryQueryCaches.get(queryNode)?.()) {
|
|
818
|
+
return outcome.canonical;
|
|
819
|
+
}
|
|
820
|
+
// A declined operation still owns its diagnostics. Restore ordinary
|
|
821
|
+
// subnode caches privately rather than bypassing evaluation or
|
|
822
|
+
// replaying its diagnostics into a public query's live sink.
|
|
823
|
+
const result = this._trial(generation, record, 'materialize-baseline', outcome.inputs, undefined, undefined, true).result;
|
|
824
|
+
if (queryNode) {
|
|
825
|
+
generation.ordinaryQueryCaches.delete(queryNode);
|
|
826
|
+
const guard = !result.isIncomplete && this._captureQueryCache?.(record.root, queryNode);
|
|
827
|
+
if (guard) {
|
|
828
|
+
generation.ordinaryQueryCaches.set(queryNode, guard);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return result;
|
|
832
|
+
}
|
|
833
|
+
return outcome.canonical;
|
|
834
|
+
}
|
|
835
|
+
_query(node, flags, context, publicQuery = false) {
|
|
836
|
+
const isCanonicalContext = (flags === 0 /* EvalFlags.None */ || flags === 2 /* EvalFlags.NoSpecialize */) &&
|
|
837
|
+
(!context || node.nodeType === 38 /* ParseNodeType.Name */);
|
|
838
|
+
if (this._active) {
|
|
839
|
+
// Diagnostic readers also evaluate type arguments. Leave their
|
|
840
|
+
// flag-sensitive validation to the ordinary evaluator in this owner.
|
|
841
|
+
return this._active.mode === 'reader' && isCanonicalContext
|
|
842
|
+
? this._active.inputs.get(node)?.value
|
|
843
|
+
: undefined;
|
|
844
|
+
}
|
|
845
|
+
const generation = this._ensure(node);
|
|
846
|
+
const record = generation?.admission.byNode.get(node);
|
|
847
|
+
if (!generation || !record || !this._isEnabled(generation, record) || !record.valueNodes.has(node)) {
|
|
848
|
+
return undefined;
|
|
849
|
+
}
|
|
850
|
+
if (!isCanonicalContext) {
|
|
851
|
+
// Context-dependent requests are complete ordinary operations, not
|
|
852
|
+
// canonical memo entries. Their actual flags and context never key a
|
|
853
|
+
// persistent table or change the context-free published value.
|
|
854
|
+
const contextual = this._expressionRecord(record, node, flags, context);
|
|
855
|
+
const prior = this.roots.get(node);
|
|
856
|
+
this.roots.set(node, contextual.ids);
|
|
857
|
+
try {
|
|
858
|
+
generation.work.contextualRequests++;
|
|
859
|
+
const result = this._trial(generation, contextual, 'context', this._inputs(generation, contextual)).result;
|
|
860
|
+
this._emit({ kind: 'context', node, flags, context, result });
|
|
861
|
+
return result;
|
|
862
|
+
}
|
|
863
|
+
finally {
|
|
864
|
+
if (prior) {
|
|
865
|
+
this.roots.set(node, prior);
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
this.roots.delete(node);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
// Name evaluation does not use an expected type. Its value is the
|
|
873
|
+
// canonical reaching definition under both supported value flags.
|
|
874
|
+
if (node.nodeType === 38 /* ParseNodeType.Name */) {
|
|
875
|
+
if (node.parent?.nodeType === 35 /* ParseNodeType.MemberAccess */ && node.parent.d.member === node) {
|
|
876
|
+
// A member token represents its enclosing access, not a local.
|
|
877
|
+
return this._query(node.parent, flags, context);
|
|
878
|
+
}
|
|
879
|
+
const definition = this._definition(generation, node);
|
|
880
|
+
const value = definition && this._isEnabled(generation, definition)
|
|
881
|
+
? this._build(generation, definition).value
|
|
882
|
+
: undefined;
|
|
883
|
+
if (value && !(0, types_1.isOverloadResult)(value.type)) {
|
|
884
|
+
// Only public context-free Name readers can reuse a previously
|
|
885
|
+
// owned restoration. The ordinary reader still returns the
|
|
886
|
+
// actual cache entry; expression/flag requests always evaluate.
|
|
887
|
+
this._queryOutcome(generation, record, publicQuery ? node : undefined);
|
|
888
|
+
}
|
|
889
|
+
return value && (0, types_1.isOverloadResult)(value.type) ? value : undefined;
|
|
890
|
+
}
|
|
891
|
+
if (flags === 0 /* EvalFlags.None */ && (node === record.expression || node === record.statement)) {
|
|
892
|
+
return this._queryOutcome(generation, record);
|
|
893
|
+
}
|
|
894
|
+
if (flags === 2 /* EvalFlags.NoSpecialize */ ||
|
|
895
|
+
node.nodeType === 9 /* ParseNodeType.Call */ ||
|
|
896
|
+
node.nodeType === 35 /* ParseNodeType.MemberAccess */ ||
|
|
897
|
+
node.nodeType === 51 /* ParseNodeType.Ternary */) {
|
|
898
|
+
return this._queryOutcome(generation, this._variant(generation, record, node, flags));
|
|
899
|
+
}
|
|
900
|
+
return undefined;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
exports.ExperimentalOverloadResultController = ExperimentalOverloadResultController;
|
|
904
|
+
//# sourceMappingURL=overloadResultController.js.map
|