@typespec/compiler 0.57.0-dev.0 → 0.57.0-dev.13
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/generated-defs/TypeSpec.d.ts +33 -33
- package/dist/generated-defs/TypeSpec.d.ts.map +1 -1
- package/dist/manifest.js +2 -2
- package/dist/src/config/config-schema.d.ts +1 -1
- package/dist/src/config/config-schema.d.ts.map +1 -1
- package/dist/src/config/types.d.ts +2 -2
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/core/binder.d.ts +1 -1
- package/dist/src/core/binder.d.ts.map +1 -1
- package/dist/src/core/binder.js +16 -3
- package/dist/src/core/binder.js.map +1 -1
- package/dist/src/core/checker.d.ts +11 -9
- package/dist/src/core/checker.d.ts.map +1 -1
- package/dist/src/core/checker.js +1851 -288
- package/dist/src/core/checker.js.map +1 -1
- package/dist/src/core/compiler-code-fixes/model-to-object-literal.codefix.d.ts +6 -0
- package/dist/src/core/compiler-code-fixes/model-to-object-literal.codefix.d.ts.map +1 -0
- package/dist/src/core/compiler-code-fixes/model-to-object-literal.codefix.js +15 -0
- package/dist/src/core/compiler-code-fixes/model-to-object-literal.codefix.js.map +1 -0
- package/dist/src/core/compiler-code-fixes/tuple-to-array-value.codefix.d.ts +6 -0
- package/dist/src/core/compiler-code-fixes/tuple-to-array-value.codefix.d.ts.map +1 -0
- package/dist/src/core/compiler-code-fixes/tuple-to-array-value.codefix.js +15 -0
- package/dist/src/core/compiler-code-fixes/tuple-to-array-value.codefix.js.map +1 -0
- package/dist/src/core/decorator-utils.d.ts +5 -1
- package/dist/src/core/decorator-utils.d.ts.map +1 -1
- package/dist/src/core/decorator-utils.js +11 -1
- package/dist/src/core/decorator-utils.js.map +1 -1
- package/dist/src/core/deprecation.d.ts +1 -1
- package/dist/src/core/deprecation.d.ts.map +1 -1
- package/dist/src/core/diagnostic-creator.d.ts.map +1 -1
- package/dist/src/core/diagnostic-creator.js +1 -2
- package/dist/src/core/diagnostic-creator.js.map +1 -1
- package/dist/src/core/diagnostics.js +3 -3
- package/dist/src/core/diagnostics.js.map +1 -1
- package/dist/src/core/emitter-utils.d.ts +1 -1
- package/dist/src/core/emitter-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/discriminator-utils.d.ts +2 -2
- package/dist/src/core/helpers/discriminator-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/discriminator-utils.js +1 -1
- package/dist/src/core/helpers/discriminator-utils.js.map +1 -1
- package/dist/src/core/helpers/index.d.ts +1 -1
- package/dist/src/core/helpers/index.d.ts.map +1 -1
- package/dist/src/core/helpers/index.js +3 -1
- package/dist/src/core/helpers/index.js.map +1 -1
- package/dist/src/core/helpers/location-context.d.ts +2 -2
- package/dist/src/core/helpers/location-context.d.ts.map +1 -1
- package/dist/src/core/helpers/projected-names-utils.d.ts +2 -2
- package/dist/src/core/helpers/projected-names-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/projected-names-utils.js.map +1 -1
- package/dist/src/core/helpers/string-template-utils.d.ts +6 -6
- package/dist/src/core/helpers/string-template-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/string-template-utils.js +20 -33
- package/dist/src/core/helpers/string-template-utils.js.map +1 -1
- package/dist/src/core/helpers/type-name-utils.d.ts +3 -2
- package/dist/src/core/helpers/type-name-utils.d.ts.map +1 -1
- package/dist/src/core/helpers/type-name-utils.js +57 -8
- package/dist/src/core/helpers/type-name-utils.js.map +1 -1
- package/dist/src/core/index.d.ts +4 -1
- package/dist/src/core/index.d.ts.map +1 -1
- package/dist/src/core/index.js +4 -1
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/core/intrinsic-type-state.d.ts +63 -0
- package/dist/src/core/intrinsic-type-state.d.ts.map +1 -0
- package/dist/src/core/intrinsic-type-state.js +160 -0
- package/dist/src/core/intrinsic-type-state.js.map +1 -0
- package/dist/src/core/js-marshaller.d.ts +13 -0
- package/dist/src/core/js-marshaller.d.ts.map +1 -0
- package/dist/src/core/js-marshaller.js +79 -0
- package/dist/src/core/js-marshaller.js.map +1 -0
- package/dist/src/core/library.d.ts +2 -1
- package/dist/src/core/library.d.ts.map +1 -1
- package/dist/src/core/library.js +3 -0
- package/dist/src/core/library.js.map +1 -1
- package/dist/src/core/linter.d.ts +1 -1
- package/dist/src/core/linter.d.ts.map +1 -1
- package/dist/src/core/linter.js +1 -1
- package/dist/src/core/linter.js.map +1 -1
- package/dist/src/core/messages.d.ts +235 -2
- package/dist/src/core/messages.d.ts.map +1 -1
- package/dist/src/core/messages.js +74 -1
- package/dist/src/core/messages.js.map +1 -1
- package/dist/src/core/numeric-ranges.d.ts +51 -0
- package/dist/src/core/numeric-ranges.d.ts.map +1 -0
- package/dist/src/core/numeric-ranges.js +30 -0
- package/dist/src/core/numeric-ranges.js.map +1 -0
- package/dist/src/core/numeric.js +2 -8
- package/dist/src/core/numeric.js.map +1 -1
- package/dist/src/core/parser.d.ts +2 -1
- package/dist/src/core/parser.d.ts.map +1 -1
- package/dist/src/core/parser.js +288 -6
- package/dist/src/core/parser.js.map +1 -1
- package/dist/src/core/program.d.ts +2 -45
- package/dist/src/core/program.d.ts.map +1 -1
- package/dist/src/core/program.js +3 -127
- package/dist/src/core/program.js.map +1 -1
- package/dist/src/core/projected-program.d.ts +3 -0
- package/dist/src/core/projected-program.d.ts.map +1 -0
- package/dist/src/core/projected-program.js +4 -0
- package/dist/src/core/projected-program.js.map +1 -0
- package/dist/src/core/projection-members.d.ts +2 -2
- package/dist/src/core/projection-members.d.ts.map +1 -1
- package/dist/src/core/projector.d.ts +2 -2
- package/dist/src/core/projector.d.ts.map +1 -1
- package/dist/src/core/projector.js +12 -3
- package/dist/src/core/projector.js.map +1 -1
- package/dist/src/core/scanner.d.ts +42 -37
- package/dist/src/core/scanner.d.ts.map +1 -1
- package/dist/src/core/scanner.js +67 -46
- package/dist/src/core/scanner.js.map +1 -1
- package/dist/src/core/schema-validator.js +1 -1
- package/dist/src/core/schema-validator.js.map +1 -1
- package/dist/src/core/semantic-walker.d.ts +1 -1
- package/dist/src/core/semantic-walker.d.ts.map +1 -1
- package/dist/src/core/semantic-walker.js +12 -0
- package/dist/src/core/semantic-walker.js.map +1 -1
- package/dist/src/core/state-accessors.d.ts +46 -0
- package/dist/src/core/state-accessors.d.ts.map +1 -0
- package/dist/src/core/state-accessors.js +123 -0
- package/dist/src/core/state-accessors.js.map +1 -0
- package/dist/src/core/type-utils.d.ts +18 -7
- package/dist/src/core/type-utils.d.ts.map +1 -1
- package/dist/src/core/type-utils.js +24 -5
- package/dist/src/core/type-utils.js.map +1 -1
- package/dist/src/core/types.d.ts +238 -46
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js +12 -1
- package/dist/src/core/types.js.map +1 -1
- package/dist/src/emitter-framework/asset-emitter.d.ts +1 -1
- package/dist/src/emitter-framework/asset-emitter.d.ts.map +1 -1
- package/dist/src/emitter-framework/asset-emitter.js +4 -1
- package/dist/src/emitter-framework/asset-emitter.js.map +1 -1
- package/dist/src/emitter-framework/ref-scope.d.ts +1 -1
- package/dist/src/emitter-framework/ref-scope.d.ts.map +1 -1
- package/dist/src/emitter-framework/reference-cycle.d.ts +2 -2
- package/dist/src/emitter-framework/reference-cycle.d.ts.map +1 -1
- package/dist/src/emitter-framework/reference-cycle.js +1 -1
- package/dist/src/emitter-framework/reference-cycle.js.map +1 -1
- package/dist/src/emitter-framework/type-emitter.d.ts +3 -2
- package/dist/src/emitter-framework/type-emitter.d.ts.map +1 -1
- package/dist/src/emitter-framework/type-emitter.js +11 -3
- package/dist/src/emitter-framework/type-emitter.js.map +1 -1
- package/dist/src/emitter-framework/types.d.ts +2 -2
- package/dist/src/emitter-framework/types.d.ts.map +1 -1
- package/dist/src/formatter/print/comment-handler.d.ts.map +1 -1
- package/dist/src/formatter/print/comment-handler.js +22 -0
- package/dist/src/formatter/print/comment-handler.js.map +1 -1
- package/dist/src/formatter/print/printer.d.ts +11 -5
- package/dist/src/formatter/print/printer.d.ts.map +1 -1
- package/dist/src/formatter/print/printer.js +95 -4
- package/dist/src/formatter/print/printer.js.map +1 -1
- package/dist/src/init/file-templating.d.ts +2 -2
- package/dist/src/init/file-templating.d.ts.map +1 -1
- package/dist/src/init/init-template.d.ts +1 -1
- package/dist/src/init/init-template.d.ts.map +1 -1
- package/dist/src/lib/decorators.d.ts +3 -55
- package/dist/src/lib/decorators.d.ts.map +1 -1
- package/dist/src/lib/decorators.js +30 -124
- package/dist/src/lib/decorators.js.map +1 -1
- package/dist/src/lib/encoded-names.d.ts +2 -2
- package/dist/src/lib/encoded-names.d.ts.map +1 -1
- package/dist/src/lib/intrinsic-decorators.d.ts +2 -2
- package/dist/src/lib/intrinsic-decorators.d.ts.map +1 -1
- package/dist/src/lib/intrinsic-decorators.js +7 -0
- package/dist/src/lib/intrinsic-decorators.js.map +1 -1
- package/dist/src/lib/service.d.ts +1 -1
- package/dist/src/lib/service.d.ts.map +1 -1
- package/dist/src/server/classify.d.ts.map +1 -1
- package/dist/src/server/classify.js +10 -0
- package/dist/src/server/classify.js.map +1 -1
- package/dist/src/server/completion.d.ts +2 -2
- package/dist/src/server/completion.d.ts.map +1 -1
- package/dist/src/server/completion.js +44 -2
- package/dist/src/server/completion.js.map +1 -1
- package/dist/src/server/serverlib.d.ts.map +1 -1
- package/dist/src/server/serverlib.js +10 -10
- package/dist/src/server/serverlib.js.map +1 -1
- package/dist/src/server/tmlanguage.d.ts +1 -1
- package/dist/src/server/tmlanguage.d.ts.map +1 -1
- package/dist/src/server/tmlanguage.js +147 -20
- package/dist/src/server/tmlanguage.js.map +1 -1
- package/dist/src/server/type-details.js +14 -7
- package/dist/src/server/type-details.js.map +1 -1
- package/dist/src/server/type-signature.js +15 -6
- package/dist/src/server/type-signature.js.map +1 -1
- package/dist/src/server/types.d.ts +1 -1
- package/dist/src/server/types.d.ts.map +1 -1
- package/dist/src/testing/expect.js +1 -1
- package/dist/src/testing/expect.js.map +1 -1
- package/dist/src/testing/rule-tester.d.ts.map +1 -1
- package/dist/src/testing/rule-tester.js +1 -2
- package/dist/src/testing/rule-tester.js.map +1 -1
- package/dist/src/testing/test-host.d.ts +1 -2
- package/dist/src/testing/test-host.d.ts.map +1 -1
- package/dist/src/testing/test-host.js +1 -8
- package/dist/src/testing/test-host.js.map +1 -1
- package/dist/src/testing/test-server-host.d.ts.map +1 -1
- package/dist/src/testing/test-server-host.js +2 -1
- package/dist/src/testing/test-server-host.js.map +1 -1
- package/dist/src/testing/test-utils.d.ts +1 -0
- package/dist/src/testing/test-utils.d.ts.map +1 -1
- package/dist/src/testing/test-utils.js +7 -0
- package/dist/src/testing/test-utils.js.map +1 -1
- package/dist/typespec.tmLanguage +408 -17
- package/lib/intrinsics.tsp +55 -5
- package/package.json +9 -9
package/dist/src/core/checker.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { $docFromComment,
|
|
2
|
-
import { getIndexer } from "../lib/intrinsic-decorators.js";
|
|
1
|
+
import { $docFromComment, getIndexer } from "../lib/intrinsic-decorators.js";
|
|
3
2
|
import { MultiKeyMap, createRekeyableMap, isArray, mutate } from "../utils/misc.js";
|
|
4
3
|
import { createSymbol, createSymbolTable } from "./binder.js";
|
|
5
4
|
import { createChangeIdentifierCodeFix } from "./compiler-code-fixes/change-identifier.codefix.js";
|
|
5
|
+
import { createModelToObjectValueCodeFix } from "./compiler-code-fixes/model-to-object-literal.codefix.js";
|
|
6
|
+
import { createTupleToArrayValueCodeFix } from "./compiler-code-fixes/tuple-to-array-value.codefix.js";
|
|
6
7
|
import { getDeprecationDetails, markDeprecated } from "./deprecation.js";
|
|
7
|
-
import { ProjectionError, compilerAssert, reportDeprecated } from "./diagnostics.js";
|
|
8
|
+
import { ProjectionError, compilerAssert, ignoreDiagnostics, reportDeprecated, } from "./diagnostics.js";
|
|
8
9
|
import { validateInheritanceDiscriminatedUnions } from "./helpers/discriminator-utils.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { getLocationContext } from "./helpers/location-context.js";
|
|
11
|
+
import { explainStringTemplateNotSerializable } from "./helpers/string-template-utils.js";
|
|
12
|
+
import { getEntityName, getNamespaceFullName, getTypeName, } from "./helpers/type-name-utils.js";
|
|
13
|
+
import { getMaxItems, getMaxLength, getMaxValueAsNumeric, getMaxValueExclusiveAsNumeric, getMinItems, getMinLength, getMinValueAsNumeric, getMinValueExclusiveAsNumeric, } from "./intrinsic-type-state.js";
|
|
14
|
+
import { canNumericConstraintBeJsNumber, legacyMarshallTypeForJS, marshallTypeForJS, } from "./js-marshaller.js";
|
|
11
15
|
import { createDiagnostic } from "./messages.js";
|
|
12
|
-
import {
|
|
16
|
+
import { numericRanges } from "./numeric-ranges.js";
|
|
17
|
+
import { Numeric } from "./numeric.js";
|
|
18
|
+
import { exprIsBareIdentifier, getFirstAncestor, getIdentifierContext, hasParseError, visitChildren, } from "./parser.js";
|
|
13
19
|
import { createProjectionMembers } from "./projection-members.js";
|
|
14
|
-
import { getFullyQualifiedSymbolName, getParentTemplateNode, isNeverType, isTemplateInstance, isUnknownType, isVoidType, } from "./type-utils.js";
|
|
20
|
+
import { getFullyQualifiedSymbolName, getParentTemplateNode, isArrayModelType, isErrorType, isNeverType, isNullType, isTemplateInstance, isType, isUnknownType, isValue, isVoidType, } from "./type-utils.js";
|
|
15
21
|
import { IdentifierKind, SyntaxKind, } from "./types.js";
|
|
16
22
|
/**
|
|
17
23
|
* Maps type arguments to type instantiation.
|
|
@@ -105,6 +111,7 @@ export function createChecker(program) {
|
|
|
105
111
|
project,
|
|
106
112
|
neverType,
|
|
107
113
|
errorType,
|
|
114
|
+
nullType,
|
|
108
115
|
anyType: unknownType,
|
|
109
116
|
voidType,
|
|
110
117
|
typePrototype,
|
|
@@ -117,6 +124,8 @@ export function createChecker(program) {
|
|
|
117
124
|
isStdType,
|
|
118
125
|
getStdType,
|
|
119
126
|
resolveTypeReference,
|
|
127
|
+
getValueForNode,
|
|
128
|
+
getTypeOrValueForNode,
|
|
120
129
|
};
|
|
121
130
|
const projectionMembers = createProjectionMembers(checker);
|
|
122
131
|
return checker;
|
|
@@ -207,13 +216,13 @@ export function createChecker(program) {
|
|
|
207
216
|
if (ref.flags & 4096 /* SymbolFlags.Namespace */) {
|
|
208
217
|
const links = getSymbolLinks(getMergedSymbol(ref));
|
|
209
218
|
const type = links.type;
|
|
210
|
-
const decApp =
|
|
219
|
+
const decApp = checkDecoratorApplication(type, decNode, undefined);
|
|
211
220
|
if (decApp) {
|
|
212
221
|
type.decorators.push(decApp);
|
|
213
222
|
applyDecoratorToType(program, decApp, type);
|
|
214
223
|
}
|
|
215
224
|
}
|
|
216
|
-
else if (args.length > 0 || ref.flags &
|
|
225
|
+
else if (args.length > 0 || ref.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
217
226
|
reportCheckerDiagnostic(createDiagnostic({
|
|
218
227
|
code: "augment-decorator-target",
|
|
219
228
|
messageId: "noInstance",
|
|
@@ -313,9 +322,265 @@ export function createChecker(program) {
|
|
|
313
322
|
return checkOperation(node, mapper, containerType);
|
|
314
323
|
case SyntaxKind.UnionVariant:
|
|
315
324
|
return checkUnionVariant(node, mapper);
|
|
325
|
+
case SyntaxKind.ScalarConstructor:
|
|
326
|
+
return checkScalarConstructor(node, mapper, containerType);
|
|
316
327
|
}
|
|
317
328
|
}
|
|
329
|
+
function getTypeForTypeOrIndeterminate(entity) {
|
|
330
|
+
if (entity.entityKind === "Indeterminate") {
|
|
331
|
+
return entity.type;
|
|
332
|
+
}
|
|
333
|
+
return entity;
|
|
334
|
+
}
|
|
318
335
|
function getTypeForNode(node, mapper) {
|
|
336
|
+
const entity = checkNode(node, mapper);
|
|
337
|
+
if (entity === null) {
|
|
338
|
+
return errorType;
|
|
339
|
+
}
|
|
340
|
+
if (entity.entityKind === "Indeterminate") {
|
|
341
|
+
return entity.type;
|
|
342
|
+
}
|
|
343
|
+
if (isValue(entity)) {
|
|
344
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
345
|
+
code: "value-in-type",
|
|
346
|
+
target: node,
|
|
347
|
+
}));
|
|
348
|
+
return errorType;
|
|
349
|
+
}
|
|
350
|
+
if (entity.kind === "TemplateParameter") {
|
|
351
|
+
if (entity.constraint?.valueType) {
|
|
352
|
+
// means this template constraint will accept values
|
|
353
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
354
|
+
code: "value-in-type",
|
|
355
|
+
messageId: "referenceTemplate",
|
|
356
|
+
target: node,
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return entity;
|
|
361
|
+
}
|
|
362
|
+
function getValueForNode(node, mapper, constraint, options = {}) {
|
|
363
|
+
const initial = checkNode(node, mapper, constraint);
|
|
364
|
+
if (initial === null) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
let entity;
|
|
368
|
+
if (initial.entityKind === "Indeterminate") {
|
|
369
|
+
entity = getValueFromIndeterminate(initial.type, constraint, node);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
entity = initial;
|
|
373
|
+
}
|
|
374
|
+
if (options.legacyTupleAndModelCast && entity !== null && isType(entity)) {
|
|
375
|
+
entity = legacy_tryTypeToValueCast(entity, constraint, node);
|
|
376
|
+
}
|
|
377
|
+
if (entity === null) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
if (isValue(entity)) {
|
|
381
|
+
return constraint ? inferScalarsFromConstraints(entity, constraint.type) : entity;
|
|
382
|
+
}
|
|
383
|
+
reportExpectedValue(node, entity);
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
function reportExpectedValue(target, type) {
|
|
387
|
+
if (type.kind === "Model" && type.name === "" && target.kind === SyntaxKind.ModelExpression) {
|
|
388
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
389
|
+
code: "expect-value",
|
|
390
|
+
messageId: "model",
|
|
391
|
+
format: { name: getTypeName(type) },
|
|
392
|
+
codefixes: [createModelToObjectValueCodeFix(target)],
|
|
393
|
+
target,
|
|
394
|
+
}));
|
|
395
|
+
}
|
|
396
|
+
else if (type.kind === "Tuple" && target.kind === SyntaxKind.TupleExpression) {
|
|
397
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
398
|
+
code: "expect-value",
|
|
399
|
+
messageId: "tuple",
|
|
400
|
+
format: { name: getTypeName(type) },
|
|
401
|
+
codefixes: [createTupleToArrayValueCodeFix(target)],
|
|
402
|
+
target,
|
|
403
|
+
}));
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
407
|
+
code: "expect-value",
|
|
408
|
+
format: { name: getTypeName(type) },
|
|
409
|
+
target,
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/** In certain context for types that can also be value if the constraint allows it we try to use it as a value instead of a type. */
|
|
414
|
+
function getValueFromIndeterminate(type, constraint, node) {
|
|
415
|
+
switch (type.kind) {
|
|
416
|
+
case "String":
|
|
417
|
+
case "StringTemplate":
|
|
418
|
+
return checkStringValue(type, constraint, node);
|
|
419
|
+
case "Number":
|
|
420
|
+
return checkNumericValue(type, constraint, node);
|
|
421
|
+
case "Boolean":
|
|
422
|
+
return checkBooleanValue(type, constraint, node);
|
|
423
|
+
case "EnumMember":
|
|
424
|
+
return checkEnumValue(type, constraint, node);
|
|
425
|
+
case "UnionVariant":
|
|
426
|
+
return getValueFromIndeterminate(type.type, constraint, node);
|
|
427
|
+
case "Intrinsic":
|
|
428
|
+
switch (type.name) {
|
|
429
|
+
case "null":
|
|
430
|
+
return checkNullValue(type, constraint, node);
|
|
431
|
+
}
|
|
432
|
+
return type;
|
|
433
|
+
default:
|
|
434
|
+
return type;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function legacy_tryTypeToValueCast(type, constraint, node) {
|
|
438
|
+
switch (type.kind) {
|
|
439
|
+
case "Tuple":
|
|
440
|
+
return legacy_tryUsingTupleAsArrayValue(type, constraint?.type, node);
|
|
441
|
+
case "Model":
|
|
442
|
+
return legacy_tryUsingModelAsObjectValue(type, constraint?.type, node);
|
|
443
|
+
default:
|
|
444
|
+
return type;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Legacy behavior to smooth transition to object values.
|
|
448
|
+
function legacy_tryUsingModelAsObjectValue(model, type, node) {
|
|
449
|
+
if (model.node?.kind !== SyntaxKind.ModelExpression) {
|
|
450
|
+
return model; // we only want to convert model expressions
|
|
451
|
+
}
|
|
452
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
453
|
+
code: "deprecated",
|
|
454
|
+
codefixes: [createModelToObjectValueCodeFix(model.node)],
|
|
455
|
+
format: {
|
|
456
|
+
message: "Using a model as a value is deprecated. Use an object value instead(with #{}).",
|
|
457
|
+
},
|
|
458
|
+
target: model.node,
|
|
459
|
+
}));
|
|
460
|
+
const value = {
|
|
461
|
+
entityKind: "Value",
|
|
462
|
+
valueKind: "ObjectValue",
|
|
463
|
+
type: type ?? model,
|
|
464
|
+
node: model.node,
|
|
465
|
+
properties: new Map(),
|
|
466
|
+
};
|
|
467
|
+
for (const prop of model.properties.values()) {
|
|
468
|
+
let propValue = getValueFromIndeterminate(prop.type, { kind: "assignment", type: prop.type }, node);
|
|
469
|
+
if (propValue !== null && isType(propValue)) {
|
|
470
|
+
propValue = legacy_tryTypeToValueCast(propValue, { kind: "assignment", type: prop.type }, node);
|
|
471
|
+
}
|
|
472
|
+
if (propValue == null) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
else if (!isValue(propValue)) {
|
|
476
|
+
return model;
|
|
477
|
+
}
|
|
478
|
+
value.properties.set(prop.name, {
|
|
479
|
+
name: prop.name,
|
|
480
|
+
value: propValue,
|
|
481
|
+
node: prop.node,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
if (type !== undefined && !checkTypeAssignable(model, type, node)) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
return value;
|
|
488
|
+
}
|
|
489
|
+
// Legacy behavior to smooth transition to array values.
|
|
490
|
+
function legacy_tryUsingTupleAsArrayValue(tuple, type, node) {
|
|
491
|
+
if (tuple.node.kind !== SyntaxKind.TupleExpression) {
|
|
492
|
+
return tuple; // we won't convert dynamic tuples to array values
|
|
493
|
+
}
|
|
494
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
495
|
+
code: "deprecated",
|
|
496
|
+
codefixes: [createTupleToArrayValueCodeFix(tuple.node)],
|
|
497
|
+
format: {
|
|
498
|
+
message: "Using a tuple as a value is deprecated. Use an array value instead(with #[]).",
|
|
499
|
+
},
|
|
500
|
+
target: tuple.node,
|
|
501
|
+
}));
|
|
502
|
+
const values = [];
|
|
503
|
+
for (const [index, item] of tuple.values.entries()) {
|
|
504
|
+
const itemType = type?.kind === "Model" && isArrayModelType(program, type)
|
|
505
|
+
? type.indexer.value
|
|
506
|
+
: type?.kind === "Tuple"
|
|
507
|
+
? type.values[index]
|
|
508
|
+
: undefined;
|
|
509
|
+
let value = getValueFromIndeterminate(item, itemType && { kind: "assignment", type: itemType }, node);
|
|
510
|
+
if (value !== null && isType(value)) {
|
|
511
|
+
value = legacy_tryTypeToValueCast(value, itemType && { kind: "assignment", type: itemType }, node);
|
|
512
|
+
}
|
|
513
|
+
if (value === null) {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
else if (!isValue(value)) {
|
|
517
|
+
return tuple;
|
|
518
|
+
}
|
|
519
|
+
values.push(value);
|
|
520
|
+
}
|
|
521
|
+
if (type !== undefined && !checkTypeAssignable(tuple, type, node)) {
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
return {
|
|
525
|
+
entityKind: "Value",
|
|
526
|
+
valueKind: "ArrayValue",
|
|
527
|
+
type: type ?? tuple,
|
|
528
|
+
node: tuple.node,
|
|
529
|
+
values,
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Gets a type or value depending on the node and current constraint.
|
|
534
|
+
* For nodes that can be both type or values(e.g. string), the value will be returned if the constraint expect a value of that type even if the constrain also allows the type.
|
|
535
|
+
* This means that if the constraint is `string | valueof string` passing `"abc"` will send the value `"abc"` and not the type `"abc"`.
|
|
536
|
+
*/
|
|
537
|
+
function getTypeOrValueForNode(node, mapper, constraint) {
|
|
538
|
+
const valueConstraint = extractValueOfConstraints(constraint);
|
|
539
|
+
const entity = checkNode(node, mapper, valueConstraint);
|
|
540
|
+
if (entity === null) {
|
|
541
|
+
return entity;
|
|
542
|
+
}
|
|
543
|
+
else if (isType(entity)) {
|
|
544
|
+
if (valueConstraint) {
|
|
545
|
+
return legacy_tryTypeToValueCast(entity, valueConstraint, node);
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
return entity;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
else if (isValue(entity)) {
|
|
552
|
+
return entity;
|
|
553
|
+
}
|
|
554
|
+
compilerAssert(entity.entityKind === "Indeterminate", "Expected indeterminate entity");
|
|
555
|
+
if (valueConstraint) {
|
|
556
|
+
const valueDiagnostics = [];
|
|
557
|
+
const oldDiagnosticHook = onCheckerDiagnostic;
|
|
558
|
+
onCheckerDiagnostic = (x) => valueDiagnostics.push(x);
|
|
559
|
+
const result = getValueFromIndeterminate(entity.type, valueConstraint, node);
|
|
560
|
+
onCheckerDiagnostic = oldDiagnosticHook;
|
|
561
|
+
if (result) {
|
|
562
|
+
// If there were diagnostic reported but we still got a value this means that the value might be invalid.
|
|
563
|
+
reportCheckerDiagnostics(valueDiagnostics);
|
|
564
|
+
return result;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return entity.type;
|
|
568
|
+
}
|
|
569
|
+
/** Extact the type constraint a value should match. */
|
|
570
|
+
function extractValueOfConstraints(constraint) {
|
|
571
|
+
if (constraint?.constraint.valueType) {
|
|
572
|
+
return { kind: constraint.kind, type: constraint.constraint.valueType };
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Gets a type, value or indeterminate depending on the node and current constraint.
|
|
580
|
+
* For nodes that can be both type or values(e.g. string literals), an indeterminate entity will be returned.
|
|
581
|
+
* It is the job of of the consumer to decide if it should be a type or a value depending on the context.
|
|
582
|
+
*/
|
|
583
|
+
function checkNode(node, mapper, valueConstraint) {
|
|
319
584
|
switch (node.kind) {
|
|
320
585
|
case SyntaxKind.ModelExpression:
|
|
321
586
|
return checkModel(node, mapper);
|
|
@@ -346,10 +611,10 @@ export function createChecker(program) {
|
|
|
346
611
|
return checkNumericLiteral(node);
|
|
347
612
|
case SyntaxKind.BooleanLiteral:
|
|
348
613
|
return checkBooleanLiteral(node);
|
|
349
|
-
case SyntaxKind.TupleExpression:
|
|
350
|
-
return checkTupleExpression(node, mapper);
|
|
351
614
|
case SyntaxKind.StringLiteral:
|
|
352
615
|
return checkStringLiteral(node);
|
|
616
|
+
case SyntaxKind.TupleExpression:
|
|
617
|
+
return checkTupleExpression(node, mapper);
|
|
353
618
|
case SyntaxKind.StringTemplateExpression:
|
|
354
619
|
return checkStringTemplateExpresion(node, mapper);
|
|
355
620
|
case SyntaxKind.ArrayExpression:
|
|
@@ -363,7 +628,7 @@ export function createChecker(program) {
|
|
|
363
628
|
case SyntaxKind.FunctionDeclarationStatement:
|
|
364
629
|
return checkFunctionDeclaration(node, mapper);
|
|
365
630
|
case SyntaxKind.TypeReference:
|
|
366
|
-
return
|
|
631
|
+
return checkTypeOrValueReference(node, mapper);
|
|
367
632
|
case SyntaxKind.TemplateArgument:
|
|
368
633
|
return checkTemplateArgument(node, mapper);
|
|
369
634
|
case SyntaxKind.TemplateParameterDeclaration:
|
|
@@ -376,12 +641,19 @@ export function createChecker(program) {
|
|
|
376
641
|
return neverType;
|
|
377
642
|
case SyntaxKind.UnknownKeyword:
|
|
378
643
|
return unknownType;
|
|
644
|
+
case SyntaxKind.ObjectLiteral:
|
|
645
|
+
return checkObjectValue(node, mapper, valueConstraint);
|
|
646
|
+
case SyntaxKind.ArrayLiteral:
|
|
647
|
+
return checkArrayValue(node, mapper, valueConstraint);
|
|
648
|
+
case SyntaxKind.ConstStatement:
|
|
649
|
+
return checkConst(node);
|
|
650
|
+
case SyntaxKind.CallExpression:
|
|
651
|
+
return checkCallExpression(node, mapper);
|
|
652
|
+
case SyntaxKind.TypeOfExpression:
|
|
653
|
+
return checkTypeOfExpression(node, mapper);
|
|
654
|
+
default:
|
|
655
|
+
return errorType;
|
|
379
656
|
}
|
|
380
|
-
// we don't emit an error here as we blindly call this function
|
|
381
|
-
// with any node type, but some nodes don't produce a type
|
|
382
|
-
// (e.g. imports). errorType should result in an error if it
|
|
383
|
-
// bubbles out somewhere its not supposed to be.
|
|
384
|
-
return errorType;
|
|
385
657
|
}
|
|
386
658
|
/**
|
|
387
659
|
* Return a fully qualified id of node
|
|
@@ -440,7 +712,7 @@ export function createChecker(program) {
|
|
|
440
712
|
});
|
|
441
713
|
if (node.constraint) {
|
|
442
714
|
pendingResolutions.start(getNodeSymId(node), ResolutionKind.Constraint);
|
|
443
|
-
type.constraint =
|
|
715
|
+
type.constraint = getParamConstraintEntityForNode(node.constraint);
|
|
444
716
|
pendingResolutions.finish(getNodeSymId(node), ResolutionKind.Constraint);
|
|
445
717
|
}
|
|
446
718
|
if (node.default) {
|
|
@@ -453,23 +725,24 @@ export function createChecker(program) {
|
|
|
453
725
|
if (declaredType.default === undefined) {
|
|
454
726
|
return undefined;
|
|
455
727
|
}
|
|
456
|
-
if (isErrorType(declaredType.default))
|
|
728
|
+
if ((isType(declaredType.default) && isErrorType(declaredType.default)) ||
|
|
729
|
+
declaredType.default === null) {
|
|
457
730
|
return declaredType.default;
|
|
458
731
|
}
|
|
459
|
-
return
|
|
732
|
+
return checkNode(node.default, mapper);
|
|
460
733
|
}
|
|
461
734
|
function checkTemplateParameterDefault(nodeDefault, templateParameters, index, constraint) {
|
|
462
735
|
function visit(node) {
|
|
463
|
-
const
|
|
736
|
+
const entity = checkNode(node);
|
|
464
737
|
let hasError = false;
|
|
465
|
-
if (
|
|
738
|
+
if (entity !== null && "kind" in entity && entity.kind === "TemplateParameter") {
|
|
466
739
|
for (let i = index; i < templateParameters.length; i++) {
|
|
467
|
-
if (
|
|
740
|
+
if (entity.node.symbol === templateParameters[i].symbol) {
|
|
468
741
|
reportCheckerDiagnostic(createDiagnostic({ code: "invalid-template-default", target: node }));
|
|
469
742
|
return undefined;
|
|
470
743
|
}
|
|
471
744
|
}
|
|
472
|
-
return
|
|
745
|
+
return entity;
|
|
473
746
|
}
|
|
474
747
|
visitChildren(node, (x) => {
|
|
475
748
|
const visited = visit(x);
|
|
@@ -477,10 +750,10 @@ export function createChecker(program) {
|
|
|
477
750
|
hasError = true;
|
|
478
751
|
}
|
|
479
752
|
});
|
|
480
|
-
return hasError ? undefined :
|
|
753
|
+
return hasError ? undefined : entity;
|
|
481
754
|
}
|
|
482
755
|
const type = visit(nodeDefault) ?? errorType;
|
|
483
|
-
if (!isErrorType(type) && constraint) {
|
|
756
|
+
if (!("kind" in type && isErrorType(type)) && constraint) {
|
|
484
757
|
checkTypeAssignable(type, constraint, nodeDefault);
|
|
485
758
|
}
|
|
486
759
|
return type;
|
|
@@ -500,8 +773,22 @@ export function createChecker(program) {
|
|
|
500
773
|
const type = checkTypeReferenceSymbol(sym, node, mapper, instantiateTemplate);
|
|
501
774
|
return type;
|
|
502
775
|
}
|
|
776
|
+
/**
|
|
777
|
+
* Check and resolve a type for the given type reference node.
|
|
778
|
+
* @param node Node.
|
|
779
|
+
* @param mapper Type mapper for template instantiation context.
|
|
780
|
+
* @param instantiateTemplate If templated type should be instantiated if they haven't yet.
|
|
781
|
+
* @returns Resolved type.
|
|
782
|
+
*/
|
|
783
|
+
function checkTypeOrValueReference(node, mapper, instantiateTemplate = true) {
|
|
784
|
+
const sym = resolveTypeReferenceSym(node, mapper);
|
|
785
|
+
if (!sym) {
|
|
786
|
+
return errorType;
|
|
787
|
+
}
|
|
788
|
+
return checkTypeOrValueReferenceSymbol(sym, node, mapper, instantiateTemplate) ?? errorType;
|
|
789
|
+
}
|
|
503
790
|
function checkTemplateArgument(node, mapper) {
|
|
504
|
-
return
|
|
791
|
+
return checkNode(node.argument, mapper);
|
|
505
792
|
}
|
|
506
793
|
function resolveTypeReference(node) {
|
|
507
794
|
const oldDiagnosticHook = onCheckerDiagnostic;
|
|
@@ -567,8 +854,8 @@ export function createChecker(program) {
|
|
|
567
854
|
function checkTemplateInstantiationArgs(node, args, decls, mapper) {
|
|
568
855
|
const params = new Map();
|
|
569
856
|
const positional = [];
|
|
570
|
-
const initMap = new Map(decls.map(
|
|
571
|
-
const declaredType =
|
|
857
|
+
const initMap = new Map(decls.map((decl) => {
|
|
858
|
+
const declaredType = checkTemplateParameterDeclaration(decl, undefined);
|
|
572
859
|
positional.push(declaredType);
|
|
573
860
|
params.set(decl.id.sv, declaredType);
|
|
574
861
|
return [
|
|
@@ -582,7 +869,7 @@ export function createChecker(program) {
|
|
|
582
869
|
let named = false;
|
|
583
870
|
for (const [arg, idx] of args.map((v, i) => [v, i])) {
|
|
584
871
|
function deferredCheck() {
|
|
585
|
-
return [arg,
|
|
872
|
+
return [arg, checkNode(arg.argument, mapper)];
|
|
586
873
|
}
|
|
587
874
|
if (arg.name) {
|
|
588
875
|
named = true;
|
|
@@ -657,18 +944,30 @@ export function createChecker(program) {
|
|
|
657
944
|
target: node,
|
|
658
945
|
}));
|
|
659
946
|
// TODO-TIM check if we expose this below
|
|
660
|
-
commit(param, param.constraint?.
|
|
947
|
+
commit(param, param.constraint?.type ?? unknownType);
|
|
661
948
|
}
|
|
662
949
|
continue;
|
|
663
950
|
}
|
|
664
951
|
const [argNode, type] = init();
|
|
952
|
+
if (type === null) {
|
|
953
|
+
commit(param, unknownType);
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
665
956
|
if (param.constraint) {
|
|
666
|
-
const constraint = param.constraint.kind === "TemplateParameter"
|
|
667
|
-
? finalMap.get(param.constraint)
|
|
957
|
+
const constraint = param.constraint.type?.kind === "TemplateParameter"
|
|
958
|
+
? finalMap.get(param.constraint.type)
|
|
668
959
|
: param.constraint;
|
|
669
|
-
if (
|
|
670
|
-
|
|
671
|
-
|
|
960
|
+
if (isType(type) && param.constraint?.valueType) {
|
|
961
|
+
const converted = legacy_tryTypeToValueCast(type, { kind: "argument", type: param.constraint.valueType }, argNode);
|
|
962
|
+
// If we manage to convert it means this might be convertable so we skip type checking.
|
|
963
|
+
// However we still return the original entity
|
|
964
|
+
if (converted !== type) {
|
|
965
|
+
commit(param, type);
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
if (param.constraint && !checkArgumentAssignable(type, constraint, argNode)) {
|
|
970
|
+
const effectiveType = param.constraint.type ?? unknownType;
|
|
672
971
|
commit(param, effectiveType);
|
|
673
972
|
continue;
|
|
674
973
|
}
|
|
@@ -679,6 +978,15 @@ export function createChecker(program) {
|
|
|
679
978
|
commit(param, unknownType);
|
|
680
979
|
continue;
|
|
681
980
|
}
|
|
981
|
+
else if (isValue(type)) {
|
|
982
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
983
|
+
code: "value-in-type",
|
|
984
|
+
messageId: "noTemplateConstraint",
|
|
985
|
+
target: argNode,
|
|
986
|
+
}));
|
|
987
|
+
commit(param, unknownType);
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
682
990
|
commit(param, type);
|
|
683
991
|
}
|
|
684
992
|
return finalMap;
|
|
@@ -692,6 +1000,20 @@ export function createChecker(program) {
|
|
|
692
1000
|
* @returns resolved type.
|
|
693
1001
|
*/
|
|
694
1002
|
function checkTypeReferenceSymbol(sym, node, mapper, instantiateTemplates = true) {
|
|
1003
|
+
const result = checkTypeOrValueReferenceSymbol(sym, node, mapper, instantiateTemplates);
|
|
1004
|
+
if (result === null || isValue(result)) {
|
|
1005
|
+
reportCheckerDiagnostic(createDiagnostic({ code: "value-in-type", target: node }));
|
|
1006
|
+
return errorType;
|
|
1007
|
+
}
|
|
1008
|
+
if (result.entityKind === "Indeterminate") {
|
|
1009
|
+
return result.type;
|
|
1010
|
+
}
|
|
1011
|
+
return result;
|
|
1012
|
+
}
|
|
1013
|
+
function checkTypeOrValueReferenceSymbol(sym, node, mapper, instantiateTemplates = true) {
|
|
1014
|
+
if (sym.flags & 16777216 /* SymbolFlags.Const */) {
|
|
1015
|
+
return getValueForNode(sym.declarations[0], mapper);
|
|
1016
|
+
}
|
|
695
1017
|
if (sym.flags & 16384 /* SymbolFlags.Decorator */) {
|
|
696
1018
|
reportCheckerDiagnostic(createDiagnostic({ code: "invalid-type-ref", messageId: "decorator", target: sym }));
|
|
697
1019
|
return errorType;
|
|
@@ -719,18 +1041,18 @@ export function createChecker(program) {
|
|
|
719
1041
|
target: node,
|
|
720
1042
|
}));
|
|
721
1043
|
}
|
|
722
|
-
if (sym.flags &
|
|
1044
|
+
if (sym.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
723
1045
|
compilerAssert(sym.type, "Expected late bound symbol to have type");
|
|
724
1046
|
return sym.type;
|
|
725
1047
|
}
|
|
726
1048
|
else if (symbolLinks.declaredType) {
|
|
727
1049
|
baseType = symbolLinks.declaredType;
|
|
728
1050
|
}
|
|
729
|
-
else if (sym.flags &
|
|
1051
|
+
else if (sym.flags & 33555780 /* SymbolFlags.Member */) {
|
|
730
1052
|
baseType = checkMemberSym(sym, mapper);
|
|
731
1053
|
}
|
|
732
1054
|
else {
|
|
733
|
-
baseType =
|
|
1055
|
+
baseType = checkDeclaredTypeOrIndeterminate(sym, decl, mapper);
|
|
734
1056
|
}
|
|
735
1057
|
}
|
|
736
1058
|
else {
|
|
@@ -749,12 +1071,13 @@ export function createChecker(program) {
|
|
|
749
1071
|
target: node,
|
|
750
1072
|
}));
|
|
751
1073
|
}
|
|
752
|
-
if (sym.flags &
|
|
753
|
-
compilerAssert(sym.type,
|
|
1074
|
+
if (sym.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
1075
|
+
compilerAssert(sym.type, `Expected late bound symbol to have type`);
|
|
754
1076
|
return sym.type;
|
|
755
1077
|
}
|
|
756
1078
|
else if (sym.flags & 32768 /* SymbolFlags.TemplateParameter */) {
|
|
757
|
-
|
|
1079
|
+
const mapped = checkTemplateParameterDeclaration(sym.declarations[0], mapper);
|
|
1080
|
+
baseType = mapped;
|
|
758
1081
|
}
|
|
759
1082
|
else if (symbolLinks.type) {
|
|
760
1083
|
// Have a cached type for non-declarations
|
|
@@ -764,7 +1087,7 @@ export function createChecker(program) {
|
|
|
764
1087
|
baseType = symbolLinks.declaredType;
|
|
765
1088
|
}
|
|
766
1089
|
else {
|
|
767
|
-
if (sym.flags &
|
|
1090
|
+
if (sym.flags & 33555780 /* SymbolFlags.Member */) {
|
|
768
1091
|
baseType = checkMemberSym(sym, mapper);
|
|
769
1092
|
}
|
|
770
1093
|
else {
|
|
@@ -778,11 +1101,16 @@ export function createChecker(program) {
|
|
|
778
1101
|
// don't raise deprecation when the usage site is also a deprecated
|
|
779
1102
|
// declaration.
|
|
780
1103
|
const declarationNode = sym?.declarations[0];
|
|
781
|
-
if (declarationNode && mapper === undefined) {
|
|
1104
|
+
if (declarationNode && mapper === undefined && isType(baseType)) {
|
|
782
1105
|
if (!isTypeReferenceContextDeprecated(node.parent)) {
|
|
783
1106
|
checkDeprecated(baseType, declarationNode, node);
|
|
784
1107
|
}
|
|
785
1108
|
}
|
|
1109
|
+
// Elements that could be used as type or values depending on the context
|
|
1110
|
+
if ((isType(baseType) && (baseType.kind === "EnumMember" || baseType.kind === "UnionVariant")) ||
|
|
1111
|
+
isNullType(baseType)) {
|
|
1112
|
+
return createIndeterminateEntity(baseType);
|
|
1113
|
+
}
|
|
786
1114
|
return baseType;
|
|
787
1115
|
}
|
|
788
1116
|
/**
|
|
@@ -797,11 +1125,11 @@ export function createChecker(program) {
|
|
|
797
1125
|
if (symbolLinks.declaredType) {
|
|
798
1126
|
return symbolLinks.declaredType;
|
|
799
1127
|
}
|
|
800
|
-
if (sym.flags &
|
|
1128
|
+
if (sym.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
801
1129
|
compilerAssert(sym.type, "Expected late bound symbol to have type");
|
|
802
1130
|
return sym.type;
|
|
803
1131
|
}
|
|
804
|
-
if (sym.flags &
|
|
1132
|
+
if (sym.flags & 33555780 /* SymbolFlags.Member */) {
|
|
805
1133
|
return checkMemberSym(sym, mapper);
|
|
806
1134
|
}
|
|
807
1135
|
else {
|
|
@@ -815,8 +1143,8 @@ export function createChecker(program) {
|
|
|
815
1143
|
* @param mapper Type mapper for template resolution
|
|
816
1144
|
* @returns The declared type for the given node.
|
|
817
1145
|
*/
|
|
818
|
-
function
|
|
819
|
-
|
|
1146
|
+
function checkDeclaredTypeOrIndeterminate(sym, node, mapper) {
|
|
1147
|
+
const type = sym.flags & 2 /* SymbolFlags.Model */
|
|
820
1148
|
? checkModelStatement(node, mapper)
|
|
821
1149
|
: sym.flags & 8 /* SymbolFlags.Scalar */
|
|
822
1150
|
? checkScalar(node, mapper)
|
|
@@ -827,6 +1155,10 @@ export function createChecker(program) {
|
|
|
827
1155
|
: sym.flags & 16 /* SymbolFlags.Operation */
|
|
828
1156
|
? checkOperation(node, mapper)
|
|
829
1157
|
: checkUnion(node, mapper);
|
|
1158
|
+
return type;
|
|
1159
|
+
}
|
|
1160
|
+
function checkDeclaredType(sym, node, mapper) {
|
|
1161
|
+
return getTypeForTypeOrIndeterminate(checkDeclaredTypeOrIndeterminate(sym, node, mapper));
|
|
830
1162
|
}
|
|
831
1163
|
function getOrInstantiateTemplate(templateNode, params, args, parentMapper, instantiateTempalates = true) {
|
|
832
1164
|
const symbolLinks = templateNode.kind === SyntaxKind.OperationStatement &&
|
|
@@ -874,6 +1206,57 @@ export function createChecker(program) {
|
|
|
874
1206
|
}
|
|
875
1207
|
return type;
|
|
876
1208
|
}
|
|
1209
|
+
/** Check a union expresion used in a parameter constraint, those allow the use of `valueof` as a variant. */
|
|
1210
|
+
function checkMixedParameterConstraintUnion(node, mapper) {
|
|
1211
|
+
const values = [];
|
|
1212
|
+
const types = [];
|
|
1213
|
+
for (const option of node.options) {
|
|
1214
|
+
const [kind, type] = getTypeOrValueOfTypeForNode(option, mapper);
|
|
1215
|
+
if (kind === "value") {
|
|
1216
|
+
values.push(type);
|
|
1217
|
+
}
|
|
1218
|
+
else {
|
|
1219
|
+
types.push(type);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
return {
|
|
1223
|
+
entityKind: "MixedParameterConstraint",
|
|
1224
|
+
node,
|
|
1225
|
+
valueType: values.length === 0
|
|
1226
|
+
? undefined
|
|
1227
|
+
: values.length === 1
|
|
1228
|
+
? values[0]
|
|
1229
|
+
: createConstraintUnion(node, values),
|
|
1230
|
+
type: types.length === 0
|
|
1231
|
+
? undefined
|
|
1232
|
+
: types.length === 1
|
|
1233
|
+
? types[0]
|
|
1234
|
+
: createConstraintUnion(node, types),
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
function createConstraintUnion(node, options) {
|
|
1238
|
+
const variants = createRekeyableMap();
|
|
1239
|
+
const union = createAndFinishType({
|
|
1240
|
+
kind: "Union",
|
|
1241
|
+
node,
|
|
1242
|
+
options,
|
|
1243
|
+
decorators: [],
|
|
1244
|
+
variants,
|
|
1245
|
+
expression: true,
|
|
1246
|
+
});
|
|
1247
|
+
for (const option of options) {
|
|
1248
|
+
const name = Symbol("indexer-union-variant");
|
|
1249
|
+
variants.set(name, createAndFinishType({
|
|
1250
|
+
kind: "UnionVariant",
|
|
1251
|
+
node: undefined,
|
|
1252
|
+
type: option,
|
|
1253
|
+
name,
|
|
1254
|
+
union,
|
|
1255
|
+
decorators: [],
|
|
1256
|
+
}));
|
|
1257
|
+
}
|
|
1258
|
+
return union;
|
|
1259
|
+
}
|
|
877
1260
|
function checkUnionExpression(node, mapper) {
|
|
878
1261
|
const unionType = createAndFinishType({
|
|
879
1262
|
kind: "Union",
|
|
@@ -910,13 +1293,6 @@ export function createChecker(program) {
|
|
|
910
1293
|
}
|
|
911
1294
|
return unionType;
|
|
912
1295
|
}
|
|
913
|
-
function checkValueOfExpression(node, mapper) {
|
|
914
|
-
const target = getTypeForNode(node.target, mapper);
|
|
915
|
-
return {
|
|
916
|
-
kind: "Value",
|
|
917
|
-
target,
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
1296
|
/**
|
|
921
1297
|
* Intersection produces a model type from the properties of its operands.
|
|
922
1298
|
* So this doesn't work if we don't have a known set of properties (e.g.
|
|
@@ -948,14 +1324,43 @@ export function createChecker(program) {
|
|
|
948
1324
|
name: `@${name}`,
|
|
949
1325
|
namespace,
|
|
950
1326
|
node,
|
|
951
|
-
target: checkFunctionParameter(node.target, mapper),
|
|
952
|
-
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper)),
|
|
1327
|
+
target: checkFunctionParameter(node.target, mapper, true),
|
|
1328
|
+
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, true)),
|
|
953
1329
|
implementation: implementation ?? (() => { }),
|
|
954
1330
|
});
|
|
955
1331
|
namespace.decoratorDeclarations.set(name, decoratorType);
|
|
956
1332
|
linkType(links, decoratorType, mapper);
|
|
1333
|
+
checkDecoratorLegacyMarshalling(decoratorType);
|
|
957
1334
|
return decoratorType;
|
|
958
1335
|
}
|
|
1336
|
+
function checkDecoratorLegacyMarshalling(decorator) {
|
|
1337
|
+
const marshalling = resolveDecoratorArgMarshalling(decorator);
|
|
1338
|
+
function reportDeprecatedLegacyMarshalling(param, message) {
|
|
1339
|
+
reportDeprecated(program, [
|
|
1340
|
+
`Parameter ${param.name} of decorator ${decorator.name} is using legacy marshalling but is accepting ${message}.`,
|
|
1341
|
+
`This will change in the future.`,
|
|
1342
|
+
'Add `export const $flags = {decoratorArgMarshalling: "new"}}` to your library to opt-in to the new marshalling behavior.',
|
|
1343
|
+
].join("\n"), param.node);
|
|
1344
|
+
}
|
|
1345
|
+
if (marshalling === "legacy") {
|
|
1346
|
+
for (const param of decorator.parameters) {
|
|
1347
|
+
if (param.type.valueType) {
|
|
1348
|
+
if (ignoreDiagnostics(isTypeAssignableTo(nullType, param.type.valueType, param.type))) {
|
|
1349
|
+
reportDeprecatedLegacyMarshalling(param, "null as a type");
|
|
1350
|
+
}
|
|
1351
|
+
else if (param.type.valueType.kind === "Enum" ||
|
|
1352
|
+
param.type.valueType.kind === "EnumMember" ||
|
|
1353
|
+
(isReflectionType(param.type.valueType) && param.type.valueType.name === "EnumMember")) {
|
|
1354
|
+
reportDeprecatedLegacyMarshalling(param, "enum members");
|
|
1355
|
+
}
|
|
1356
|
+
else if (ignoreDiagnostics(isTypeAssignableTo(param.type.valueType, getStdType("numeric"), param.type.valueType)) &&
|
|
1357
|
+
!canNumericConstraintBeJsNumber(param.type.valueType)) {
|
|
1358
|
+
reportDeprecatedLegacyMarshalling(param, "a numeric type that is not representable as a JS Number");
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
959
1364
|
function checkFunctionDeclaration(node, mapper) {
|
|
960
1365
|
const symbol = getMergedSymbol(node.symbol);
|
|
961
1366
|
const links = getSymbolLinks(symbol);
|
|
@@ -978,7 +1383,7 @@ export function createChecker(program) {
|
|
|
978
1383
|
name,
|
|
979
1384
|
namespace,
|
|
980
1385
|
node,
|
|
981
|
-
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper)),
|
|
1386
|
+
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, true)),
|
|
982
1387
|
returnType: node.returnType ? getTypeForNode(node.returnType, mapper) : unknownType,
|
|
983
1388
|
implementation: implementation ?? (() => { }),
|
|
984
1389
|
});
|
|
@@ -986,7 +1391,7 @@ export function createChecker(program) {
|
|
|
986
1391
|
linkType(links, functionType, mapper);
|
|
987
1392
|
return functionType;
|
|
988
1393
|
}
|
|
989
|
-
function checkFunctionParameter(node, mapper) {
|
|
1394
|
+
function checkFunctionParameter(node, mapper, mixed) {
|
|
990
1395
|
const links = getSymbolLinks(node.symbol);
|
|
991
1396
|
if (links.declaredType) {
|
|
992
1397
|
return links.declaredType;
|
|
@@ -998,24 +1403,62 @@ export function createChecker(program) {
|
|
|
998
1403
|
node.type.target.kind === SyntaxKind.ArrayExpression))) {
|
|
999
1404
|
reportCheckerDiagnostic(createDiagnostic({ code: "rest-parameter-array", target: node.type }));
|
|
1000
1405
|
}
|
|
1001
|
-
const
|
|
1002
|
-
const parameterType = createType({
|
|
1406
|
+
const base = {
|
|
1003
1407
|
kind: "FunctionParameter",
|
|
1004
1408
|
node,
|
|
1005
1409
|
name: node.id.sv,
|
|
1006
1410
|
optional: node.optional,
|
|
1007
1411
|
rest: node.rest,
|
|
1008
|
-
type,
|
|
1009
1412
|
implementation: node.symbol.value,
|
|
1010
|
-
}
|
|
1413
|
+
};
|
|
1414
|
+
let parameterType;
|
|
1415
|
+
if (mixed) {
|
|
1416
|
+
const type = node.type
|
|
1417
|
+
? getParamConstraintEntityForNode(node.type)
|
|
1418
|
+
: ({
|
|
1419
|
+
entityKind: "MixedParameterConstraint",
|
|
1420
|
+
type: unknownType,
|
|
1421
|
+
});
|
|
1422
|
+
parameterType = createType({
|
|
1423
|
+
...base,
|
|
1424
|
+
type,
|
|
1425
|
+
mixed: true,
|
|
1426
|
+
implementation: node.symbol.value,
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
else {
|
|
1430
|
+
parameterType = createType({
|
|
1431
|
+
...base,
|
|
1432
|
+
mixed: false,
|
|
1433
|
+
type: node.type ? getTypeForNode(node.type) : unknownType,
|
|
1434
|
+
implementation: node.symbol.value,
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1011
1437
|
linkType(links, parameterType, mapper);
|
|
1012
1438
|
return parameterType;
|
|
1013
1439
|
}
|
|
1014
|
-
function
|
|
1015
|
-
|
|
1016
|
-
|
|
1440
|
+
function getTypeOrValueOfTypeForNode(node, mapper) {
|
|
1441
|
+
switch (node.kind) {
|
|
1442
|
+
case SyntaxKind.ValueOfExpression:
|
|
1443
|
+
const target = getTypeForNode(node.target, mapper);
|
|
1444
|
+
return ["value", target];
|
|
1445
|
+
default:
|
|
1446
|
+
return ["type", getTypeForNode(node, mapper)];
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
function getParamConstraintEntityForNode(node, mapper) {
|
|
1450
|
+
switch (node.kind) {
|
|
1451
|
+
case SyntaxKind.UnionExpression:
|
|
1452
|
+
return checkMixedParameterConstraintUnion(node, mapper);
|
|
1453
|
+
default:
|
|
1454
|
+
const [kind, entity] = getTypeOrValueOfTypeForNode(node, mapper);
|
|
1455
|
+
return {
|
|
1456
|
+
entityKind: "MixedParameterConstraint",
|
|
1457
|
+
node: node,
|
|
1458
|
+
type: kind === "value" ? undefined : entity,
|
|
1459
|
+
valueType: kind === "value" ? entity : undefined,
|
|
1460
|
+
};
|
|
1017
1461
|
}
|
|
1018
|
-
return getTypeForNode(node, mapper);
|
|
1019
1462
|
}
|
|
1020
1463
|
function mergeModelTypes(node, options, mapper) {
|
|
1021
1464
|
const properties = createRekeyableMap();
|
|
@@ -1104,7 +1547,7 @@ export function createChecker(program) {
|
|
|
1104
1547
|
}
|
|
1105
1548
|
if (node.kind === SyntaxKind.NamespaceStatement) {
|
|
1106
1549
|
if (isArray(node.statements)) {
|
|
1107
|
-
node.statements.forEach((x) =>
|
|
1550
|
+
node.statements.forEach((x) => checkNode(x));
|
|
1108
1551
|
}
|
|
1109
1552
|
else if (node.statements) {
|
|
1110
1553
|
const subNs = checkNamespace(node.statements);
|
|
@@ -1391,13 +1834,27 @@ export function createChecker(program) {
|
|
|
1391
1834
|
let sym;
|
|
1392
1835
|
const { node, kind } = getIdentifierContext(id);
|
|
1393
1836
|
switch (kind) {
|
|
1837
|
+
case IdentifierKind.ModelExpressionProperty:
|
|
1838
|
+
case IdentifierKind.ObjectLiteralProperty:
|
|
1839
|
+
const model = getReferencedModel(node);
|
|
1840
|
+
if (model) {
|
|
1841
|
+
sym = getMemberSymbol(model.node.symbol, id.sv);
|
|
1842
|
+
}
|
|
1843
|
+
else {
|
|
1844
|
+
return undefined;
|
|
1845
|
+
}
|
|
1846
|
+
break;
|
|
1847
|
+
case IdentifierKind.ModelStatementProperty:
|
|
1394
1848
|
case IdentifierKind.Declaration:
|
|
1395
1849
|
if (node.symbol && (!isTemplatedNode(node) || mapper === undefined)) {
|
|
1396
1850
|
sym = getMergedSymbol(node.symbol);
|
|
1397
1851
|
break;
|
|
1398
1852
|
}
|
|
1399
1853
|
compilerAssert(node.parent, "Parent expected.");
|
|
1400
|
-
const containerType =
|
|
1854
|
+
const containerType = getTypeOrValueForNode(node.parent, mapper);
|
|
1855
|
+
if (containerType === null || isValue(containerType)) {
|
|
1856
|
+
return undefined;
|
|
1857
|
+
}
|
|
1401
1858
|
if (isAnonymous(containerType)) {
|
|
1402
1859
|
return undefined; // member of anonymous type cannot be referenced.
|
|
1403
1860
|
}
|
|
@@ -1452,54 +1909,251 @@ export function createChecker(program) {
|
|
|
1452
1909
|
const resolved = resolveTypeReferenceSym(node.parent, mapper, false);
|
|
1453
1910
|
return (resolved?.declarations.filter((n) => isTemplatedNode(n)) ?? []);
|
|
1454
1911
|
}
|
|
1455
|
-
function
|
|
1456
|
-
const
|
|
1457
|
-
const
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1912
|
+
function getReferencedModel(propertyNode) {
|
|
1913
|
+
const isModelOrArrayValue = (n) => n?.kind === SyntaxKind.ArrayLiteral || n?.kind === SyntaxKind.ObjectLiteral;
|
|
1914
|
+
const isModelOrArrayType = (n) => n?.kind === SyntaxKind.ModelExpression || n?.kind === SyntaxKind.TupleExpression;
|
|
1915
|
+
const isModelOrArray = (n) => isModelOrArrayValue(n) || isModelOrArrayType(n);
|
|
1916
|
+
const path = [];
|
|
1917
|
+
let preNode;
|
|
1918
|
+
const foundNode = getFirstAncestor(propertyNode, (n) => {
|
|
1919
|
+
pushToModelPath(n, preNode, path);
|
|
1920
|
+
preNode = n;
|
|
1921
|
+
return ((isModelOrArray(n) &&
|
|
1922
|
+
(n.parent?.kind === SyntaxKind.TemplateParameterDeclaration ||
|
|
1923
|
+
n.parent?.kind === SyntaxKind.DecoratorExpression)) ||
|
|
1924
|
+
(isModelOrArrayValue(n) &&
|
|
1925
|
+
(n.parent?.kind === SyntaxKind.CallExpression ||
|
|
1926
|
+
n.parent?.kind === SyntaxKind.ConstStatement)));
|
|
1927
|
+
});
|
|
1928
|
+
let refType;
|
|
1929
|
+
switch (foundNode?.parent?.kind) {
|
|
1930
|
+
case SyntaxKind.TemplateParameterDeclaration:
|
|
1931
|
+
refType = getReferencedTypeFromTemplateDeclaration(foundNode);
|
|
1932
|
+
break;
|
|
1933
|
+
case SyntaxKind.DecoratorExpression:
|
|
1934
|
+
refType = getReferencedTypeFromDecoratorArgument(foundNode);
|
|
1935
|
+
break;
|
|
1936
|
+
case SyntaxKind.CallExpression:
|
|
1937
|
+
refType = getReferencedTypeFromScalarConstructor(foundNode);
|
|
1938
|
+
break;
|
|
1939
|
+
case SyntaxKind.ConstStatement:
|
|
1940
|
+
refType = getReferencedTypeFromConstAssignment(foundNode);
|
|
1941
|
+
break;
|
|
1480
1942
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1943
|
+
return refType?.kind === "Model" || refType?.kind === "Tuple"
|
|
1944
|
+
? getNestedModel(refType, path)
|
|
1945
|
+
: undefined;
|
|
1946
|
+
function pushToModelPath(node, preNode, path) {
|
|
1947
|
+
if (node.kind === SyntaxKind.ArrayLiteral || node.kind === SyntaxKind.TupleExpression) {
|
|
1948
|
+
const index = node.values.findIndex((n) => n === preNode);
|
|
1949
|
+
if (index >= 0) {
|
|
1950
|
+
path.unshift({ tupleIndex: index });
|
|
1486
1951
|
}
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const type = base.type ?? getTypeForNode(base.declarations[0], undefined);
|
|
1490
|
-
if (isTemplateInstance(type)) {
|
|
1491
|
-
lateBindMemberContainer(type);
|
|
1492
|
-
lateBindMembers(type, base);
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
addCompletions(base.exports ?? base.members);
|
|
1952
|
+
else {
|
|
1953
|
+
compilerAssert(false, "not expected, can't find child from the parent?");
|
|
1496
1954
|
}
|
|
1497
1955
|
}
|
|
1956
|
+
if (node.kind === SyntaxKind.ModelProperty ||
|
|
1957
|
+
node.kind === SyntaxKind.ObjectLiteralProperty) {
|
|
1958
|
+
path.unshift({ propertyName: node.id.sv });
|
|
1959
|
+
}
|
|
1498
1960
|
}
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1961
|
+
function getNestedModel(modelOrTuple, path) {
|
|
1962
|
+
let cur = modelOrTuple;
|
|
1963
|
+
for (const seg of path) {
|
|
1964
|
+
switch (cur?.kind) {
|
|
1965
|
+
case "Tuple":
|
|
1966
|
+
if (seg.tupleIndex !== undefined &&
|
|
1967
|
+
seg.tupleIndex >= 0 &&
|
|
1968
|
+
seg.tupleIndex < cur.values.length) {
|
|
1969
|
+
cur = cur.values[seg.tupleIndex];
|
|
1970
|
+
}
|
|
1971
|
+
else {
|
|
1972
|
+
return undefined;
|
|
1973
|
+
}
|
|
1974
|
+
break;
|
|
1975
|
+
case "Model":
|
|
1976
|
+
if (cur.name === "Array" && seg.tupleIndex !== undefined) {
|
|
1977
|
+
cur = cur.templateMapper?.args[0];
|
|
1978
|
+
}
|
|
1979
|
+
else if (cur.name !== "Array" && seg.propertyName) {
|
|
1980
|
+
cur = cur.properties.get(seg.propertyName)?.type;
|
|
1981
|
+
}
|
|
1982
|
+
else {
|
|
1983
|
+
return undefined;
|
|
1984
|
+
}
|
|
1985
|
+
break;
|
|
1986
|
+
default:
|
|
1987
|
+
return undefined;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
return cur?.kind === "Model" ? cur : undefined;
|
|
1991
|
+
}
|
|
1992
|
+
function getReferencedTypeFromTemplateDeclaration(dftNode) {
|
|
1993
|
+
const templateParmaeterDeclNode = dftNode?.parent;
|
|
1994
|
+
if (templateParmaeterDeclNode?.kind !== SyntaxKind.TemplateParameterDeclaration ||
|
|
1995
|
+
!templateParmaeterDeclNode.constraint ||
|
|
1996
|
+
!templateParmaeterDeclNode.default ||
|
|
1997
|
+
templateParmaeterDeclNode.default !== dftNode) {
|
|
1998
|
+
return undefined;
|
|
1999
|
+
}
|
|
2000
|
+
let constraintType;
|
|
2001
|
+
if (isModelOrArrayValue(dftNode) &&
|
|
2002
|
+
templateParmaeterDeclNode.constraint.kind === SyntaxKind.ValueOfExpression) {
|
|
2003
|
+
constraintType = program.checker.getTypeForNode(templateParmaeterDeclNode.constraint.target);
|
|
2004
|
+
}
|
|
2005
|
+
else if (isModelOrArrayType(dftNode) &&
|
|
2006
|
+
templateParmaeterDeclNode.constraint.kind !== SyntaxKind.ValueOfExpression) {
|
|
2007
|
+
constraintType = program.checker.getTypeForNode(templateParmaeterDeclNode.constraint);
|
|
2008
|
+
}
|
|
2009
|
+
return constraintType;
|
|
2010
|
+
}
|
|
2011
|
+
function getReferencedTypeFromScalarConstructor(argNode) {
|
|
2012
|
+
const callExpNode = argNode?.parent;
|
|
2013
|
+
if (callExpNode?.kind !== SyntaxKind.CallExpression) {
|
|
2014
|
+
return undefined;
|
|
2015
|
+
}
|
|
2016
|
+
const ctorType = checkCallExpressionTarget(callExpNode, undefined);
|
|
2017
|
+
if (ctorType?.kind !== "ScalarConstructor") {
|
|
2018
|
+
return undefined;
|
|
2019
|
+
}
|
|
2020
|
+
const argIndex = callExpNode.arguments.findIndex((n) => n === argNode);
|
|
2021
|
+
if (argIndex < 0 || argIndex >= ctorType.parameters.length) {
|
|
2022
|
+
return undefined;
|
|
2023
|
+
}
|
|
2024
|
+
const arg = ctorType.parameters[argIndex];
|
|
2025
|
+
return arg.type;
|
|
2026
|
+
}
|
|
2027
|
+
function getReferencedTypeFromConstAssignment(valueNode) {
|
|
2028
|
+
const constNode = valueNode?.parent;
|
|
2029
|
+
if (!constNode ||
|
|
2030
|
+
constNode.kind !== SyntaxKind.ConstStatement ||
|
|
2031
|
+
!constNode.type ||
|
|
2032
|
+
constNode.value !== valueNode) {
|
|
2033
|
+
return undefined;
|
|
2034
|
+
}
|
|
2035
|
+
return program.checker.getTypeForNode(constNode.type);
|
|
2036
|
+
}
|
|
2037
|
+
function getReferencedTypeFromDecoratorArgument(decArgNode) {
|
|
2038
|
+
const decNode = decArgNode?.parent;
|
|
2039
|
+
if (decNode?.kind !== SyntaxKind.DecoratorExpression) {
|
|
2040
|
+
return undefined;
|
|
2041
|
+
}
|
|
2042
|
+
const decSym = program.checker.resolveIdentifier(decNode.target.kind === SyntaxKind.MemberExpression ? decNode.target.id : decNode.target);
|
|
2043
|
+
if (!decSym) {
|
|
2044
|
+
return undefined;
|
|
2045
|
+
}
|
|
2046
|
+
const decDecl = decSym.declarations.find((x) => x.kind === SyntaxKind.DecoratorDeclarationStatement);
|
|
2047
|
+
if (!decDecl) {
|
|
2048
|
+
return undefined;
|
|
2049
|
+
}
|
|
2050
|
+
const decType = program.checker.getTypeForNode(decDecl);
|
|
2051
|
+
compilerAssert(decType.kind === "Decorator", "Expected type to be a Decorator.");
|
|
2052
|
+
const argIndex = decNode.arguments.findIndex((n) => n === decArgNode);
|
|
2053
|
+
if (argIndex < 0 || argIndex >= decType.parameters.length) {
|
|
2054
|
+
return undefined;
|
|
2055
|
+
}
|
|
2056
|
+
const decArg = decType.parameters[argIndex];
|
|
2057
|
+
let type;
|
|
2058
|
+
if (isModelOrArrayValue(decArgNode)) {
|
|
2059
|
+
type = decArg.type.valueType;
|
|
2060
|
+
}
|
|
2061
|
+
else if (isModelOrArrayType(decArgNode)) {
|
|
2062
|
+
type = decArg.type.type ?? decArg.type.valueType;
|
|
2063
|
+
}
|
|
2064
|
+
else {
|
|
2065
|
+
compilerAssert(false, "not expected node type to get reference model from decorator argument");
|
|
2066
|
+
}
|
|
2067
|
+
return type;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
function resolveCompletions(identifier) {
|
|
2071
|
+
const completions = new Map();
|
|
2072
|
+
const { kind, node: ancestor } = getIdentifierContext(identifier);
|
|
2073
|
+
switch (kind) {
|
|
2074
|
+
case IdentifierKind.Using:
|
|
2075
|
+
case IdentifierKind.Decorator:
|
|
2076
|
+
case IdentifierKind.Function:
|
|
2077
|
+
case IdentifierKind.TypeReference:
|
|
2078
|
+
case IdentifierKind.ModelExpressionProperty:
|
|
2079
|
+
case IdentifierKind.ModelStatementProperty:
|
|
2080
|
+
case IdentifierKind.ObjectLiteralProperty:
|
|
2081
|
+
break; // supported
|
|
2082
|
+
case IdentifierKind.Other:
|
|
2083
|
+
return completions; // not implemented
|
|
2084
|
+
case IdentifierKind.Declaration:
|
|
2085
|
+
return completions; // cannot complete, name can be chosen arbitrarily
|
|
2086
|
+
case IdentifierKind.TemplateArgument: {
|
|
2087
|
+
const templates = getTemplateDeclarationsForArgument(ancestor, undefined);
|
|
2088
|
+
for (const template of templates) {
|
|
2089
|
+
for (const param of template.templateParameters) {
|
|
2090
|
+
addCompletion(param.id.sv, param.symbol);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
return completions;
|
|
2094
|
+
}
|
|
2095
|
+
default:
|
|
2096
|
+
const _assertNever = kind;
|
|
2097
|
+
compilerAssert(false, "Unreachable");
|
|
2098
|
+
}
|
|
2099
|
+
if (kind === IdentifierKind.ModelStatementProperty) {
|
|
2100
|
+
const model = ancestor.parent;
|
|
2101
|
+
const modelType = program.checker.getTypeForNode(model);
|
|
2102
|
+
const baseType = modelType.baseModel;
|
|
2103
|
+
const baseNode = baseType?.node;
|
|
2104
|
+
if (!baseNode) {
|
|
2105
|
+
return completions;
|
|
2106
|
+
}
|
|
2107
|
+
for (const prop of baseType.properties.values()) {
|
|
2108
|
+
if (identifier.sv === prop.name || !modelType.properties.has(prop.name)) {
|
|
2109
|
+
const sym = getMemberSymbol(baseNode.symbol, prop.name);
|
|
2110
|
+
if (sym) {
|
|
2111
|
+
addCompletion(prop.name, sym);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
else if (kind === IdentifierKind.ModelExpressionProperty ||
|
|
2117
|
+
kind === IdentifierKind.ObjectLiteralProperty) {
|
|
2118
|
+
const model = getReferencedModel(ancestor);
|
|
2119
|
+
if (!model) {
|
|
2120
|
+
return completions;
|
|
2121
|
+
}
|
|
2122
|
+
const curModelNode = ancestor.parent;
|
|
2123
|
+
for (const prop of walkPropertiesInherited(model)) {
|
|
2124
|
+
if (identifier.sv === prop.name ||
|
|
2125
|
+
!curModelNode.properties.find((p) => (p.kind === SyntaxKind.ModelProperty ||
|
|
2126
|
+
p.kind === SyntaxKind.ObjectLiteralProperty) &&
|
|
2127
|
+
p.id.sv === prop.name)) {
|
|
2128
|
+
const sym = getMemberSymbol(model.node.symbol, prop.name);
|
|
2129
|
+
if (sym) {
|
|
2130
|
+
addCompletion(prop.name, sym);
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
else if (identifier.parent && identifier.parent.kind === SyntaxKind.MemberExpression) {
|
|
2136
|
+
let base = resolveTypeReferenceSym(identifier.parent.base, undefined, false);
|
|
2137
|
+
if (base) {
|
|
2138
|
+
if (base.flags & 2048 /* SymbolFlags.Alias */) {
|
|
2139
|
+
base = getAliasedSymbol(base, undefined, defaultSymbolResolutionOptions);
|
|
2140
|
+
}
|
|
2141
|
+
if (base) {
|
|
2142
|
+
if (isTemplatedNode(base.declarations[0])) {
|
|
2143
|
+
const type = base.type ?? getTypeForNode(base.declarations[0], undefined);
|
|
2144
|
+
if (isTemplateInstance(type)) {
|
|
2145
|
+
lateBindMemberContainer(type);
|
|
2146
|
+
lateBindMembers(type, base);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
addCompletions(base.exports ?? base.members);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
else {
|
|
2154
|
+
// We will only add template arguments if the template isn't already named
|
|
2155
|
+
// to avoid completing the name of the argument again.
|
|
2156
|
+
if (kind === IdentifierKind.TypeReference &&
|
|
1503
2157
|
exprIsBareIdentifier(ancestor) &&
|
|
1504
2158
|
ancestor.parent?.kind === SyntaxKind.TemplateArgument &&
|
|
1505
2159
|
ancestor.parent.name === undefined) {
|
|
@@ -1570,6 +2224,10 @@ export function createChecker(program) {
|
|
|
1570
2224
|
}
|
|
1571
2225
|
function shouldAddCompletion(sym) {
|
|
1572
2226
|
switch (kind) {
|
|
2227
|
+
case IdentifierKind.ModelExpressionProperty:
|
|
2228
|
+
case IdentifierKind.ModelStatementProperty:
|
|
2229
|
+
case IdentifierKind.ObjectLiteralProperty:
|
|
2230
|
+
return !!(sym.flags & 4 /* SymbolFlags.ModelProperty */);
|
|
1573
2231
|
case IdentifierKind.Decorator:
|
|
1574
2232
|
// Only return decorators and namespaces when completing decorator
|
|
1575
2233
|
return !!(sym.flags & (16384 /* SymbolFlags.Decorator */ | 4096 /* SymbolFlags.Namespace */));
|
|
@@ -1746,9 +2404,9 @@ export function createChecker(program) {
|
|
|
1746
2404
|
}));
|
|
1747
2405
|
return undefined;
|
|
1748
2406
|
}
|
|
1749
|
-
else if (base.flags &
|
|
2407
|
+
else if (base.flags & 682 /* SymbolFlags.MemberContainer */) {
|
|
1750
2408
|
if (options.checkTemplateTypes && isTemplatedNode(base.declarations[0])) {
|
|
1751
|
-
const type = base.flags &
|
|
2409
|
+
const type = base.flags & 67108864 /* SymbolFlags.LateBound */
|
|
1752
2410
|
? base.type
|
|
1753
2411
|
: getTypeForNode(base.declarations[0], mapper);
|
|
1754
2412
|
if (isTemplateInstance(type)) {
|
|
@@ -1863,17 +2521,112 @@ export function createChecker(program) {
|
|
|
1863
2521
|
}
|
|
1864
2522
|
}
|
|
1865
2523
|
function checkStringTemplateExpresion(node, mapper) {
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2524
|
+
let hasType = false;
|
|
2525
|
+
let hasValue = false;
|
|
2526
|
+
const spanTypeOrValues = node.spans.map((span) => [span, checkNode(span.expression, mapper)]);
|
|
2527
|
+
for (const [_, typeOrValue] of spanTypeOrValues) {
|
|
2528
|
+
if (typeOrValue !== null) {
|
|
2529
|
+
if (isValue(typeOrValue)) {
|
|
2530
|
+
hasValue = true;
|
|
2531
|
+
}
|
|
2532
|
+
else if ("kind" in typeOrValue && typeOrValue.kind === "TemplateParameter") {
|
|
2533
|
+
if (typeOrValue.constraint) {
|
|
2534
|
+
if (typeOrValue.constraint.valueType) {
|
|
2535
|
+
hasValue = true;
|
|
2536
|
+
}
|
|
2537
|
+
if (typeOrValue.constraint.type) {
|
|
2538
|
+
hasType = true;
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
else {
|
|
2542
|
+
hasType = true;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
else {
|
|
2546
|
+
hasType = true;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
if (hasType && hasValue) {
|
|
2551
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2552
|
+
code: "mixed-string-template",
|
|
2553
|
+
target: node,
|
|
2554
|
+
}));
|
|
2555
|
+
return null;
|
|
2556
|
+
}
|
|
2557
|
+
if (hasValue) {
|
|
2558
|
+
let str = node.head.value;
|
|
2559
|
+
for (const [span, typeOrValue] of spanTypeOrValues) {
|
|
2560
|
+
if (typeOrValue !== null &&
|
|
2561
|
+
(!("kind" in typeOrValue) || typeOrValue.kind !== "TemplateParameter")) {
|
|
2562
|
+
compilerAssert(typeOrValue !== null && isValue(typeOrValue), "Expected value.");
|
|
2563
|
+
str += stringifyValueForTemplate(typeOrValue);
|
|
2564
|
+
}
|
|
2565
|
+
str += span.literal.value;
|
|
2566
|
+
}
|
|
2567
|
+
return checkStringValue(createLiteralType(str), undefined, node);
|
|
2568
|
+
}
|
|
2569
|
+
else {
|
|
2570
|
+
let hasNonStringElement = false;
|
|
2571
|
+
let stringValue = node.head.value;
|
|
2572
|
+
const spans = [createTemplateSpanLiteral(node.head)];
|
|
2573
|
+
for (const [span, typeOrValue] of spanTypeOrValues) {
|
|
2574
|
+
compilerAssert(typeOrValue !== null && !isValue(typeOrValue), "Expected type.");
|
|
2575
|
+
const type = typeOrValue.entityKind === "Indeterminate" ? typeOrValue.type : typeOrValue;
|
|
2576
|
+
const spanValue = createTemplateSpanValue(span.expression, type);
|
|
2577
|
+
spans.push(spanValue);
|
|
2578
|
+
const spanValueAsString = stringifyTypeForTemplate(type);
|
|
2579
|
+
if (spanValueAsString) {
|
|
2580
|
+
stringValue += spanValueAsString;
|
|
2581
|
+
}
|
|
2582
|
+
else {
|
|
2583
|
+
hasNonStringElement = true;
|
|
2584
|
+
}
|
|
2585
|
+
spans.push(createTemplateSpanLiteral(span.literal));
|
|
2586
|
+
stringValue += span.literal.value;
|
|
2587
|
+
}
|
|
2588
|
+
return createIndeterminateEntity(createType({
|
|
2589
|
+
kind: "StringTemplate",
|
|
2590
|
+
node,
|
|
2591
|
+
spans,
|
|
2592
|
+
stringValue: hasNonStringElement ? undefined : stringValue,
|
|
2593
|
+
}));
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
function createIndeterminateEntity(type) {
|
|
2597
|
+
return {
|
|
2598
|
+
entityKind: "Indeterminate",
|
|
2599
|
+
type,
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
function stringifyTypeForTemplate(type) {
|
|
2603
|
+
switch (type.kind) {
|
|
2604
|
+
case "String":
|
|
2605
|
+
case "Number":
|
|
2606
|
+
case "Boolean":
|
|
2607
|
+
return String(type.value);
|
|
2608
|
+
case "StringTemplate":
|
|
2609
|
+
if (type.stringValue !== undefined) {
|
|
2610
|
+
return type.stringValue;
|
|
2611
|
+
}
|
|
2612
|
+
return undefined;
|
|
2613
|
+
default:
|
|
2614
|
+
return undefined;
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
function stringifyValueForTemplate(value) {
|
|
2618
|
+
switch (value.valueKind) {
|
|
2619
|
+
case "StringValue":
|
|
2620
|
+
case "NumericValue":
|
|
2621
|
+
case "BooleanValue":
|
|
2622
|
+
return value.value.toString();
|
|
2623
|
+
default:
|
|
2624
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2625
|
+
code: "non-literal-string-template",
|
|
2626
|
+
target: value,
|
|
2627
|
+
}));
|
|
2628
|
+
return `[${value.valueKind}]`;
|
|
1870
2629
|
}
|
|
1871
|
-
const type = createType({
|
|
1872
|
-
kind: "StringTemplate",
|
|
1873
|
-
node,
|
|
1874
|
-
spans,
|
|
1875
|
-
});
|
|
1876
|
-
return type;
|
|
1877
2630
|
}
|
|
1878
2631
|
function createTemplateSpanLiteral(node) {
|
|
1879
2632
|
return createType({
|
|
@@ -1883,22 +2636,31 @@ export function createChecker(program) {
|
|
|
1883
2636
|
type: getLiteralType(node),
|
|
1884
2637
|
});
|
|
1885
2638
|
}
|
|
1886
|
-
function createTemplateSpanValue(node,
|
|
2639
|
+
function createTemplateSpanValue(node, type) {
|
|
1887
2640
|
return createType({
|
|
1888
2641
|
kind: "StringTemplateSpan",
|
|
1889
2642
|
node: node,
|
|
1890
2643
|
isInterpolated: true,
|
|
1891
|
-
type:
|
|
2644
|
+
type: type,
|
|
1892
2645
|
});
|
|
1893
2646
|
}
|
|
1894
2647
|
function checkStringLiteral(str) {
|
|
1895
|
-
return
|
|
2648
|
+
return {
|
|
2649
|
+
entityKind: "Indeterminate",
|
|
2650
|
+
type: getLiteralType(str),
|
|
2651
|
+
};
|
|
1896
2652
|
}
|
|
1897
2653
|
function checkNumericLiteral(num) {
|
|
1898
|
-
return
|
|
2654
|
+
return {
|
|
2655
|
+
entityKind: "Indeterminate",
|
|
2656
|
+
type: getLiteralType(num),
|
|
2657
|
+
};
|
|
1899
2658
|
}
|
|
1900
2659
|
function checkBooleanLiteral(bool) {
|
|
1901
|
-
return
|
|
2660
|
+
return {
|
|
2661
|
+
entityKind: "Indeterminate",
|
|
2662
|
+
type: getLiteralType(bool),
|
|
2663
|
+
};
|
|
1902
2664
|
}
|
|
1903
2665
|
function checkProgram() {
|
|
1904
2666
|
program.reportDuplicateSymbols(globalNamespaceNode.symbol.exports);
|
|
@@ -1947,7 +2709,7 @@ export function createChecker(program) {
|
|
|
1947
2709
|
}
|
|
1948
2710
|
function checkSourceFile(file) {
|
|
1949
2711
|
for (const statement of file.statements) {
|
|
1950
|
-
|
|
2712
|
+
checkNode(statement, undefined);
|
|
1951
2713
|
}
|
|
1952
2714
|
}
|
|
1953
2715
|
/**
|
|
@@ -2056,7 +2818,8 @@ export function createChecker(program) {
|
|
|
2056
2818
|
return false;
|
|
2057
2819
|
}
|
|
2058
2820
|
// Some of the mapper args are still template parameter so we shouldn't create the type.
|
|
2059
|
-
return !mapper.partial &&
|
|
2821
|
+
return (!mapper.partial &&
|
|
2822
|
+
mapper.args.every((t) => isValue(t) || t.entityKind === "Indeterminate" || t.kind !== "TemplateParameter"));
|
|
2060
2823
|
}
|
|
2061
2824
|
function checkModelExpression(node, mapper) {
|
|
2062
2825
|
const properties = createRekeyableMap();
|
|
@@ -2149,6 +2912,414 @@ export function createChecker(program) {
|
|
|
2149
2912
|
};
|
|
2150
2913
|
}
|
|
2151
2914
|
}
|
|
2915
|
+
function checkObjectValue(node, mapper, constraint) {
|
|
2916
|
+
const properties = checkObjectLiteralProperties(node, mapper);
|
|
2917
|
+
if (properties === null) {
|
|
2918
|
+
return null;
|
|
2919
|
+
}
|
|
2920
|
+
const preciseType = createTypeForObjectValue(node, properties);
|
|
2921
|
+
if (constraint && !checkTypeOfValueMatchConstraint(preciseType, constraint, node)) {
|
|
2922
|
+
return null;
|
|
2923
|
+
}
|
|
2924
|
+
return {
|
|
2925
|
+
entityKind: "Value",
|
|
2926
|
+
valueKind: "ObjectValue",
|
|
2927
|
+
node: node,
|
|
2928
|
+
properties,
|
|
2929
|
+
type: constraint ? constraint.type : preciseType,
|
|
2930
|
+
};
|
|
2931
|
+
}
|
|
2932
|
+
function createTypeForObjectValue(node, properties) {
|
|
2933
|
+
const model = createType({
|
|
2934
|
+
kind: "Model",
|
|
2935
|
+
name: "",
|
|
2936
|
+
node,
|
|
2937
|
+
properties: createRekeyableMap(),
|
|
2938
|
+
decorators: [],
|
|
2939
|
+
derivedModels: [],
|
|
2940
|
+
sourceModels: [],
|
|
2941
|
+
});
|
|
2942
|
+
for (const prop of properties.values()) {
|
|
2943
|
+
model.properties.set(prop.name, createModelPropertyForObjectPropertyDescriptor(prop, model));
|
|
2944
|
+
}
|
|
2945
|
+
return finishType(model);
|
|
2946
|
+
}
|
|
2947
|
+
function createModelPropertyForObjectPropertyDescriptor(prop, parentModel) {
|
|
2948
|
+
return createAndFinishType({
|
|
2949
|
+
kind: "ModelProperty",
|
|
2950
|
+
node: prop.node,
|
|
2951
|
+
model: parentModel,
|
|
2952
|
+
optional: false,
|
|
2953
|
+
name: prop.name,
|
|
2954
|
+
type: prop.value.type,
|
|
2955
|
+
decorators: [],
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
function checkObjectLiteralProperties(node, mapper) {
|
|
2959
|
+
const properties = new Map();
|
|
2960
|
+
let hasError = false;
|
|
2961
|
+
for (const prop of node.properties) {
|
|
2962
|
+
if ("id" in prop) {
|
|
2963
|
+
const value = getValueForNode(prop.value, mapper);
|
|
2964
|
+
if (value === null) {
|
|
2965
|
+
hasError = true;
|
|
2966
|
+
}
|
|
2967
|
+
else {
|
|
2968
|
+
properties.set(prop.id.sv, { name: prop.id.sv, value: value, node: prop });
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
else {
|
|
2972
|
+
const targetType = checkObjectSpreadProperty(prop.target, mapper);
|
|
2973
|
+
if (targetType) {
|
|
2974
|
+
for (const [name, value] of targetType.properties) {
|
|
2975
|
+
properties.set(name, { ...value });
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
return hasError ? null : properties;
|
|
2981
|
+
}
|
|
2982
|
+
function checkObjectSpreadProperty(targetNode, mapper) {
|
|
2983
|
+
const value = getValueForNode(targetNode, mapper);
|
|
2984
|
+
if (value === null) {
|
|
2985
|
+
return null;
|
|
2986
|
+
}
|
|
2987
|
+
if (value.valueKind !== "ObjectValue") {
|
|
2988
|
+
reportCheckerDiagnostic(createDiagnostic({ code: "spread-object", target: targetNode }));
|
|
2989
|
+
return null;
|
|
2990
|
+
}
|
|
2991
|
+
return value;
|
|
2992
|
+
}
|
|
2993
|
+
function checkArrayValue(node, mapper, constraint) {
|
|
2994
|
+
let hasError = false;
|
|
2995
|
+
const values = node.values.map((itemNode) => {
|
|
2996
|
+
const value = getValueForNode(itemNode, mapper);
|
|
2997
|
+
if (value === null) {
|
|
2998
|
+
hasError = true;
|
|
2999
|
+
}
|
|
3000
|
+
return value;
|
|
3001
|
+
});
|
|
3002
|
+
if (hasError) {
|
|
3003
|
+
return null;
|
|
3004
|
+
}
|
|
3005
|
+
const preciseType = createTypeForArrayValue(node, values);
|
|
3006
|
+
if (constraint && !checkTypeOfValueMatchConstraint(preciseType, constraint, node)) {
|
|
3007
|
+
return null;
|
|
3008
|
+
}
|
|
3009
|
+
return {
|
|
3010
|
+
entityKind: "Value",
|
|
3011
|
+
valueKind: "ArrayValue",
|
|
3012
|
+
node: node,
|
|
3013
|
+
values: values,
|
|
3014
|
+
type: constraint ? constraint.type : preciseType,
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
3017
|
+
function createTypeForArrayValue(node, values) {
|
|
3018
|
+
return createAndFinishType({
|
|
3019
|
+
kind: "Tuple",
|
|
3020
|
+
node,
|
|
3021
|
+
values: values.map((x) => x.type),
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
function inferScalarForPrimitiveValue(type, literalType) {
|
|
3025
|
+
if (type === undefined) {
|
|
3026
|
+
return undefined;
|
|
3027
|
+
}
|
|
3028
|
+
switch (type.kind) {
|
|
3029
|
+
case "Scalar":
|
|
3030
|
+
if (ignoreDiagnostics(isTypeAssignableTo(literalType, type, literalType))) {
|
|
3031
|
+
return type;
|
|
3032
|
+
}
|
|
3033
|
+
return undefined;
|
|
3034
|
+
case "Union":
|
|
3035
|
+
let found = undefined;
|
|
3036
|
+
for (const variant of type.variants.values()) {
|
|
3037
|
+
const scalar = inferScalarForPrimitiveValue(variant.type, literalType);
|
|
3038
|
+
if (scalar) {
|
|
3039
|
+
if (found) {
|
|
3040
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3041
|
+
code: "ambiguous-scalar-type",
|
|
3042
|
+
format: {
|
|
3043
|
+
value: getTypeName(literalType),
|
|
3044
|
+
types: [found, scalar].map((x) => x.name).join(", "),
|
|
3045
|
+
example: found.name,
|
|
3046
|
+
},
|
|
3047
|
+
target: literalType,
|
|
3048
|
+
}));
|
|
3049
|
+
return undefined;
|
|
3050
|
+
}
|
|
3051
|
+
else {
|
|
3052
|
+
found = scalar;
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
return found;
|
|
3057
|
+
default:
|
|
3058
|
+
return undefined;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
function checkStringValue(literalType, constraint, node) {
|
|
3062
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
3063
|
+
return null;
|
|
3064
|
+
}
|
|
3065
|
+
let value;
|
|
3066
|
+
if (literalType.kind === "StringTemplate") {
|
|
3067
|
+
if (literalType.stringValue) {
|
|
3068
|
+
value = literalType.stringValue;
|
|
3069
|
+
}
|
|
3070
|
+
else {
|
|
3071
|
+
reportCheckerDiagnostics(explainStringTemplateNotSerializable(literalType));
|
|
3072
|
+
return null;
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
else {
|
|
3076
|
+
value = literalType.value;
|
|
3077
|
+
}
|
|
3078
|
+
const scalar = inferScalarForPrimitiveValue(constraint?.type, literalType);
|
|
3079
|
+
return {
|
|
3080
|
+
entityKind: "Value",
|
|
3081
|
+
valueKind: "StringValue",
|
|
3082
|
+
value,
|
|
3083
|
+
type: constraint ? constraint.type : literalType,
|
|
3084
|
+
scalar,
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
3087
|
+
function checkNumericValue(literalType, constraint, node) {
|
|
3088
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
3089
|
+
return null;
|
|
3090
|
+
}
|
|
3091
|
+
const scalar = inferScalarForPrimitiveValue(constraint?.type, literalType);
|
|
3092
|
+
return {
|
|
3093
|
+
entityKind: "Value",
|
|
3094
|
+
valueKind: "NumericValue",
|
|
3095
|
+
value: Numeric(literalType.valueAsString),
|
|
3096
|
+
type: constraint ? constraint.type : literalType,
|
|
3097
|
+
scalar,
|
|
3098
|
+
};
|
|
3099
|
+
}
|
|
3100
|
+
function checkBooleanValue(literalType, constraint, node) {
|
|
3101
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
3102
|
+
return null;
|
|
3103
|
+
}
|
|
3104
|
+
const scalar = inferScalarForPrimitiveValue(constraint?.type, literalType);
|
|
3105
|
+
return {
|
|
3106
|
+
entityKind: "Value",
|
|
3107
|
+
valueKind: "BooleanValue",
|
|
3108
|
+
value: literalType.value,
|
|
3109
|
+
type: constraint ? constraint.type : literalType,
|
|
3110
|
+
scalar,
|
|
3111
|
+
};
|
|
3112
|
+
}
|
|
3113
|
+
function checkNullValue(literalType, constraint, node) {
|
|
3114
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
3115
|
+
return null;
|
|
3116
|
+
}
|
|
3117
|
+
return {
|
|
3118
|
+
entityKind: "Value",
|
|
3119
|
+
valueKind: "NullValue",
|
|
3120
|
+
type: constraint ? constraint.type : literalType,
|
|
3121
|
+
value: null,
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
function checkEnumValue(literalType, constraint, node) {
|
|
3125
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
3126
|
+
return null;
|
|
3127
|
+
}
|
|
3128
|
+
return {
|
|
3129
|
+
entityKind: "Value",
|
|
3130
|
+
valueKind: "EnumValue",
|
|
3131
|
+
type: constraint ? constraint.type : literalType,
|
|
3132
|
+
value: literalType,
|
|
3133
|
+
};
|
|
3134
|
+
}
|
|
3135
|
+
function checkCallExpressionTarget(node, mapper) {
|
|
3136
|
+
const target = checkTypeReference(node.target, mapper);
|
|
3137
|
+
if (target.kind === "Scalar" || target.kind === "ScalarConstructor") {
|
|
3138
|
+
return target;
|
|
3139
|
+
}
|
|
3140
|
+
else {
|
|
3141
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3142
|
+
code: "non-callable",
|
|
3143
|
+
format: { type: target.kind },
|
|
3144
|
+
target: node.target,
|
|
3145
|
+
}));
|
|
3146
|
+
return null;
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
/** Check the arguments of the call expression are a single value of the given syntax. */
|
|
3150
|
+
function checkPrimitiveArg(node, scalar, valueKind) {
|
|
3151
|
+
if (node.arguments.length !== 1) {
|
|
3152
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3153
|
+
code: "invalid-primitive-init",
|
|
3154
|
+
target: node.target,
|
|
3155
|
+
}));
|
|
3156
|
+
return null;
|
|
3157
|
+
}
|
|
3158
|
+
const argNode = node.arguments[0];
|
|
3159
|
+
const value = getValueForNode(argNode, undefined);
|
|
3160
|
+
if (value === null) {
|
|
3161
|
+
return null; // error should already have been reported above.
|
|
3162
|
+
}
|
|
3163
|
+
if (value.valueKind !== valueKind) {
|
|
3164
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3165
|
+
code: "invalid-primitive-init",
|
|
3166
|
+
messageId: "invalidArg",
|
|
3167
|
+
format: { actual: value.valueKind, expected: valueKind },
|
|
3168
|
+
target: argNode,
|
|
3169
|
+
}));
|
|
3170
|
+
return null;
|
|
3171
|
+
}
|
|
3172
|
+
if (!checkValueOfType(value, scalar, argNode)) {
|
|
3173
|
+
return null;
|
|
3174
|
+
}
|
|
3175
|
+
return { ...value, scalar, type: scalar };
|
|
3176
|
+
}
|
|
3177
|
+
function createScalarValue(node, mapper, declaration) {
|
|
3178
|
+
let hasError = false;
|
|
3179
|
+
const minArgs = declaration.parameters.filter((x) => !x.optional && !x.rest).length ?? 0;
|
|
3180
|
+
const maxArgs = declaration.parameters[declaration.parameters.length - 1]?.rest
|
|
3181
|
+
? undefined
|
|
3182
|
+
: declaration.parameters.length;
|
|
3183
|
+
if (node.arguments.length < minArgs ||
|
|
3184
|
+
(maxArgs !== undefined && node.arguments.length > maxArgs)) {
|
|
3185
|
+
// In the case we have too little args then this decorator is not applicable.
|
|
3186
|
+
// If there is too many args then we can still run the decorator as long as the args are valid.
|
|
3187
|
+
if (node.arguments.length < minArgs) {
|
|
3188
|
+
hasError = true;
|
|
3189
|
+
}
|
|
3190
|
+
if (maxArgs === undefined) {
|
|
3191
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3192
|
+
code: "invalid-argument-count",
|
|
3193
|
+
messageId: "atLeast",
|
|
3194
|
+
format: { actual: node.arguments.length.toString(), expected: minArgs.toString() },
|
|
3195
|
+
target: node,
|
|
3196
|
+
}));
|
|
3197
|
+
}
|
|
3198
|
+
else {
|
|
3199
|
+
const expected = minArgs === maxArgs ? minArgs.toString() : `${minArgs}-${maxArgs}`;
|
|
3200
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3201
|
+
code: "invalid-argument-count",
|
|
3202
|
+
format: { actual: node.arguments.length.toString(), expected },
|
|
3203
|
+
target: node,
|
|
3204
|
+
}));
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
const resolvedArgs = [];
|
|
3208
|
+
for (const [index, parameter] of declaration.parameters.entries()) {
|
|
3209
|
+
if (parameter.rest) {
|
|
3210
|
+
const restType = getIndexType(parameter.type);
|
|
3211
|
+
if (restType) {
|
|
3212
|
+
for (let i = index; i < node.arguments.length; i++) {
|
|
3213
|
+
const argNode = node.arguments[i];
|
|
3214
|
+
if (argNode) {
|
|
3215
|
+
const arg = getValueForNode(argNode, mapper, { kind: "argument", type: restType });
|
|
3216
|
+
if (arg === null) {
|
|
3217
|
+
hasError = true;
|
|
3218
|
+
continue;
|
|
3219
|
+
}
|
|
3220
|
+
if (checkValueOfType(arg, restType, argNode)) {
|
|
3221
|
+
resolvedArgs.push(arg);
|
|
3222
|
+
}
|
|
3223
|
+
else {
|
|
3224
|
+
hasError = true;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
break;
|
|
3230
|
+
}
|
|
3231
|
+
const argNode = node.arguments[index];
|
|
3232
|
+
if (argNode) {
|
|
3233
|
+
const arg = getValueForNode(argNode, mapper, {
|
|
3234
|
+
kind: "argument",
|
|
3235
|
+
type: parameter.type,
|
|
3236
|
+
});
|
|
3237
|
+
if (arg === null) {
|
|
3238
|
+
hasError = true;
|
|
3239
|
+
continue;
|
|
3240
|
+
}
|
|
3241
|
+
if (checkValueOfType(arg, parameter.type, argNode)) {
|
|
3242
|
+
resolvedArgs.push(arg);
|
|
3243
|
+
}
|
|
3244
|
+
else {
|
|
3245
|
+
hasError = true;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
if (hasError) {
|
|
3250
|
+
return null;
|
|
3251
|
+
}
|
|
3252
|
+
return {
|
|
3253
|
+
entityKind: "Value",
|
|
3254
|
+
valueKind: "ScalarValue",
|
|
3255
|
+
value: {
|
|
3256
|
+
name: declaration.name,
|
|
3257
|
+
args: resolvedArgs,
|
|
3258
|
+
},
|
|
3259
|
+
scalar: declaration.scalar,
|
|
3260
|
+
type: declaration.scalar,
|
|
3261
|
+
};
|
|
3262
|
+
}
|
|
3263
|
+
function checkCallExpression(node, mapper) {
|
|
3264
|
+
const target = checkCallExpressionTarget(node, mapper);
|
|
3265
|
+
if (target === null) {
|
|
3266
|
+
return null;
|
|
3267
|
+
}
|
|
3268
|
+
if (target.kind === "ScalarConstructor") {
|
|
3269
|
+
return createScalarValue(node, mapper, target);
|
|
3270
|
+
}
|
|
3271
|
+
if (areScalarsRelated(target, getStdType("string"))) {
|
|
3272
|
+
return checkPrimitiveArg(node, target, "StringValue");
|
|
3273
|
+
}
|
|
3274
|
+
else if (areScalarsRelated(target, getStdType("numeric"))) {
|
|
3275
|
+
return checkPrimitiveArg(node, target, "NumericValue");
|
|
3276
|
+
}
|
|
3277
|
+
else if (areScalarsRelated(target, getStdType("boolean"))) {
|
|
3278
|
+
return checkPrimitiveArg(node, target, "BooleanValue");
|
|
3279
|
+
}
|
|
3280
|
+
else {
|
|
3281
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3282
|
+
code: "named-init-required",
|
|
3283
|
+
format: { typeKind: target.kind },
|
|
3284
|
+
target: node.target,
|
|
3285
|
+
}));
|
|
3286
|
+
return null;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
function checkTypeOfExpression(node, mapper) {
|
|
3290
|
+
const entity = checkNode(node.target, mapper, undefined);
|
|
3291
|
+
if (entity === null) {
|
|
3292
|
+
// Shouldn't need to emit error as we assume null value already emitted error when produced
|
|
3293
|
+
return errorType;
|
|
3294
|
+
}
|
|
3295
|
+
if (entity.entityKind === "Indeterminate") {
|
|
3296
|
+
return entity.type;
|
|
3297
|
+
}
|
|
3298
|
+
if (isType(entity)) {
|
|
3299
|
+
if (entity.kind === "TemplateParameter") {
|
|
3300
|
+
if (entity.constraint === undefined || entity.constraint.type !== undefined) {
|
|
3301
|
+
// means this template constraint will accept values
|
|
3302
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3303
|
+
code: "expect-value",
|
|
3304
|
+
messageId: "templateConstraint",
|
|
3305
|
+
format: { name: getTypeName(entity) },
|
|
3306
|
+
target: node.target,
|
|
3307
|
+
}));
|
|
3308
|
+
return errorType;
|
|
3309
|
+
}
|
|
3310
|
+
else if (entity.constraint.valueType) {
|
|
3311
|
+
return entity.constraint.valueType;
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3315
|
+
code: "expect-value",
|
|
3316
|
+
format: { name: getTypeName(entity) },
|
|
3317
|
+
target: node.target,
|
|
3318
|
+
}));
|
|
3319
|
+
return entity;
|
|
3320
|
+
}
|
|
3321
|
+
return entity.type;
|
|
3322
|
+
}
|
|
2152
3323
|
function createUnion(options) {
|
|
2153
3324
|
const variants = createRekeyableMap();
|
|
2154
3325
|
const union = createAndFinishType({
|
|
@@ -2229,6 +3400,15 @@ export function createChecker(program) {
|
|
|
2229
3400
|
}
|
|
2230
3401
|
}
|
|
2231
3402
|
break;
|
|
3403
|
+
case SyntaxKind.ScalarStatement:
|
|
3404
|
+
if (node.extends && node.extends.kind === SyntaxKind.TypeReference) {
|
|
3405
|
+
resolveAndCopyMembers(node.extends);
|
|
3406
|
+
}
|
|
3407
|
+
for (const member of node.members) {
|
|
3408
|
+
const name = member.id.sv;
|
|
3409
|
+
bindMember(name, member, 33554432 /* SymbolFlags.ScalarMember */);
|
|
3410
|
+
}
|
|
3411
|
+
break;
|
|
2232
3412
|
case SyntaxKind.ModelExpression:
|
|
2233
3413
|
for (const prop of node.properties) {
|
|
2234
3414
|
if (prop.kind === SyntaxKind.ModelSpreadProperty) {
|
|
@@ -2356,7 +3536,7 @@ export function createChecker(program) {
|
|
|
2356
3536
|
const sigTable = getOrCreateAugmentedSymbolTable(sig.metatypeMembers);
|
|
2357
3537
|
const sigParameterSym = sigTable.get("parameters");
|
|
2358
3538
|
if (sigParameterSym !== undefined) {
|
|
2359
|
-
const parametersSym = createSymbol(sigParameterSym.declarations[0], "parameters", 2 /* SymbolFlags.Model */ &
|
|
3539
|
+
const parametersSym = createSymbol(sigParameterSym.declarations[0], "parameters", 2 /* SymbolFlags.Model */ & 682 /* SymbolFlags.MemberContainer */);
|
|
2360
3540
|
copyMembersToContainer(parametersSym, sigParameterSym.members);
|
|
2361
3541
|
table.set("parameters", parametersSym);
|
|
2362
3542
|
table.set("returnType", sigTable.get("returnType"));
|
|
@@ -2381,17 +3561,17 @@ export function createChecker(program) {
|
|
|
2381
3561
|
return;
|
|
2382
3562
|
switch (type.kind) {
|
|
2383
3563
|
case "Model":
|
|
2384
|
-
type.symbol = createSymbol(type.node, type.name, 2 /* SymbolFlags.Model */ |
|
|
3564
|
+
type.symbol = createSymbol(type.node, type.name, 2 /* SymbolFlags.Model */ | 67108864 /* SymbolFlags.LateBound */);
|
|
2385
3565
|
mutate(type.symbol).type = type;
|
|
2386
3566
|
break;
|
|
2387
3567
|
case "Interface":
|
|
2388
|
-
type.symbol = createSymbol(type.node, type.name, 128 /* SymbolFlags.Interface */ |
|
|
3568
|
+
type.symbol = createSymbol(type.node, type.name, 128 /* SymbolFlags.Interface */ | 67108864 /* SymbolFlags.LateBound */);
|
|
2389
3569
|
mutate(type.symbol).type = type;
|
|
2390
3570
|
break;
|
|
2391
3571
|
case "Union":
|
|
2392
3572
|
if (!type.name)
|
|
2393
3573
|
return; // don't make a symbol for anonymous unions
|
|
2394
|
-
type.symbol = createSymbol(type.node, type.name, 512 /* SymbolFlags.Union */ |
|
|
3574
|
+
type.symbol = createSymbol(type.node, type.name, 512 /* SymbolFlags.Union */ | 67108864 /* SymbolFlags.LateBound */);
|
|
2395
3575
|
mutate(type.symbol).type = type;
|
|
2396
3576
|
break;
|
|
2397
3577
|
}
|
|
@@ -2404,6 +3584,11 @@ export function createChecker(program) {
|
|
|
2404
3584
|
lateBindMember(prop, 4 /* SymbolFlags.ModelProperty */);
|
|
2405
3585
|
}
|
|
2406
3586
|
break;
|
|
3587
|
+
case "Scalar":
|
|
3588
|
+
for (const member of type.constructors.values()) {
|
|
3589
|
+
lateBindMember(member, 33555780 /* SymbolFlags.Member */);
|
|
3590
|
+
}
|
|
3591
|
+
break;
|
|
2407
3592
|
case "Enum":
|
|
2408
3593
|
for (const member of type.members.values()) {
|
|
2409
3594
|
lateBindMember(member, 64 /* SymbolFlags.EnumMember */);
|
|
@@ -2425,7 +3610,7 @@ export function createChecker(program) {
|
|
|
2425
3610
|
// don't bind anything for union expressions
|
|
2426
3611
|
return;
|
|
2427
3612
|
}
|
|
2428
|
-
const sym = createSymbol(member.node, member.name, kind |
|
|
3613
|
+
const sym = createSymbol(member.node, member.name, kind | 67108864 /* SymbolFlags.LateBound */, containerSym);
|
|
2429
3614
|
mutate(sym).type = member;
|
|
2430
3615
|
compilerAssert(containerSym.members, "containerSym.members is undefined");
|
|
2431
3616
|
containerMembers ??= getOrCreateAugmentedSymbolTable(containerSym.members);
|
|
@@ -2611,7 +3796,14 @@ export function createChecker(program) {
|
|
|
2611
3796
|
else {
|
|
2612
3797
|
pendingResolutions.start(symId, ResolutionKind.Type);
|
|
2613
3798
|
type.type = getTypeForNode(prop.value, mapper);
|
|
2614
|
-
|
|
3799
|
+
if (prop.default) {
|
|
3800
|
+
const defaultValue = checkDefaultValue(prop.default, type.type);
|
|
3801
|
+
if (defaultValue !== null) {
|
|
3802
|
+
type.defaultValue = defaultValue;
|
|
3803
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
3804
|
+
type.default = checkLegacyDefault(prop.default);
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
2615
3807
|
if (links) {
|
|
2616
3808
|
linkType(links, type, mapper);
|
|
2617
3809
|
}
|
|
@@ -2641,43 +3833,42 @@ export function createChecker(program) {
|
|
|
2641
3833
|
],
|
|
2642
3834
|
};
|
|
2643
3835
|
}
|
|
2644
|
-
function
|
|
2645
|
-
if (type === nullType) {
|
|
2646
|
-
return true;
|
|
2647
|
-
}
|
|
2648
|
-
if (type.kind === "StringTemplate") {
|
|
2649
|
-
const [valid] = isStringTemplateSerializable(type);
|
|
2650
|
-
return valid;
|
|
2651
|
-
}
|
|
2652
|
-
if (type.kind === "UnionVariant") {
|
|
2653
|
-
return isValueType(type.type);
|
|
2654
|
-
}
|
|
2655
|
-
const valueTypes = new Set(["String", "Number", "Boolean", "EnumMember", "Tuple"]);
|
|
2656
|
-
return valueTypes.has(type.kind);
|
|
2657
|
-
}
|
|
2658
|
-
function checkDefault(defaultNode, type) {
|
|
2659
|
-
const defaultType = getTypeForNode(defaultNode, undefined);
|
|
3836
|
+
function checkDefaultValue(defaultNode, type) {
|
|
2660
3837
|
if (isErrorType(type)) {
|
|
2661
|
-
|
|
3838
|
+
// if the prop type is an error we don't need to validate again.
|
|
3839
|
+
return null;
|
|
2662
3840
|
}
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
return errorType;
|
|
3841
|
+
const defaultValue = getValueForNode(defaultNode, undefined, {
|
|
3842
|
+
kind: "assignment",
|
|
3843
|
+
type,
|
|
3844
|
+
}, { legacyTupleAndModelCast: true });
|
|
3845
|
+
if (defaultValue === null) {
|
|
3846
|
+
return null;
|
|
2670
3847
|
}
|
|
2671
|
-
const [related, diagnostics] =
|
|
3848
|
+
const [related, diagnostics] = isValueOfType(defaultValue, type, defaultNode);
|
|
2672
3849
|
if (!related) {
|
|
2673
3850
|
reportCheckerDiagnostics(diagnostics);
|
|
2674
|
-
return
|
|
3851
|
+
return null;
|
|
2675
3852
|
}
|
|
2676
3853
|
else {
|
|
2677
|
-
return
|
|
3854
|
+
return { ...defaultValue, type };
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
/**
|
|
3858
|
+
* Fill in the legacy `.default` property.
|
|
3859
|
+
* We do do checking here we just keep existing behavior.
|
|
3860
|
+
*/
|
|
3861
|
+
function checkLegacyDefault(defaultNode) {
|
|
3862
|
+
const resolved = checkNode(defaultNode, undefined);
|
|
3863
|
+
if (resolved === null || isValue(resolved)) {
|
|
3864
|
+
return undefined;
|
|
2678
3865
|
}
|
|
3866
|
+
if (resolved.entityKind === "Indeterminate") {
|
|
3867
|
+
return resolved.type;
|
|
3868
|
+
}
|
|
3869
|
+
return resolved;
|
|
2679
3870
|
}
|
|
2680
|
-
function
|
|
3871
|
+
function checkDecoratorApplication(targetType, decNode, mapper) {
|
|
2681
3872
|
const sym = resolveTypeReferenceSym(decNode.target, undefined, true);
|
|
2682
3873
|
if (!sym) {
|
|
2683
3874
|
reportCheckerDiagnostic(createDiagnostic({
|
|
@@ -2695,7 +3886,6 @@ export function createChecker(program) {
|
|
|
2695
3886
|
return undefined;
|
|
2696
3887
|
}
|
|
2697
3888
|
const symbolLinks = getSymbolLinks(sym);
|
|
2698
|
-
let args = checkDecoratorArguments(decNode, mapper);
|
|
2699
3889
|
let hasError = false;
|
|
2700
3890
|
if (symbolLinks.declaredType === undefined) {
|
|
2701
3891
|
const decoratorDeclNode = sym.declarations.find((x) => x.kind === SyntaxKind.DecoratorDeclarationStatement);
|
|
@@ -2705,10 +3895,12 @@ export function createChecker(program) {
|
|
|
2705
3895
|
}
|
|
2706
3896
|
if (symbolLinks.declaredType) {
|
|
2707
3897
|
compilerAssert(symbolLinks.declaredType.kind === "Decorator", "Expected to find a decorator type.");
|
|
2708
|
-
|
|
2709
|
-
|
|
3898
|
+
if (!checkDecoratorTarget(targetType, symbolLinks.declaredType, decNode)) {
|
|
3899
|
+
hasError = true;
|
|
3900
|
+
}
|
|
2710
3901
|
}
|
|
2711
|
-
|
|
3902
|
+
const [argsHaveError, args] = checkDecoratorArguments(decNode, mapper, symbolLinks.declaredType);
|
|
3903
|
+
if (hasError || argsHaveError) {
|
|
2712
3904
|
return undefined;
|
|
2713
3905
|
}
|
|
2714
3906
|
return {
|
|
@@ -2718,62 +3910,121 @@ export function createChecker(program) {
|
|
|
2718
3910
|
args,
|
|
2719
3911
|
};
|
|
2720
3912
|
}
|
|
2721
|
-
function
|
|
2722
|
-
|
|
3913
|
+
function resolveDecoratorArgMarshalling(declaredType) {
|
|
3914
|
+
if (declaredType) {
|
|
3915
|
+
const location = getLocationContext(program, declaredType);
|
|
3916
|
+
if (location.type === "compiler") {
|
|
3917
|
+
return "new";
|
|
3918
|
+
}
|
|
3919
|
+
else if ((location.type === "library" || location.type === "project") &&
|
|
3920
|
+
location.flags?.decoratorArgMarshalling) {
|
|
3921
|
+
return location.flags.decoratorArgMarshalling;
|
|
3922
|
+
}
|
|
3923
|
+
else {
|
|
3924
|
+
return "legacy";
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
return "new";
|
|
3928
|
+
}
|
|
3929
|
+
/** Check the decorator target is valid */
|
|
3930
|
+
function checkDecoratorTarget(targetType, declaration, decoratorNode) {
|
|
2723
3931
|
const [targetValid] = isTypeAssignableTo(targetType, declaration.target.type, decoratorNode);
|
|
2724
3932
|
if (!targetValid) {
|
|
2725
|
-
hasError = true;
|
|
2726
3933
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2727
3934
|
code: "decorator-wrong-target",
|
|
2728
3935
|
messageId: "withExpected",
|
|
2729
3936
|
format: {
|
|
2730
3937
|
decorator: declaration.name,
|
|
2731
3938
|
to: getTypeName(targetType),
|
|
2732
|
-
expected:
|
|
3939
|
+
expected: getEntityName(declaration.target.type),
|
|
2733
3940
|
},
|
|
2734
3941
|
target: decoratorNode,
|
|
2735
3942
|
}));
|
|
2736
3943
|
}
|
|
2737
|
-
|
|
3944
|
+
return targetValid;
|
|
3945
|
+
}
|
|
3946
|
+
function checkDecoratorArguments(node, mapper, declaration) {
|
|
3947
|
+
// if we don't have a declaration we can just return the types or values if
|
|
3948
|
+
if (declaration === undefined) {
|
|
3949
|
+
return [
|
|
3950
|
+
false,
|
|
3951
|
+
node.arguments.map((argNode) => {
|
|
3952
|
+
let type = checkNode(argNode, mapper) ?? errorType;
|
|
3953
|
+
if (type.entityKind === "Indeterminate") {
|
|
3954
|
+
type = type.type;
|
|
3955
|
+
}
|
|
3956
|
+
return {
|
|
3957
|
+
value: type,
|
|
3958
|
+
jsValue: type,
|
|
3959
|
+
node: argNode,
|
|
3960
|
+
};
|
|
3961
|
+
}),
|
|
3962
|
+
];
|
|
3963
|
+
}
|
|
3964
|
+
let hasError = false;
|
|
3965
|
+
const minArgs = declaration.parameters.filter((x) => !x.optional && !x.rest).length ?? 0;
|
|
2738
3966
|
const maxArgs = declaration.parameters[declaration.parameters.length - 1]?.rest
|
|
2739
3967
|
? undefined
|
|
2740
3968
|
: declaration.parameters.length;
|
|
2741
|
-
if (
|
|
3969
|
+
if (node.arguments.length < minArgs ||
|
|
3970
|
+
(maxArgs !== undefined && node.arguments.length > maxArgs)) {
|
|
2742
3971
|
// In the case we have too little args then this decorator is not applicable.
|
|
2743
3972
|
// If there is too many args then we can still run the decorator as long as the args are valid.
|
|
2744
|
-
if (
|
|
3973
|
+
if (node.arguments.length < minArgs) {
|
|
2745
3974
|
hasError = true;
|
|
2746
3975
|
}
|
|
2747
3976
|
if (maxArgs === undefined) {
|
|
2748
3977
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2749
3978
|
code: "invalid-argument-count",
|
|
2750
3979
|
messageId: "atLeast",
|
|
2751
|
-
format: { actual:
|
|
2752
|
-
target:
|
|
3980
|
+
format: { actual: node.arguments.length.toString(), expected: minArgs.toString() },
|
|
3981
|
+
target: node,
|
|
2753
3982
|
}));
|
|
2754
3983
|
}
|
|
2755
3984
|
else {
|
|
2756
3985
|
const expected = minArgs === maxArgs ? minArgs.toString() : `${minArgs}-${maxArgs}`;
|
|
2757
3986
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2758
3987
|
code: "invalid-argument-count",
|
|
2759
|
-
format: { actual:
|
|
2760
|
-
target:
|
|
3988
|
+
format: { actual: node.arguments.length.toString(), expected },
|
|
3989
|
+
target: node,
|
|
2761
3990
|
}));
|
|
2762
3991
|
}
|
|
2763
3992
|
}
|
|
2764
3993
|
const resolvedArgs = [];
|
|
3994
|
+
const jsMarshalling = resolveDecoratorArgMarshalling(declaration);
|
|
3995
|
+
function resolveArg(argNode, perParamType) {
|
|
3996
|
+
const arg = getTypeOrValueForNode(argNode, mapper, {
|
|
3997
|
+
kind: "argument",
|
|
3998
|
+
constraint: perParamType,
|
|
3999
|
+
});
|
|
4000
|
+
if (arg !== null &&
|
|
4001
|
+
!(isType(arg) && isErrorType(arg)) &&
|
|
4002
|
+
checkArgumentAssignable(arg, perParamType, argNode)) {
|
|
4003
|
+
return {
|
|
4004
|
+
value: arg,
|
|
4005
|
+
node: argNode,
|
|
4006
|
+
jsValue: resolveDecoratorArgJsValue(arg, extractValueOfConstraints({
|
|
4007
|
+
kind: "argument",
|
|
4008
|
+
constraint: perParamType,
|
|
4009
|
+
}), jsMarshalling),
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
else {
|
|
4013
|
+
return undefined;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
2765
4016
|
for (const [index, parameter] of declaration.parameters.entries()) {
|
|
2766
4017
|
if (parameter.rest) {
|
|
2767
|
-
const restType =
|
|
4018
|
+
const restType = extractRestParamConstraint(parameter.type);
|
|
2768
4019
|
if (restType) {
|
|
2769
|
-
for (let i = index; i <
|
|
2770
|
-
const
|
|
2771
|
-
if (
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
}
|
|
2776
|
-
|
|
4020
|
+
for (let i = index; i < node.arguments.length; i++) {
|
|
4021
|
+
const argNode = node.arguments[i];
|
|
4022
|
+
if (argNode) {
|
|
4023
|
+
const arg = resolveArg(argNode, restType);
|
|
4024
|
+
if (arg) {
|
|
4025
|
+
resolvedArgs.push(arg);
|
|
4026
|
+
}
|
|
4027
|
+
else {
|
|
2777
4028
|
hasError = true;
|
|
2778
4029
|
}
|
|
2779
4030
|
}
|
|
@@ -2781,29 +4032,58 @@ export function createChecker(program) {
|
|
|
2781
4032
|
}
|
|
2782
4033
|
break;
|
|
2783
4034
|
}
|
|
2784
|
-
const
|
|
2785
|
-
if (
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
}
|
|
2790
|
-
|
|
4035
|
+
const argNode = node.arguments[index];
|
|
4036
|
+
if (argNode) {
|
|
4037
|
+
const arg = resolveArg(argNode, parameter.type);
|
|
4038
|
+
if (arg) {
|
|
4039
|
+
resolvedArgs.push(arg);
|
|
4040
|
+
}
|
|
4041
|
+
else {
|
|
2791
4042
|
hasError = true;
|
|
2792
4043
|
}
|
|
2793
4044
|
}
|
|
2794
4045
|
}
|
|
2795
4046
|
return [hasError, resolvedArgs];
|
|
2796
4047
|
}
|
|
4048
|
+
/** For a rest param of constraint T[] or valueof T[] return the T or valueof T */
|
|
4049
|
+
function extractRestParamConstraint(constraint) {
|
|
4050
|
+
let valueType;
|
|
4051
|
+
let type;
|
|
4052
|
+
if (constraint.valueType) {
|
|
4053
|
+
if (constraint.valueType.kind === "Model" &&
|
|
4054
|
+
isArrayModelType(program, constraint.valueType)) {
|
|
4055
|
+
valueType = constraint.valueType.indexer.value;
|
|
4056
|
+
}
|
|
4057
|
+
else {
|
|
4058
|
+
return undefined;
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
if (constraint.type) {
|
|
4062
|
+
if (constraint.type.kind === "Model" && isArrayModelType(program, constraint.type)) {
|
|
4063
|
+
type = constraint.type.indexer.value;
|
|
4064
|
+
}
|
|
4065
|
+
else {
|
|
4066
|
+
return undefined;
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
return {
|
|
4070
|
+
entityKind: "MixedParameterConstraint",
|
|
4071
|
+
type,
|
|
4072
|
+
valueType,
|
|
4073
|
+
};
|
|
4074
|
+
}
|
|
2797
4075
|
function getIndexType(type) {
|
|
2798
4076
|
return type.kind === "Model" ? type.indexer?.value : undefined;
|
|
2799
4077
|
}
|
|
2800
|
-
function resolveDecoratorArgJsValue(value,
|
|
2801
|
-
if (
|
|
2802
|
-
if (value
|
|
2803
|
-
return
|
|
4078
|
+
function resolveDecoratorArgJsValue(value, valueConstraint, jsMarshalling) {
|
|
4079
|
+
if (valueConstraint !== undefined) {
|
|
4080
|
+
if (isValue(value)) {
|
|
4081
|
+
return jsMarshalling === "legacy"
|
|
4082
|
+
? legacyMarshallTypeForJS(checker, value)
|
|
4083
|
+
: marshallTypeForJS(value, valueConstraint.type);
|
|
2804
4084
|
}
|
|
2805
|
-
else
|
|
2806
|
-
return
|
|
4085
|
+
else {
|
|
4086
|
+
return value;
|
|
2807
4087
|
}
|
|
2808
4088
|
}
|
|
2809
4089
|
return value;
|
|
@@ -2814,8 +4094,8 @@ export function createChecker(program) {
|
|
|
2814
4094
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2815
4095
|
code: "invalid-argument",
|
|
2816
4096
|
format: {
|
|
2817
|
-
value:
|
|
2818
|
-
expected:
|
|
4097
|
+
value: getEntityName(argumentType),
|
|
4098
|
+
expected: getEntityName(parameterType),
|
|
2819
4099
|
},
|
|
2820
4100
|
target: diagnosticTarget,
|
|
2821
4101
|
}));
|
|
@@ -2826,7 +4106,7 @@ export function createChecker(program) {
|
|
|
2826
4106
|
const augmentDecoratorNodes = augmentDecoratorsForSym.get(sym) ?? [];
|
|
2827
4107
|
const decorators = [];
|
|
2828
4108
|
for (const decNode of augmentDecoratorNodes) {
|
|
2829
|
-
const decorator =
|
|
4109
|
+
const decorator = checkDecoratorApplication(targetType, decNode, mapper);
|
|
2830
4110
|
if (decorator) {
|
|
2831
4111
|
decorators.unshift(decorator);
|
|
2832
4112
|
}
|
|
@@ -2842,7 +4122,7 @@ export function createChecker(program) {
|
|
|
2842
4122
|
...node.decorators,
|
|
2843
4123
|
];
|
|
2844
4124
|
for (const decNode of decoratorNodes) {
|
|
2845
|
-
const decorator =
|
|
4125
|
+
const decorator = checkDecoratorApplication(targetType, decNode, mapper);
|
|
2846
4126
|
if (decorator) {
|
|
2847
4127
|
decorators.unshift(decorator);
|
|
2848
4128
|
}
|
|
@@ -2863,16 +4143,6 @@ export function createChecker(program) {
|
|
|
2863
4143
|
}
|
|
2864
4144
|
return decorators;
|
|
2865
4145
|
}
|
|
2866
|
-
function checkDecoratorArguments(decorator, mapper) {
|
|
2867
|
-
return decorator.arguments.map((argNode) => {
|
|
2868
|
-
const type = getTypeForNode(argNode, mapper);
|
|
2869
|
-
return {
|
|
2870
|
-
value: type,
|
|
2871
|
-
jsValue: type,
|
|
2872
|
-
node: argNode,
|
|
2873
|
-
};
|
|
2874
|
-
});
|
|
2875
|
-
}
|
|
2876
4146
|
function checkScalar(node, mapper) {
|
|
2877
4147
|
const links = getSymbolLinks(node.symbol);
|
|
2878
4148
|
if (links.declaredType && mapper === undefined) {
|
|
@@ -2885,10 +4155,12 @@ export function createChecker(program) {
|
|
|
2885
4155
|
kind: "Scalar",
|
|
2886
4156
|
name: node.id.sv,
|
|
2887
4157
|
node: node,
|
|
4158
|
+
constructors: new Map(),
|
|
2888
4159
|
namespace: getParentNamespaceType(node),
|
|
2889
4160
|
decorators,
|
|
2890
4161
|
derivedScalars: [],
|
|
2891
4162
|
});
|
|
4163
|
+
checkScalarConstructors(type, node, type.constructors, mapper);
|
|
2892
4164
|
linkType(links, type, mapper);
|
|
2893
4165
|
if (node.extends) {
|
|
2894
4166
|
type.baseScalar = checkScalarExtends(node, node.extends, mapper);
|
|
@@ -2939,6 +4211,43 @@ export function createChecker(program) {
|
|
|
2939
4211
|
}
|
|
2940
4212
|
return extendsType;
|
|
2941
4213
|
}
|
|
4214
|
+
function checkScalarConstructors(parentScalar, node, constructors, mapper) {
|
|
4215
|
+
for (const member of node.members) {
|
|
4216
|
+
const constructor = checkScalarConstructor(member, mapper, parentScalar);
|
|
4217
|
+
if (constructors.has(constructor.name)) {
|
|
4218
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
4219
|
+
code: "constructor-duplicate",
|
|
4220
|
+
format: { name: constructor.name.toString() },
|
|
4221
|
+
target: member,
|
|
4222
|
+
}));
|
|
4223
|
+
continue;
|
|
4224
|
+
}
|
|
4225
|
+
constructors.set(constructor.name, constructor);
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
function checkScalarConstructor(node, mapper, parentScalar) {
|
|
4229
|
+
const name = node.id.sv;
|
|
4230
|
+
const links = getSymbolLinksForMember(node);
|
|
4231
|
+
if (links && links.declaredType && mapper === undefined) {
|
|
4232
|
+
// we're not instantiating this scalar constructor and we've already checked it
|
|
4233
|
+
return links.declaredType;
|
|
4234
|
+
}
|
|
4235
|
+
const member = createType({
|
|
4236
|
+
kind: "ScalarConstructor",
|
|
4237
|
+
scalar: parentScalar,
|
|
4238
|
+
name,
|
|
4239
|
+
node,
|
|
4240
|
+
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, false)),
|
|
4241
|
+
});
|
|
4242
|
+
linkMapper(member, mapper);
|
|
4243
|
+
if (shouldCreateTypeForTemplate(node.parent, mapper)) {
|
|
4244
|
+
finishType(member);
|
|
4245
|
+
}
|
|
4246
|
+
if (links) {
|
|
4247
|
+
linkType(links, member, mapper);
|
|
4248
|
+
}
|
|
4249
|
+
return finishType(member);
|
|
4250
|
+
}
|
|
2942
4251
|
function checkAlias(node, mapper) {
|
|
2943
4252
|
const links = getSymbolLinks(node.symbol);
|
|
2944
4253
|
if (links.declaredType && mapper === undefined) {
|
|
@@ -2958,11 +4267,63 @@ export function createChecker(program) {
|
|
|
2958
4267
|
return errorType;
|
|
2959
4268
|
}
|
|
2960
4269
|
pendingResolutions.start(aliasSymId, ResolutionKind.Type);
|
|
2961
|
-
const type =
|
|
4270
|
+
const type = checkNode(node.value, mapper);
|
|
4271
|
+
if (type === null) {
|
|
4272
|
+
links.declaredType = errorType;
|
|
4273
|
+
return errorType;
|
|
4274
|
+
}
|
|
4275
|
+
if (isValue(type)) {
|
|
4276
|
+
reportCheckerDiagnostic(createDiagnostic({ code: "value-in-type", target: node.value }));
|
|
4277
|
+
links.declaredType = errorType;
|
|
4278
|
+
return errorType;
|
|
4279
|
+
}
|
|
2962
4280
|
linkType(links, type, mapper);
|
|
2963
4281
|
pendingResolutions.finish(aliasSymId, ResolutionKind.Type);
|
|
2964
4282
|
return type;
|
|
2965
4283
|
}
|
|
4284
|
+
function checkConst(node) {
|
|
4285
|
+
const links = getSymbolLinks(node.symbol);
|
|
4286
|
+
if (links.value !== undefined) {
|
|
4287
|
+
return links.value;
|
|
4288
|
+
}
|
|
4289
|
+
const type = node.type ? getTypeForNode(node.type, undefined) : undefined;
|
|
4290
|
+
const symId = getSymbolId(node.symbol);
|
|
4291
|
+
if (pendingResolutions.has(symId, ResolutionKind.Value)) {
|
|
4292
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
4293
|
+
code: "circular-const",
|
|
4294
|
+
format: { name: node.id.sv },
|
|
4295
|
+
target: node,
|
|
4296
|
+
}));
|
|
4297
|
+
return null;
|
|
4298
|
+
}
|
|
4299
|
+
pendingResolutions.start(symId, ResolutionKind.Value);
|
|
4300
|
+
const value = getValueForNode(node.value, undefined, type && { kind: "assignment", type });
|
|
4301
|
+
pendingResolutions.finish(symId, ResolutionKind.Value);
|
|
4302
|
+
if (value === null || (type && !checkValueOfType(value, type, node.id))) {
|
|
4303
|
+
links.value = null;
|
|
4304
|
+
return links.value;
|
|
4305
|
+
}
|
|
4306
|
+
links.value = type ? { ...value, type } : { ...value };
|
|
4307
|
+
return links.value;
|
|
4308
|
+
}
|
|
4309
|
+
function inferScalarsFromConstraints(value, type) {
|
|
4310
|
+
switch (value.valueKind) {
|
|
4311
|
+
case "BooleanValue":
|
|
4312
|
+
case "StringValue":
|
|
4313
|
+
case "NumericValue":
|
|
4314
|
+
if (value.scalar === undefined) {
|
|
4315
|
+
const scalar = inferScalarForPrimitiveValue(type, value.type);
|
|
4316
|
+
return { ...value, scalar };
|
|
4317
|
+
}
|
|
4318
|
+
return value;
|
|
4319
|
+
case "ArrayValue":
|
|
4320
|
+
case "ObjectValue":
|
|
4321
|
+
case "EnumValue":
|
|
4322
|
+
case "NullValue":
|
|
4323
|
+
case "ScalarValue":
|
|
4324
|
+
return value;
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
2966
4327
|
function checkEnum(node, mapper) {
|
|
2967
4328
|
const links = getSymbolLinks(node.symbol);
|
|
2968
4329
|
if (!links.type) {
|
|
@@ -3279,6 +4640,7 @@ export function createChecker(program) {
|
|
|
3279
4640
|
// If the type has an associated syntax node, check any directives that
|
|
3280
4641
|
// might be attached.
|
|
3281
4642
|
const createdType = typeDef;
|
|
4643
|
+
createdType.entityKind = "Type";
|
|
3282
4644
|
if (createdType.node) {
|
|
3283
4645
|
checkDirectives(createdType.node, createdType);
|
|
3284
4646
|
}
|
|
@@ -4024,6 +5386,7 @@ export function createChecker(program) {
|
|
|
4024
5386
|
kind: "Number",
|
|
4025
5387
|
value,
|
|
4026
5388
|
valueAsString,
|
|
5389
|
+
numericValue: Numeric(valueAsString),
|
|
4027
5390
|
});
|
|
4028
5391
|
break;
|
|
4029
5392
|
}
|
|
@@ -4036,7 +5399,7 @@ export function createChecker(program) {
|
|
|
4036
5399
|
throw new ProjectionError("Can't find decorator.");
|
|
4037
5400
|
compilerAssert(ref.flags & 16384 /* SymbolFlags.Decorator */, "should only resolve decorator symbols");
|
|
4038
5401
|
return createFunctionType((...args) => {
|
|
4039
|
-
ref.value({ program }, ...
|
|
5402
|
+
ref.value({ program }, ...args.map(unsafe_projectionArgumentMarshalForJS));
|
|
4040
5403
|
return voidType;
|
|
4041
5404
|
});
|
|
4042
5405
|
}
|
|
@@ -4061,7 +5424,7 @@ export function createChecker(program) {
|
|
|
4061
5424
|
else if (ref.flags & 131072 /* SymbolFlags.Function */) {
|
|
4062
5425
|
// TODO: store this in a symbol link probably?
|
|
4063
5426
|
const t = createFunctionType((...args) => {
|
|
4064
|
-
const retval = ref.value(program, ...
|
|
5427
|
+
const retval = ref.value(program, ...args.map(unsafe_projectionArgumentMarshalForJS));
|
|
4065
5428
|
return marshalProjectionReturn(retval, { functionName: node.sv });
|
|
4066
5429
|
});
|
|
4067
5430
|
return t;
|
|
@@ -4135,6 +5498,31 @@ export function createChecker(program) {
|
|
|
4135
5498
|
parts.push(current.sv);
|
|
4136
5499
|
return parts.reverse().join(".");
|
|
4137
5500
|
}
|
|
5501
|
+
/**
|
|
5502
|
+
* Check if the source type can be assigned to the target type and emit diagnostics
|
|
5503
|
+
* @param source Type of a value
|
|
5504
|
+
* @param constraint
|
|
5505
|
+
* @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
|
|
5506
|
+
*/
|
|
5507
|
+
function checkTypeOfValueMatchConstraint(source, constraint, diagnosticTarget) {
|
|
5508
|
+
const [related, diagnostics] = isTypeAssignableTo(source, constraint.type, diagnosticTarget);
|
|
5509
|
+
if (!related) {
|
|
5510
|
+
if (constraint.kind === "argument") {
|
|
5511
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
5512
|
+
code: "invalid-argument",
|
|
5513
|
+
format: {
|
|
5514
|
+
value: getEntityName(source),
|
|
5515
|
+
expected: getEntityName(constraint.type),
|
|
5516
|
+
},
|
|
5517
|
+
target: diagnosticTarget,
|
|
5518
|
+
}));
|
|
5519
|
+
}
|
|
5520
|
+
else {
|
|
5521
|
+
reportCheckerDiagnostics(diagnostics);
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
return related;
|
|
5525
|
+
}
|
|
4138
5526
|
/**
|
|
4139
5527
|
* Check if the source type can be assigned to the target type and emit diagnostics
|
|
4140
5528
|
* @param source Source type
|
|
@@ -4148,6 +5536,13 @@ export function createChecker(program) {
|
|
|
4148
5536
|
}
|
|
4149
5537
|
return related;
|
|
4150
5538
|
}
|
|
5539
|
+
function checkValueOfType(source, target, diagnosticTarget) {
|
|
5540
|
+
const [related, diagnostics] = isValueOfType(source, target, diagnosticTarget);
|
|
5541
|
+
if (!related) {
|
|
5542
|
+
reportCheckerDiagnostics(diagnostics);
|
|
5543
|
+
}
|
|
5544
|
+
return related;
|
|
5545
|
+
}
|
|
4151
5546
|
/**
|
|
4152
5547
|
* Check if the source type can be assigned to the target type.
|
|
4153
5548
|
* @param source Source type
|
|
@@ -4158,6 +5553,16 @@ export function createChecker(program) {
|
|
|
4158
5553
|
const [related, diagnostics] = isTypeAssignableToInternal(source, target, diagnosticTarget, new MultiKeyMap());
|
|
4159
5554
|
return [related === Related.true, diagnostics];
|
|
4160
5555
|
}
|
|
5556
|
+
/**
|
|
5557
|
+
* Check if the given Value type is of the given type.
|
|
5558
|
+
* @param source Value
|
|
5559
|
+
* @param target Target type
|
|
5560
|
+
* @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
|
|
5561
|
+
*/
|
|
5562
|
+
function isValueOfType(source, target, diagnosticTarget) {
|
|
5563
|
+
const [related, diagnostics] = isValueOfTypeInternal(source, target, diagnosticTarget, new MultiKeyMap());
|
|
5564
|
+
return [related === Related.true, diagnostics];
|
|
5565
|
+
}
|
|
4161
5566
|
function isTypeAssignableToInternal(source, target, diagnosticTarget, relationCache) {
|
|
4162
5567
|
const cached = relationCache.get([source, target]);
|
|
4163
5568
|
if (cached !== undefined) {
|
|
@@ -4168,26 +5573,44 @@ export function createChecker(program) {
|
|
|
4168
5573
|
return [result, diagnostics];
|
|
4169
5574
|
}
|
|
4170
5575
|
function isTypeAssignableToWorker(source, target, diagnosticTarget, relationCache) {
|
|
4171
|
-
// BACKCOMPAT:
|
|
4172
|
-
if (
|
|
4173
|
-
|
|
5576
|
+
// BACKCOMPAT: Allow certain type to be accepted as values
|
|
5577
|
+
if ("kind" in source &&
|
|
5578
|
+
"entityKind" in target &&
|
|
5579
|
+
source.kind === "TemplateParameter" &&
|
|
5580
|
+
source.constraint?.type &&
|
|
5581
|
+
source.constraint.valueType === undefined &&
|
|
5582
|
+
target.entityKind === "MixedParameterConstraint" &&
|
|
5583
|
+
target.valueType) {
|
|
5584
|
+
const [assignable] = isTypeAssignableToInternal(source.constraint.type, target.valueType, diagnosticTarget, relationCache);
|
|
4174
5585
|
if (assignable) {
|
|
4175
|
-
const constraint =
|
|
4176
|
-
reportDeprecated(program, `Template constrainted to '${constraint}' will not be assignable to '${
|
|
5586
|
+
const constraint = getEntityName(source.constraint);
|
|
5587
|
+
reportDeprecated(program, `Template constrainted to '${constraint}' will not be assignable to '${getEntityName(target)}' in the future. Update the constraint to be 'valueof ${constraint}'`, diagnosticTarget);
|
|
4177
5588
|
return [Related.true, []];
|
|
4178
5589
|
}
|
|
4179
5590
|
}
|
|
4180
|
-
|
|
5591
|
+
if ("kind" in source && source.kind === "TemplateParameter") {
|
|
4181
5592
|
source = source.constraint ?? unknownType;
|
|
4182
5593
|
}
|
|
5594
|
+
if (target.entityKind === "Indeterminate") {
|
|
5595
|
+
target = target.type;
|
|
5596
|
+
}
|
|
4183
5597
|
if (source === target)
|
|
4184
5598
|
return [Related.true, []];
|
|
4185
|
-
if (target
|
|
4186
|
-
return
|
|
5599
|
+
if (isValue(target)) {
|
|
5600
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5601
|
+
}
|
|
5602
|
+
if (source.entityKind === "Indeterminate") {
|
|
5603
|
+
return isIndeterminateEntityAssignableTo(source, target, diagnosticTarget, relationCache);
|
|
4187
5604
|
}
|
|
4188
|
-
if (
|
|
5605
|
+
if (target.entityKind === "MixedParameterConstraint") {
|
|
5606
|
+
return isAssignableToMixedParameterConstraint(source, target, diagnosticTarget, relationCache);
|
|
5607
|
+
}
|
|
5608
|
+
if (isValue(source) || (source.entityKind === "MixedParameterConstraint" && source.valueType)) {
|
|
4189
5609
|
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
4190
5610
|
}
|
|
5611
|
+
if (source.entityKind === "MixedParameterConstraint") {
|
|
5612
|
+
return isTypeAssignableToInternal(source.type, target, diagnosticTarget, relationCache);
|
|
5613
|
+
}
|
|
4191
5614
|
const isSimpleTypeRelated = isSimpleTypeAssignableTo(source, target);
|
|
4192
5615
|
if (isSimpleTypeRelated === true) {
|
|
4193
5616
|
return [Related.true, []];
|
|
@@ -4227,19 +5650,21 @@ export function createChecker(program) {
|
|
|
4227
5650
|
else if (target.kind === "Model" &&
|
|
4228
5651
|
isArrayModelType(program, target) &&
|
|
4229
5652
|
source.kind === "Model") {
|
|
4230
|
-
|
|
5653
|
+
if (isArrayModelType(program, source)) {
|
|
5654
|
+
return hasIndexAndIsAssignableTo(source, target, diagnosticTarget, relationCache);
|
|
5655
|
+
}
|
|
5656
|
+
else {
|
|
5657
|
+
// For other models just fallback to unassignable
|
|
5658
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5659
|
+
}
|
|
4231
5660
|
}
|
|
4232
5661
|
else if (target.kind === "Model" && source.kind === "Model") {
|
|
4233
5662
|
return isModelRelatedTo(source, target, diagnosticTarget, relationCache);
|
|
4234
5663
|
}
|
|
4235
|
-
else if (target.kind === "Model" &&
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
return [Related.false, diagnostics];
|
|
4240
|
-
}
|
|
4241
|
-
}
|
|
4242
|
-
return [Related.true, []];
|
|
5664
|
+
else if (target.kind === "Model" &&
|
|
5665
|
+
isArrayModelType(program, target) &&
|
|
5666
|
+
source.kind === "Tuple") {
|
|
5667
|
+
return isTupleAssignableToArray(source, target, diagnosticTarget, relationCache);
|
|
4243
5668
|
}
|
|
4244
5669
|
else if (target.kind === "Tuple" && source.kind === "Tuple") {
|
|
4245
5670
|
return isTupleAssignableToTuple(source, target, diagnosticTarget, relationCache);
|
|
@@ -4252,18 +5677,60 @@ export function createChecker(program) {
|
|
|
4252
5677
|
}
|
|
4253
5678
|
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
4254
5679
|
}
|
|
4255
|
-
function
|
|
4256
|
-
|
|
4257
|
-
|
|
5680
|
+
function isIndeterminateEntityAssignableTo(indeterminate, target, diagnosticTarget, relationCache) {
|
|
5681
|
+
const [typeRelated, typeDiagnostics] = isTypeAssignableToInternal(indeterminate.type, target, diagnosticTarget, relationCache);
|
|
5682
|
+
if (typeRelated) {
|
|
5683
|
+
return [Related.true, []];
|
|
4258
5684
|
}
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
5685
|
+
if (target.entityKind === "MixedParameterConstraint" && target.valueType) {
|
|
5686
|
+
const [valueRelated] = isTypeAssignableToInternal(indeterminate.type, target.valueType, diagnosticTarget, relationCache);
|
|
5687
|
+
if (valueRelated) {
|
|
5688
|
+
return [Related.true, []];
|
|
5689
|
+
}
|
|
4262
5690
|
}
|
|
4263
|
-
|
|
5691
|
+
return [Related.false, typeDiagnostics];
|
|
5692
|
+
}
|
|
5693
|
+
function isAssignableToValueType(source, target, diagnosticTarget, relationCache) {
|
|
5694
|
+
if (!isValue(source)) {
|
|
4264
5695
|
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
4265
5696
|
}
|
|
4266
|
-
return
|
|
5697
|
+
return isValueOfTypeInternal(source, target, diagnosticTarget, relationCache);
|
|
5698
|
+
}
|
|
5699
|
+
function isAssignableToMixedParameterConstraint(source, target, diagnosticTarget, relationCache) {
|
|
5700
|
+
if ("entityKind" in source && source.entityKind === "MixedParameterConstraint") {
|
|
5701
|
+
if (source.type && target.type) {
|
|
5702
|
+
const [variantAssignable, diagnostics] = isTypeAssignableToInternal(source.type, target.type, diagnosticTarget, relationCache);
|
|
5703
|
+
if (variantAssignable === Related.false) {
|
|
5704
|
+
return [Related.false, diagnostics];
|
|
5705
|
+
}
|
|
5706
|
+
return [Related.true, []];
|
|
5707
|
+
}
|
|
5708
|
+
if (source.valueType && target.valueType) {
|
|
5709
|
+
const [variantAssignable, diagnostics] = isTypeAssignableToInternal(source.valueType, target.valueType, diagnosticTarget, relationCache);
|
|
5710
|
+
if (variantAssignable === Related.false) {
|
|
5711
|
+
return [Related.false, diagnostics];
|
|
5712
|
+
}
|
|
5713
|
+
return [Related.true, []];
|
|
5714
|
+
}
|
|
5715
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5716
|
+
}
|
|
5717
|
+
if (target.type) {
|
|
5718
|
+
const [related] = isTypeAssignableToInternal(source, target.type, diagnosticTarget, relationCache);
|
|
5719
|
+
if (related) {
|
|
5720
|
+
return [Related.true, []];
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
if (target.valueType) {
|
|
5724
|
+
const [related] = isAssignableToValueType(source, target.valueType, diagnosticTarget, relationCache);
|
|
5725
|
+
if (related) {
|
|
5726
|
+
return [Related.true, []];
|
|
5727
|
+
}
|
|
5728
|
+
}
|
|
5729
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5730
|
+
}
|
|
5731
|
+
/** Check if the value is assignable to the given type. */
|
|
5732
|
+
function isValueOfTypeInternal(source, target, diagnosticTarget, relationCache) {
|
|
5733
|
+
return isTypeAssignableToInternal(source.type, target, diagnosticTarget, relationCache);
|
|
4267
5734
|
}
|
|
4268
5735
|
function isReflectionType(type) {
|
|
4269
5736
|
return (type.kind === "Model" &&
|
|
@@ -4276,7 +5743,7 @@ export function createChecker(program) {
|
|
|
4276
5743
|
return isNumericLiteralRelatedTo(source, target);
|
|
4277
5744
|
case "String":
|
|
4278
5745
|
case "StringTemplate":
|
|
4279
|
-
return
|
|
5746
|
+
return isStringLiteralRelatedTo(source, target);
|
|
4280
5747
|
case "Boolean":
|
|
4281
5748
|
return areScalarsRelated(target, getStdType("boolean"));
|
|
4282
5749
|
case "Scalar":
|
|
@@ -4314,7 +5781,12 @@ export function createChecker(program) {
|
|
|
4314
5781
|
return false;
|
|
4315
5782
|
}
|
|
4316
5783
|
if (target.kind === "String") {
|
|
4317
|
-
return source.kind === "String" &&
|
|
5784
|
+
return ((source.kind === "String" && source.value === target.value) ||
|
|
5785
|
+
(source.kind === "StringTemplate" && source.stringValue === target.value));
|
|
5786
|
+
}
|
|
5787
|
+
if (target.kind === "StringTemplate" && target.stringValue) {
|
|
5788
|
+
return ((source.kind === "String" && source.value === target.stringValue) ||
|
|
5789
|
+
(source.kind === "StringTemplate" && source.stringValue === target.stringValue));
|
|
4318
5790
|
}
|
|
4319
5791
|
if (target.kind === "Number") {
|
|
4320
5792
|
return source.kind === "Number" && target.value === source.value;
|
|
@@ -4322,6 +5794,29 @@ export function createChecker(program) {
|
|
|
4322
5794
|
return undefined;
|
|
4323
5795
|
}
|
|
4324
5796
|
function isNumericLiteralRelatedTo(source, target) {
|
|
5797
|
+
// First check that the source numeric literal is assignable to the target scalar
|
|
5798
|
+
if (!isNumericAssignableToNumericScalar(source.numericValue, target)) {
|
|
5799
|
+
return false;
|
|
5800
|
+
}
|
|
5801
|
+
const min = getMinValueAsNumeric(program, target);
|
|
5802
|
+
const max = getMaxValueAsNumeric(program, target);
|
|
5803
|
+
const minExclusive = getMinValueExclusiveAsNumeric(program, target);
|
|
5804
|
+
const maxExclusive = getMaxValueExclusiveAsNumeric(program, target);
|
|
5805
|
+
if (min && source.numericValue.lt(min)) {
|
|
5806
|
+
return false;
|
|
5807
|
+
}
|
|
5808
|
+
if (minExclusive && source.numericValue.lte(minExclusive)) {
|
|
5809
|
+
return false;
|
|
5810
|
+
}
|
|
5811
|
+
if (max && source.numericValue.gt(max)) {
|
|
5812
|
+
return false;
|
|
5813
|
+
}
|
|
5814
|
+
if (maxExclusive && source.numericValue.gte(maxExclusive)) {
|
|
5815
|
+
return false;
|
|
5816
|
+
}
|
|
5817
|
+
return true;
|
|
5818
|
+
}
|
|
5819
|
+
function isNumericAssignableToNumericScalar(source, target) {
|
|
4325
5820
|
// if the target does not derive from numeric, then it can't be assigned a numeric literal
|
|
4326
5821
|
if (!areScalarsRelated(target, getStdType("numeric"))) {
|
|
4327
5822
|
return false;
|
|
@@ -4338,7 +5833,7 @@ export function createChecker(program) {
|
|
|
4338
5833
|
return true;
|
|
4339
5834
|
if (target.name === "decimal128")
|
|
4340
5835
|
return true;
|
|
4341
|
-
const isInt =
|
|
5836
|
+
const isInt = source.isInteger;
|
|
4342
5837
|
if (target.name === "integer")
|
|
4343
5838
|
return isInt;
|
|
4344
5839
|
if (target.name === "float")
|
|
@@ -4346,7 +5841,25 @@ export function createChecker(program) {
|
|
|
4346
5841
|
if (!(target.name in numericRanges))
|
|
4347
5842
|
return false;
|
|
4348
5843
|
const [low, high, options] = numericRanges[target.name];
|
|
4349
|
-
return source.
|
|
5844
|
+
return source.gte(low) && source.lte(high) && (!options.int || isInt);
|
|
5845
|
+
}
|
|
5846
|
+
function isStringLiteralRelatedTo(source, target) {
|
|
5847
|
+
if (!areScalarsRelated(target, getStdType("string"))) {
|
|
5848
|
+
return false;
|
|
5849
|
+
}
|
|
5850
|
+
if (source.kind === "StringTemplate") {
|
|
5851
|
+
return true;
|
|
5852
|
+
}
|
|
5853
|
+
const len = source.value.length;
|
|
5854
|
+
const min = getMinLength(program, target);
|
|
5855
|
+
const max = getMaxLength(program, target);
|
|
5856
|
+
if (min && len < min) {
|
|
5857
|
+
return false;
|
|
5858
|
+
}
|
|
5859
|
+
if (max && len > max) {
|
|
5860
|
+
return false;
|
|
5861
|
+
}
|
|
5862
|
+
return true;
|
|
4350
5863
|
}
|
|
4351
5864
|
function isModelRelatedTo(source, target, diagnosticTarget, relationCache) {
|
|
4352
5865
|
relationCache.set([source, target], Related.maybe);
|
|
@@ -4396,8 +5909,30 @@ export function createChecker(program) {
|
|
|
4396
5909
|
}
|
|
4397
5910
|
}
|
|
4398
5911
|
}
|
|
5912
|
+
else if (shouldCheckExcessProperties(source)) {
|
|
5913
|
+
for (const [propName, prop] of remainingProperties) {
|
|
5914
|
+
if (shouldCheckExcessProperty(prop)) {
|
|
5915
|
+
diagnostics.push(createDiagnostic({
|
|
5916
|
+
code: "unexpected-property",
|
|
5917
|
+
format: {
|
|
5918
|
+
propertyName: propName,
|
|
5919
|
+
type: getEntityName(target),
|
|
5920
|
+
},
|
|
5921
|
+
target: prop,
|
|
5922
|
+
}));
|
|
5923
|
+
}
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
4399
5926
|
return [diagnostics.length === 0 ? Related.true : Related.false, diagnostics];
|
|
4400
5927
|
}
|
|
5928
|
+
/** If we should check for excess properties on the given model. */
|
|
5929
|
+
function shouldCheckExcessProperties(model) {
|
|
5930
|
+
return model.node?.kind === SyntaxKind.ObjectLiteral;
|
|
5931
|
+
}
|
|
5932
|
+
/** If we should check for this specific property */
|
|
5933
|
+
function shouldCheckExcessProperty(prop) {
|
|
5934
|
+
return (prop.node?.kind === SyntaxKind.ObjectLiteralProperty && prop.node.parent === prop.model?.node);
|
|
5935
|
+
}
|
|
4401
5936
|
function getProperty(model, name) {
|
|
4402
5937
|
return (model.properties.get(name) ??
|
|
4403
5938
|
(model.baseModel !== undefined ? getProperty(model.baseModel, name) : undefined));
|
|
@@ -4430,6 +5965,51 @@ export function createChecker(program) {
|
|
|
4430
5965
|
}
|
|
4431
5966
|
return isTypeAssignableToInternal(source.indexer.value, target.indexer.value, diagnosticTarget, relationCache);
|
|
4432
5967
|
}
|
|
5968
|
+
function isTupleAssignableToArray(source, target, diagnosticTarget, relationCache) {
|
|
5969
|
+
const minItems = getMinItems(program, target);
|
|
5970
|
+
const maxItems = getMaxItems(program, target);
|
|
5971
|
+
if (minItems !== undefined && source.values.length < minItems) {
|
|
5972
|
+
return [
|
|
5973
|
+
Related.false,
|
|
5974
|
+
[
|
|
5975
|
+
createDiagnostic({
|
|
5976
|
+
code: "unassignable",
|
|
5977
|
+
messageId: "withDetails",
|
|
5978
|
+
format: {
|
|
5979
|
+
sourceType: getEntityName(source),
|
|
5980
|
+
targetType: getTypeName(target),
|
|
5981
|
+
details: `Source has ${source.values.length} element(s) but target requires ${minItems}.`,
|
|
5982
|
+
},
|
|
5983
|
+
target: diagnosticTarget,
|
|
5984
|
+
}),
|
|
5985
|
+
],
|
|
5986
|
+
];
|
|
5987
|
+
}
|
|
5988
|
+
if (maxItems !== undefined && source.values.length > maxItems) {
|
|
5989
|
+
return [
|
|
5990
|
+
Related.false,
|
|
5991
|
+
[
|
|
5992
|
+
createDiagnostic({
|
|
5993
|
+
code: "unassignable",
|
|
5994
|
+
messageId: "withDetails",
|
|
5995
|
+
format: {
|
|
5996
|
+
sourceType: getEntityName(source),
|
|
5997
|
+
targetType: getTypeName(target),
|
|
5998
|
+
details: `Source has ${source.values.length} element(s) but target only allows ${maxItems}.`,
|
|
5999
|
+
},
|
|
6000
|
+
target: diagnosticTarget,
|
|
6001
|
+
}),
|
|
6002
|
+
],
|
|
6003
|
+
];
|
|
6004
|
+
}
|
|
6005
|
+
for (const item of source.values) {
|
|
6006
|
+
const [related, diagnostics] = isTypeAssignableToInternal(item, target.indexer.value, diagnosticTarget, relationCache);
|
|
6007
|
+
if (!related) {
|
|
6008
|
+
return [Related.false, diagnostics];
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
return [Related.true, []];
|
|
6012
|
+
}
|
|
4433
6013
|
function isTupleAssignableToTuple(source, target, diagnosticTarget, relationCache) {
|
|
4434
6014
|
if (source.values.length !== target.values.length) {
|
|
4435
6015
|
return [
|
|
@@ -4439,7 +6019,7 @@ export function createChecker(program) {
|
|
|
4439
6019
|
code: "unassignable",
|
|
4440
6020
|
messageId: "withDetails",
|
|
4441
6021
|
format: {
|
|
4442
|
-
sourceType:
|
|
6022
|
+
sourceType: getEntityName(source),
|
|
4443
6023
|
targetType: getTypeName(target),
|
|
4444
6024
|
details: `Source has ${source.values.length} element(s) but target requires ${target.values.length}.`,
|
|
4445
6025
|
},
|
|
@@ -4492,7 +6072,7 @@ export function createChecker(program) {
|
|
|
4492
6072
|
function createUnassignableDiagnostic(source, target, diagnosticTarget) {
|
|
4493
6073
|
return createDiagnostic({
|
|
4494
6074
|
code: "unassignable",
|
|
4495
|
-
format: { targetType:
|
|
6075
|
+
format: { targetType: getEntityName(target), value: getEntityName(source) },
|
|
4496
6076
|
target: diagnosticTarget,
|
|
4497
6077
|
});
|
|
4498
6078
|
}
|
|
@@ -4516,22 +6096,6 @@ export function createChecker(program) {
|
|
|
4516
6096
|
function isAnonymous(type) {
|
|
4517
6097
|
return !("name" in type) || typeof type.name !== "string" || !type.name;
|
|
4518
6098
|
}
|
|
4519
|
-
function isErrorType(type) {
|
|
4520
|
-
return type.kind === "Intrinsic" && type.name === "ErrorType";
|
|
4521
|
-
}
|
|
4522
|
-
const numericRanges = {
|
|
4523
|
-
int64: [BigInt("-9223372036854775807"), BigInt("9223372036854775808"), { int: true }],
|
|
4524
|
-
int32: [-2147483648, 2147483647, { int: true }],
|
|
4525
|
-
int16: [-32768, 32767, { int: true }],
|
|
4526
|
-
int8: [-128, 127, { int: true }],
|
|
4527
|
-
uint64: [0, BigInt("18446744073709551615"), { int: true }],
|
|
4528
|
-
uint32: [0, 4294967295, { int: true }],
|
|
4529
|
-
uint16: [0, 65535, { int: true }],
|
|
4530
|
-
uint8: [0, 255, { int: true }],
|
|
4531
|
-
safeint: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, { int: true }],
|
|
4532
|
-
float32: [-3.4e38, 3.4e38, { int: false }],
|
|
4533
|
-
float64: [-Number.MAX_VALUE, Number.MAX_VALUE, { int: false }],
|
|
4534
|
-
};
|
|
4535
6099
|
/**
|
|
4536
6100
|
* Find all named models that could have been the source of the given
|
|
4537
6101
|
* property. This includes the named parents of all property sources in a
|
|
@@ -4831,7 +6395,7 @@ function reportDeprecation(program, target, message, reportFunc) {
|
|
|
4831
6395
|
function applyDecoratorToType(program, decApp, target) {
|
|
4832
6396
|
compilerAssert("decorators" in target, "Cannot apply decorator to non-decoratable type", target);
|
|
4833
6397
|
for (const arg of decApp.args) {
|
|
4834
|
-
if (isErrorType(arg.value)) {
|
|
6398
|
+
if (isType(arg.value) && isErrorType(arg.value)) {
|
|
4835
6399
|
// If one of the decorator argument is an error don't run it.
|
|
4836
6400
|
return;
|
|
4837
6401
|
}
|
|
@@ -4886,23 +6450,6 @@ function createDecoratorContext(program, decApp) {
|
|
|
4886
6450
|
},
|
|
4887
6451
|
};
|
|
4888
6452
|
}
|
|
4889
|
-
/**
|
|
4890
|
-
* Convert TypeSpec argument to JS argument.
|
|
4891
|
-
*/
|
|
4892
|
-
function marshalArgumentsForJS(args) {
|
|
4893
|
-
return args.map((arg) => {
|
|
4894
|
-
if (arg.kind === "Boolean" || arg.kind === "String" || arg.kind === "Number") {
|
|
4895
|
-
return literalTypeToValue(arg);
|
|
4896
|
-
}
|
|
4897
|
-
else if (arg.kind === "StringTemplate") {
|
|
4898
|
-
return stringTemplateToString(arg)[0];
|
|
4899
|
-
}
|
|
4900
|
-
return arg;
|
|
4901
|
-
});
|
|
4902
|
-
}
|
|
4903
|
-
function literalTypeToValue(type) {
|
|
4904
|
-
return type.value;
|
|
4905
|
-
}
|
|
4906
6453
|
function isTemplatedNode(node) {
|
|
4907
6454
|
return "templateParameters" in node && node.templateParameters.length > 0;
|
|
4908
6455
|
}
|
|
@@ -4926,9 +6473,10 @@ const ReflectionNameToKind = {
|
|
|
4926
6473
|
const _assertReflectionNameToKind = ReflectionNameToKind;
|
|
4927
6474
|
var ResolutionKind;
|
|
4928
6475
|
(function (ResolutionKind) {
|
|
4929
|
-
ResolutionKind[ResolutionKind["
|
|
4930
|
-
ResolutionKind[ResolutionKind["
|
|
4931
|
-
ResolutionKind[ResolutionKind["
|
|
6476
|
+
ResolutionKind[ResolutionKind["Value"] = 0] = "Value";
|
|
6477
|
+
ResolutionKind[ResolutionKind["Type"] = 1] = "Type";
|
|
6478
|
+
ResolutionKind[ResolutionKind["BaseType"] = 2] = "BaseType";
|
|
6479
|
+
ResolutionKind[ResolutionKind["Constraint"] = 3] = "Constraint";
|
|
4932
6480
|
})(ResolutionKind || (ResolutionKind = {}));
|
|
4933
6481
|
class PendingResolutions {
|
|
4934
6482
|
#data = new Map();
|
|
@@ -4964,4 +6512,19 @@ const defaultSymbolResolutionOptions = {
|
|
|
4964
6512
|
resolveDecorators: false,
|
|
4965
6513
|
checkTemplateTypes: true,
|
|
4966
6514
|
};
|
|
6515
|
+
/**
|
|
6516
|
+
* Convert LEGACY for projection.
|
|
6517
|
+
* THIS IS BROKEN. Some decorators will not receive the correct type.
|
|
6518
|
+
* It has been broken since the introduction of valueof.
|
|
6519
|
+
* As projection as put on hold as long as versioning works we are in a good state.
|
|
6520
|
+
*/
|
|
6521
|
+
function unsafe_projectionArgumentMarshalForJS(arg) {
|
|
6522
|
+
if (arg.kind === "Boolean" || arg.kind === "String" || arg.kind === "Number") {
|
|
6523
|
+
return arg.value;
|
|
6524
|
+
}
|
|
6525
|
+
else if (arg.kind === "StringTemplate") {
|
|
6526
|
+
return arg.stringValue;
|
|
6527
|
+
}
|
|
6528
|
+
return arg;
|
|
6529
|
+
}
|
|
4967
6530
|
//# sourceMappingURL=checker.js.map
|