@typespec/compiler 0.57.0-dev.0 → 0.57.0-dev.5
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 +9 -9
- package/dist/generated-defs/TypeSpec.d.ts.map +1 -1
- package/dist/manifest.js +2 -2
- 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 +1577 -241
- 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/parser.d.ts.map +1 -1
- package/dist/src/core/parser.js +232 -5
- 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/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 +224 -45
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js +8 -0
- 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 +2 -1
- package/dist/src/emitter-framework/type-emitter.d.ts.map +1 -1
- package/dist/src/emitter-framework/type-emitter.js +10 -2
- 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/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.map +1 -1
- package/dist/src/server/completion.js +6 -0
- package/dist/src/server/completion.js.map +1 -1
- package/dist/src/server/serverlib.js +2 -2
- 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 +1 -2
- 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 +1 -1
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";
|
|
16
|
+
import { numericRanges } from "./numeric-ranges.js";
|
|
17
|
+
import { Numeric } from "./numeric.js";
|
|
12
18
|
import { exprIsBareIdentifier, 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,259 @@ 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
|
}
|
|
318
329
|
function getTypeForNode(node, mapper) {
|
|
330
|
+
const entity = checkNode(node, mapper);
|
|
331
|
+
if (entity === null) {
|
|
332
|
+
return errorType;
|
|
333
|
+
}
|
|
334
|
+
if (entity.entityKind === "Indeterminate") {
|
|
335
|
+
return entity.type;
|
|
336
|
+
}
|
|
337
|
+
if (isValue(entity)) {
|
|
338
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
339
|
+
code: "value-in-type",
|
|
340
|
+
target: node,
|
|
341
|
+
}));
|
|
342
|
+
return errorType;
|
|
343
|
+
}
|
|
344
|
+
if (entity.kind === "TemplateParameter") {
|
|
345
|
+
if (entity.constraint?.valueType) {
|
|
346
|
+
// means this template constraint will accept values
|
|
347
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
348
|
+
code: "value-in-type",
|
|
349
|
+
messageId: "referenceTemplate",
|
|
350
|
+
target: node,
|
|
351
|
+
}));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return entity;
|
|
355
|
+
}
|
|
356
|
+
function getValueForNode(node, mapper, constraint, options = {}) {
|
|
357
|
+
const initial = checkNode(node, mapper, constraint);
|
|
358
|
+
if (initial === null) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
let entity;
|
|
362
|
+
if (initial.entityKind === "Indeterminate") {
|
|
363
|
+
entity = getValueFromIndeterminate(initial.type, constraint, node);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
entity = initial;
|
|
367
|
+
}
|
|
368
|
+
if (options.legacyTupleAndModelCast && entity !== null && isType(entity)) {
|
|
369
|
+
entity = legacy_tryTypeToValueCast(entity, constraint, node);
|
|
370
|
+
}
|
|
371
|
+
if (entity === null) {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
if (isValue(entity)) {
|
|
375
|
+
return constraint ? inferScalarsFromConstraints(entity, constraint.type) : entity;
|
|
376
|
+
}
|
|
377
|
+
reportExpectedValue(node, entity);
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
function reportExpectedValue(target, type) {
|
|
381
|
+
if (type.kind === "Model" && type.name === "" && target.kind === SyntaxKind.ModelExpression) {
|
|
382
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
383
|
+
code: "expect-value",
|
|
384
|
+
messageId: "model",
|
|
385
|
+
format: { name: getTypeName(type) },
|
|
386
|
+
codefixes: [createModelToObjectValueCodeFix(target)],
|
|
387
|
+
target,
|
|
388
|
+
}));
|
|
389
|
+
}
|
|
390
|
+
else if (type.kind === "Tuple" && target.kind === SyntaxKind.TupleExpression) {
|
|
391
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
392
|
+
code: "expect-value",
|
|
393
|
+
messageId: "tuple",
|
|
394
|
+
format: { name: getTypeName(type) },
|
|
395
|
+
codefixes: [createTupleToArrayValueCodeFix(target)],
|
|
396
|
+
target,
|
|
397
|
+
}));
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
401
|
+
code: "expect-value",
|
|
402
|
+
format: { name: getTypeName(type) },
|
|
403
|
+
target,
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/** 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. */
|
|
408
|
+
function getValueFromIndeterminate(type, constraint, node) {
|
|
409
|
+
switch (type.kind) {
|
|
410
|
+
case "String":
|
|
411
|
+
case "StringTemplate":
|
|
412
|
+
return checkStringValue(type, constraint, node);
|
|
413
|
+
case "Number":
|
|
414
|
+
return checkNumericValue(type, constraint, node);
|
|
415
|
+
case "Boolean":
|
|
416
|
+
return checkBooleanValue(type, constraint, node);
|
|
417
|
+
case "EnumMember":
|
|
418
|
+
return checkEnumValue(type, constraint, node);
|
|
419
|
+
case "UnionVariant":
|
|
420
|
+
return getValueFromIndeterminate(type.type, constraint, node);
|
|
421
|
+
case "Intrinsic":
|
|
422
|
+
switch (type.name) {
|
|
423
|
+
case "null":
|
|
424
|
+
return checkNullValue(type, constraint, node);
|
|
425
|
+
}
|
|
426
|
+
return type;
|
|
427
|
+
default:
|
|
428
|
+
return type;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
function legacy_tryTypeToValueCast(type, constraint, node) {
|
|
432
|
+
switch (type.kind) {
|
|
433
|
+
case "Tuple":
|
|
434
|
+
return legacy_tryUsingTupleAsArrayValue(type, constraint?.type, node);
|
|
435
|
+
case "Model":
|
|
436
|
+
return legacy_tryUsingModelAsObjectValue(type, constraint?.type, node);
|
|
437
|
+
default:
|
|
438
|
+
return type;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
// Legacy behavior to smooth transition to object values.
|
|
442
|
+
function legacy_tryUsingModelAsObjectValue(model, type, node) {
|
|
443
|
+
if (model.node?.kind !== SyntaxKind.ModelExpression) {
|
|
444
|
+
return model; // we only want to convert model expressions
|
|
445
|
+
}
|
|
446
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
447
|
+
code: "deprecated",
|
|
448
|
+
codefixes: [createModelToObjectValueCodeFix(model.node)],
|
|
449
|
+
format: {
|
|
450
|
+
message: "Using a model as a value is deprecated. Use an object value instead(with #{}).",
|
|
451
|
+
},
|
|
452
|
+
target: model.node,
|
|
453
|
+
}));
|
|
454
|
+
const value = {
|
|
455
|
+
entityKind: "Value",
|
|
456
|
+
valueKind: "ObjectValue",
|
|
457
|
+
type: type ?? model,
|
|
458
|
+
node: model.node,
|
|
459
|
+
properties: new Map(),
|
|
460
|
+
};
|
|
461
|
+
for (const prop of model.properties.values()) {
|
|
462
|
+
let propValue = getValueFromIndeterminate(prop.type, { kind: "assignment", type: prop.type }, node);
|
|
463
|
+
if (propValue !== null && isType(propValue)) {
|
|
464
|
+
propValue = legacy_tryTypeToValueCast(propValue, { kind: "assignment", type: prop.type }, node);
|
|
465
|
+
}
|
|
466
|
+
if (propValue == null) {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
else if (!isValue(propValue)) {
|
|
470
|
+
return model;
|
|
471
|
+
}
|
|
472
|
+
value.properties.set(prop.name, {
|
|
473
|
+
name: prop.name,
|
|
474
|
+
value: propValue,
|
|
475
|
+
node: prop.node,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
if (type !== undefined && !checkTypeAssignable(model, type, node)) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
return value;
|
|
482
|
+
}
|
|
483
|
+
// Legacy behavior to smooth transition to array values.
|
|
484
|
+
function legacy_tryUsingTupleAsArrayValue(tuple, type, node) {
|
|
485
|
+
if (tuple.node.kind !== SyntaxKind.TupleExpression) {
|
|
486
|
+
return tuple; // we won't convert dynamic tuples to array values
|
|
487
|
+
}
|
|
488
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
489
|
+
code: "deprecated",
|
|
490
|
+
codefixes: [createTupleToArrayValueCodeFix(tuple.node)],
|
|
491
|
+
format: {
|
|
492
|
+
message: "Using a tuple as a value is deprecated. Use an array value instead(with #[]).",
|
|
493
|
+
},
|
|
494
|
+
target: tuple.node,
|
|
495
|
+
}));
|
|
496
|
+
const values = [];
|
|
497
|
+
for (const [index, item] of tuple.values.entries()) {
|
|
498
|
+
const itemType = type?.kind === "Model" && isArrayModelType(program, type)
|
|
499
|
+
? type.indexer.value
|
|
500
|
+
: type?.kind === "Tuple"
|
|
501
|
+
? type.values[index]
|
|
502
|
+
: undefined;
|
|
503
|
+
let value = getValueFromIndeterminate(item, itemType && { kind: "assignment", type: itemType }, node);
|
|
504
|
+
if (value !== null && isType(value)) {
|
|
505
|
+
value = legacy_tryTypeToValueCast(value, itemType && { kind: "assignment", type: itemType }, node);
|
|
506
|
+
}
|
|
507
|
+
if (value === null) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
else if (!isValue(value)) {
|
|
511
|
+
return tuple;
|
|
512
|
+
}
|
|
513
|
+
values.push(value);
|
|
514
|
+
}
|
|
515
|
+
if (type !== undefined && !checkTypeAssignable(tuple, type, node)) {
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
entityKind: "Value",
|
|
520
|
+
valueKind: "ArrayValue",
|
|
521
|
+
type: type ?? tuple,
|
|
522
|
+
node: tuple.node,
|
|
523
|
+
values,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Gets a type or value depending on the node and current constraint.
|
|
528
|
+
* 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.
|
|
529
|
+
* This means that if the constraint is `string | valueof string` passing `"abc"` will send the value `"abc"` and not the type `"abc"`.
|
|
530
|
+
*/
|
|
531
|
+
function getTypeOrValueForNode(node, mapper, constraint) {
|
|
532
|
+
const valueConstraint = extractValueOfConstraints(constraint);
|
|
533
|
+
const entity = checkNode(node, mapper, valueConstraint);
|
|
534
|
+
if (entity === null) {
|
|
535
|
+
return entity;
|
|
536
|
+
}
|
|
537
|
+
else if (isType(entity)) {
|
|
538
|
+
if (valueConstraint) {
|
|
539
|
+
return legacy_tryTypeToValueCast(entity, valueConstraint, node);
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
return entity;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
else if (isValue(entity)) {
|
|
546
|
+
return entity;
|
|
547
|
+
}
|
|
548
|
+
compilerAssert(entity.entityKind === "Indeterminate", "Expected indeterminate entity");
|
|
549
|
+
if (valueConstraint) {
|
|
550
|
+
const valueDiagnostics = [];
|
|
551
|
+
const oldDiagnosticHook = onCheckerDiagnostic;
|
|
552
|
+
onCheckerDiagnostic = (x) => valueDiagnostics.push(x);
|
|
553
|
+
const result = getValueFromIndeterminate(entity.type, valueConstraint, node);
|
|
554
|
+
onCheckerDiagnostic = oldDiagnosticHook;
|
|
555
|
+
if (result) {
|
|
556
|
+
// If there were diagnostic reported but we still got a value this means that the value might be invalid.
|
|
557
|
+
reportCheckerDiagnostics(valueDiagnostics);
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return entity.type;
|
|
562
|
+
}
|
|
563
|
+
/** Extact the type constraint a value should match. */
|
|
564
|
+
function extractValueOfConstraints(constraint) {
|
|
565
|
+
if (constraint?.constraint.valueType) {
|
|
566
|
+
return { kind: constraint.kind, type: constraint.constraint.valueType };
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Gets a type, value or indeterminate depending on the node and current constraint.
|
|
574
|
+
* For nodes that can be both type or values(e.g. string literals), an indeterminate entity will be returned.
|
|
575
|
+
* It is the job of of the consumer to decide if it should be a type or a value depending on the context.
|
|
576
|
+
*/
|
|
577
|
+
function checkNode(node, mapper, valueConstraint) {
|
|
319
578
|
switch (node.kind) {
|
|
320
579
|
case SyntaxKind.ModelExpression:
|
|
321
580
|
return checkModel(node, mapper);
|
|
@@ -346,10 +605,10 @@ export function createChecker(program) {
|
|
|
346
605
|
return checkNumericLiteral(node);
|
|
347
606
|
case SyntaxKind.BooleanLiteral:
|
|
348
607
|
return checkBooleanLiteral(node);
|
|
349
|
-
case SyntaxKind.TupleExpression:
|
|
350
|
-
return checkTupleExpression(node, mapper);
|
|
351
608
|
case SyntaxKind.StringLiteral:
|
|
352
609
|
return checkStringLiteral(node);
|
|
610
|
+
case SyntaxKind.TupleExpression:
|
|
611
|
+
return checkTupleExpression(node, mapper);
|
|
353
612
|
case SyntaxKind.StringTemplateExpression:
|
|
354
613
|
return checkStringTemplateExpresion(node, mapper);
|
|
355
614
|
case SyntaxKind.ArrayExpression:
|
|
@@ -363,7 +622,7 @@ export function createChecker(program) {
|
|
|
363
622
|
case SyntaxKind.FunctionDeclarationStatement:
|
|
364
623
|
return checkFunctionDeclaration(node, mapper);
|
|
365
624
|
case SyntaxKind.TypeReference:
|
|
366
|
-
return
|
|
625
|
+
return checkTypeOrValueReference(node, mapper);
|
|
367
626
|
case SyntaxKind.TemplateArgument:
|
|
368
627
|
return checkTemplateArgument(node, mapper);
|
|
369
628
|
case SyntaxKind.TemplateParameterDeclaration:
|
|
@@ -376,12 +635,19 @@ export function createChecker(program) {
|
|
|
376
635
|
return neverType;
|
|
377
636
|
case SyntaxKind.UnknownKeyword:
|
|
378
637
|
return unknownType;
|
|
638
|
+
case SyntaxKind.ObjectLiteral:
|
|
639
|
+
return checkObjectValue(node, mapper, valueConstraint);
|
|
640
|
+
case SyntaxKind.ArrayLiteral:
|
|
641
|
+
return checkArrayValue(node, mapper, valueConstraint);
|
|
642
|
+
case SyntaxKind.ConstStatement:
|
|
643
|
+
return checkConst(node);
|
|
644
|
+
case SyntaxKind.CallExpression:
|
|
645
|
+
return checkCallExpression(node, mapper);
|
|
646
|
+
case SyntaxKind.TypeOfExpression:
|
|
647
|
+
return checkTypeOfExpression(node, mapper);
|
|
648
|
+
default:
|
|
649
|
+
return errorType;
|
|
379
650
|
}
|
|
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
651
|
}
|
|
386
652
|
/**
|
|
387
653
|
* Return a fully qualified id of node
|
|
@@ -440,7 +706,7 @@ export function createChecker(program) {
|
|
|
440
706
|
});
|
|
441
707
|
if (node.constraint) {
|
|
442
708
|
pendingResolutions.start(getNodeSymId(node), ResolutionKind.Constraint);
|
|
443
|
-
type.constraint =
|
|
709
|
+
type.constraint = getParamConstraintEntityForNode(node.constraint);
|
|
444
710
|
pendingResolutions.finish(getNodeSymId(node), ResolutionKind.Constraint);
|
|
445
711
|
}
|
|
446
712
|
if (node.default) {
|
|
@@ -453,23 +719,24 @@ export function createChecker(program) {
|
|
|
453
719
|
if (declaredType.default === undefined) {
|
|
454
720
|
return undefined;
|
|
455
721
|
}
|
|
456
|
-
if (isErrorType(declaredType.default))
|
|
722
|
+
if ((isType(declaredType.default) && isErrorType(declaredType.default)) ||
|
|
723
|
+
declaredType.default === null) {
|
|
457
724
|
return declaredType.default;
|
|
458
725
|
}
|
|
459
|
-
return
|
|
726
|
+
return checkNode(node.default, mapper);
|
|
460
727
|
}
|
|
461
728
|
function checkTemplateParameterDefault(nodeDefault, templateParameters, index, constraint) {
|
|
462
729
|
function visit(node) {
|
|
463
|
-
const
|
|
730
|
+
const entity = checkNode(node);
|
|
464
731
|
let hasError = false;
|
|
465
|
-
if (
|
|
732
|
+
if (entity !== null && "kind" in entity && entity.kind === "TemplateParameter") {
|
|
466
733
|
for (let i = index; i < templateParameters.length; i++) {
|
|
467
|
-
if (
|
|
734
|
+
if (entity.node.symbol === templateParameters[i].symbol) {
|
|
468
735
|
reportCheckerDiagnostic(createDiagnostic({ code: "invalid-template-default", target: node }));
|
|
469
736
|
return undefined;
|
|
470
737
|
}
|
|
471
738
|
}
|
|
472
|
-
return
|
|
739
|
+
return entity;
|
|
473
740
|
}
|
|
474
741
|
visitChildren(node, (x) => {
|
|
475
742
|
const visited = visit(x);
|
|
@@ -477,10 +744,10 @@ export function createChecker(program) {
|
|
|
477
744
|
hasError = true;
|
|
478
745
|
}
|
|
479
746
|
});
|
|
480
|
-
return hasError ? undefined :
|
|
747
|
+
return hasError ? undefined : entity;
|
|
481
748
|
}
|
|
482
749
|
const type = visit(nodeDefault) ?? errorType;
|
|
483
|
-
if (!isErrorType(type) && constraint) {
|
|
750
|
+
if (!("kind" in type && isErrorType(type)) && constraint) {
|
|
484
751
|
checkTypeAssignable(type, constraint, nodeDefault);
|
|
485
752
|
}
|
|
486
753
|
return type;
|
|
@@ -500,8 +767,22 @@ export function createChecker(program) {
|
|
|
500
767
|
const type = checkTypeReferenceSymbol(sym, node, mapper, instantiateTemplate);
|
|
501
768
|
return type;
|
|
502
769
|
}
|
|
770
|
+
/**
|
|
771
|
+
* Check and resolve a type for the given type reference node.
|
|
772
|
+
* @param node Node.
|
|
773
|
+
* @param mapper Type mapper for template instantiation context.
|
|
774
|
+
* @param instantiateTemplate If templated type should be instantiated if they haven't yet.
|
|
775
|
+
* @returns Resolved type.
|
|
776
|
+
*/
|
|
777
|
+
function checkTypeOrValueReference(node, mapper, instantiateTemplate = true) {
|
|
778
|
+
const sym = resolveTypeReferenceSym(node, mapper);
|
|
779
|
+
if (!sym) {
|
|
780
|
+
return errorType;
|
|
781
|
+
}
|
|
782
|
+
return checkTypeOrValueReferenceSymbol(sym, node, mapper, instantiateTemplate) ?? errorType;
|
|
783
|
+
}
|
|
503
784
|
function checkTemplateArgument(node, mapper) {
|
|
504
|
-
return
|
|
785
|
+
return checkNode(node.argument, mapper);
|
|
505
786
|
}
|
|
506
787
|
function resolveTypeReference(node) {
|
|
507
788
|
const oldDiagnosticHook = onCheckerDiagnostic;
|
|
@@ -567,8 +848,8 @@ export function createChecker(program) {
|
|
|
567
848
|
function checkTemplateInstantiationArgs(node, args, decls, mapper) {
|
|
568
849
|
const params = new Map();
|
|
569
850
|
const positional = [];
|
|
570
|
-
const initMap = new Map(decls.map(
|
|
571
|
-
const declaredType =
|
|
851
|
+
const initMap = new Map(decls.map((decl) => {
|
|
852
|
+
const declaredType = checkTemplateParameterDeclaration(decl, undefined);
|
|
572
853
|
positional.push(declaredType);
|
|
573
854
|
params.set(decl.id.sv, declaredType);
|
|
574
855
|
return [
|
|
@@ -582,7 +863,7 @@ export function createChecker(program) {
|
|
|
582
863
|
let named = false;
|
|
583
864
|
for (const [arg, idx] of args.map((v, i) => [v, i])) {
|
|
584
865
|
function deferredCheck() {
|
|
585
|
-
return [arg,
|
|
866
|
+
return [arg, checkNode(arg.argument, mapper)];
|
|
586
867
|
}
|
|
587
868
|
if (arg.name) {
|
|
588
869
|
named = true;
|
|
@@ -657,18 +938,30 @@ export function createChecker(program) {
|
|
|
657
938
|
target: node,
|
|
658
939
|
}));
|
|
659
940
|
// TODO-TIM check if we expose this below
|
|
660
|
-
commit(param, param.constraint?.
|
|
941
|
+
commit(param, param.constraint?.type ?? unknownType);
|
|
661
942
|
}
|
|
662
943
|
continue;
|
|
663
944
|
}
|
|
664
945
|
const [argNode, type] = init();
|
|
946
|
+
if (type === null) {
|
|
947
|
+
commit(param, unknownType);
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
665
950
|
if (param.constraint) {
|
|
666
|
-
const constraint = param.constraint.kind === "TemplateParameter"
|
|
667
|
-
? finalMap.get(param.constraint)
|
|
951
|
+
const constraint = param.constraint.type?.kind === "TemplateParameter"
|
|
952
|
+
? finalMap.get(param.constraint.type)
|
|
668
953
|
: param.constraint;
|
|
669
|
-
if (
|
|
670
|
-
|
|
671
|
-
|
|
954
|
+
if (isType(type) && param.constraint?.valueType) {
|
|
955
|
+
const converted = legacy_tryTypeToValueCast(type, { kind: "argument", type: param.constraint.valueType }, argNode);
|
|
956
|
+
// If we manage to convert it means this might be convertable so we skip type checking.
|
|
957
|
+
// However we still return the original entity
|
|
958
|
+
if (converted !== type) {
|
|
959
|
+
commit(param, type);
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (param.constraint && !checkArgumentAssignable(type, constraint, argNode)) {
|
|
964
|
+
const effectiveType = param.constraint.type ?? unknownType;
|
|
672
965
|
commit(param, effectiveType);
|
|
673
966
|
continue;
|
|
674
967
|
}
|
|
@@ -679,6 +972,15 @@ export function createChecker(program) {
|
|
|
679
972
|
commit(param, unknownType);
|
|
680
973
|
continue;
|
|
681
974
|
}
|
|
975
|
+
else if (isValue(type)) {
|
|
976
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
977
|
+
code: "value-in-type",
|
|
978
|
+
messageId: "noTemplateConstraint",
|
|
979
|
+
target: argNode,
|
|
980
|
+
}));
|
|
981
|
+
commit(param, unknownType);
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
682
984
|
commit(param, type);
|
|
683
985
|
}
|
|
684
986
|
return finalMap;
|
|
@@ -692,6 +994,20 @@ export function createChecker(program) {
|
|
|
692
994
|
* @returns resolved type.
|
|
693
995
|
*/
|
|
694
996
|
function checkTypeReferenceSymbol(sym, node, mapper, instantiateTemplates = true) {
|
|
997
|
+
const result = checkTypeOrValueReferenceSymbol(sym, node, mapper, instantiateTemplates);
|
|
998
|
+
if (result === null || isValue(result)) {
|
|
999
|
+
reportCheckerDiagnostic(createDiagnostic({ code: "value-in-type", target: node }));
|
|
1000
|
+
return errorType;
|
|
1001
|
+
}
|
|
1002
|
+
if (result.entityKind === "Indeterminate") {
|
|
1003
|
+
return result.type;
|
|
1004
|
+
}
|
|
1005
|
+
return result;
|
|
1006
|
+
}
|
|
1007
|
+
function checkTypeOrValueReferenceSymbol(sym, node, mapper, instantiateTemplates = true) {
|
|
1008
|
+
if (sym.flags & 16777216 /* SymbolFlags.Const */) {
|
|
1009
|
+
return getValueForNode(sym.declarations[0], mapper);
|
|
1010
|
+
}
|
|
695
1011
|
if (sym.flags & 16384 /* SymbolFlags.Decorator */) {
|
|
696
1012
|
reportCheckerDiagnostic(createDiagnostic({ code: "invalid-type-ref", messageId: "decorator", target: sym }));
|
|
697
1013
|
return errorType;
|
|
@@ -719,14 +1035,14 @@ export function createChecker(program) {
|
|
|
719
1035
|
target: node,
|
|
720
1036
|
}));
|
|
721
1037
|
}
|
|
722
|
-
if (sym.flags &
|
|
1038
|
+
if (sym.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
723
1039
|
compilerAssert(sym.type, "Expected late bound symbol to have type");
|
|
724
1040
|
return sym.type;
|
|
725
1041
|
}
|
|
726
1042
|
else if (symbolLinks.declaredType) {
|
|
727
1043
|
baseType = symbolLinks.declaredType;
|
|
728
1044
|
}
|
|
729
|
-
else if (sym.flags &
|
|
1045
|
+
else if (sym.flags & 33555780 /* SymbolFlags.Member */) {
|
|
730
1046
|
baseType = checkMemberSym(sym, mapper);
|
|
731
1047
|
}
|
|
732
1048
|
else {
|
|
@@ -749,12 +1065,13 @@ export function createChecker(program) {
|
|
|
749
1065
|
target: node,
|
|
750
1066
|
}));
|
|
751
1067
|
}
|
|
752
|
-
if (sym.flags &
|
|
753
|
-
compilerAssert(sym.type,
|
|
1068
|
+
if (sym.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
1069
|
+
compilerAssert(sym.type, `Expected late bound symbol to have type`);
|
|
754
1070
|
return sym.type;
|
|
755
1071
|
}
|
|
756
1072
|
else if (sym.flags & 32768 /* SymbolFlags.TemplateParameter */) {
|
|
757
|
-
|
|
1073
|
+
const mapped = checkTemplateParameterDeclaration(sym.declarations[0], mapper);
|
|
1074
|
+
baseType = mapped;
|
|
758
1075
|
}
|
|
759
1076
|
else if (symbolLinks.type) {
|
|
760
1077
|
// Have a cached type for non-declarations
|
|
@@ -764,7 +1081,7 @@ export function createChecker(program) {
|
|
|
764
1081
|
baseType = symbolLinks.declaredType;
|
|
765
1082
|
}
|
|
766
1083
|
else {
|
|
767
|
-
if (sym.flags &
|
|
1084
|
+
if (sym.flags & 33555780 /* SymbolFlags.Member */) {
|
|
768
1085
|
baseType = checkMemberSym(sym, mapper);
|
|
769
1086
|
}
|
|
770
1087
|
else {
|
|
@@ -783,6 +1100,12 @@ export function createChecker(program) {
|
|
|
783
1100
|
checkDeprecated(baseType, declarationNode, node);
|
|
784
1101
|
}
|
|
785
1102
|
}
|
|
1103
|
+
// Elements that could be used as type or values depending on the context
|
|
1104
|
+
if (baseType.kind === "EnumMember" ||
|
|
1105
|
+
baseType.kind === "UnionVariant" ||
|
|
1106
|
+
isNullType(baseType)) {
|
|
1107
|
+
return createIndeterminateEntity(baseType);
|
|
1108
|
+
}
|
|
786
1109
|
return baseType;
|
|
787
1110
|
}
|
|
788
1111
|
/**
|
|
@@ -797,11 +1120,11 @@ export function createChecker(program) {
|
|
|
797
1120
|
if (symbolLinks.declaredType) {
|
|
798
1121
|
return symbolLinks.declaredType;
|
|
799
1122
|
}
|
|
800
|
-
if (sym.flags &
|
|
1123
|
+
if (sym.flags & 67108864 /* SymbolFlags.LateBound */) {
|
|
801
1124
|
compilerAssert(sym.type, "Expected late bound symbol to have type");
|
|
802
1125
|
return sym.type;
|
|
803
1126
|
}
|
|
804
|
-
if (sym.flags &
|
|
1127
|
+
if (sym.flags & 33555780 /* SymbolFlags.Member */) {
|
|
805
1128
|
return checkMemberSym(sym, mapper);
|
|
806
1129
|
}
|
|
807
1130
|
else {
|
|
@@ -816,7 +1139,7 @@ export function createChecker(program) {
|
|
|
816
1139
|
* @returns The declared type for the given node.
|
|
817
1140
|
*/
|
|
818
1141
|
function checkDeclaredType(sym, node, mapper) {
|
|
819
|
-
|
|
1142
|
+
const type = sym.flags & 2 /* SymbolFlags.Model */
|
|
820
1143
|
? checkModelStatement(node, mapper)
|
|
821
1144
|
: sym.flags & 8 /* SymbolFlags.Scalar */
|
|
822
1145
|
? checkScalar(node, mapper)
|
|
@@ -827,6 +1150,7 @@ export function createChecker(program) {
|
|
|
827
1150
|
: sym.flags & 16 /* SymbolFlags.Operation */
|
|
828
1151
|
? checkOperation(node, mapper)
|
|
829
1152
|
: checkUnion(node, mapper);
|
|
1153
|
+
return type;
|
|
830
1154
|
}
|
|
831
1155
|
function getOrInstantiateTemplate(templateNode, params, args, parentMapper, instantiateTempalates = true) {
|
|
832
1156
|
const symbolLinks = templateNode.kind === SyntaxKind.OperationStatement &&
|
|
@@ -874,6 +1198,57 @@ export function createChecker(program) {
|
|
|
874
1198
|
}
|
|
875
1199
|
return type;
|
|
876
1200
|
}
|
|
1201
|
+
/** Check a union expresion used in a parameter constraint, those allow the use of `valueof` as a variant. */
|
|
1202
|
+
function checkMixedParameterConstraintUnion(node, mapper) {
|
|
1203
|
+
const values = [];
|
|
1204
|
+
const types = [];
|
|
1205
|
+
for (const option of node.options) {
|
|
1206
|
+
const [kind, type] = getTypeOrValueOfTypeForNode(option, mapper);
|
|
1207
|
+
if (kind === "value") {
|
|
1208
|
+
values.push(type);
|
|
1209
|
+
}
|
|
1210
|
+
else {
|
|
1211
|
+
types.push(type);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return {
|
|
1215
|
+
entityKind: "MixedParameterConstraint",
|
|
1216
|
+
node,
|
|
1217
|
+
valueType: values.length === 0
|
|
1218
|
+
? undefined
|
|
1219
|
+
: values.length === 1
|
|
1220
|
+
? values[0]
|
|
1221
|
+
: createConstraintUnion(node, values),
|
|
1222
|
+
type: types.length === 0
|
|
1223
|
+
? undefined
|
|
1224
|
+
: types.length === 1
|
|
1225
|
+
? types[0]
|
|
1226
|
+
: createConstraintUnion(node, types),
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
function createConstraintUnion(node, options) {
|
|
1230
|
+
const variants = createRekeyableMap();
|
|
1231
|
+
const union = createAndFinishType({
|
|
1232
|
+
kind: "Union",
|
|
1233
|
+
node,
|
|
1234
|
+
options,
|
|
1235
|
+
decorators: [],
|
|
1236
|
+
variants,
|
|
1237
|
+
expression: true,
|
|
1238
|
+
});
|
|
1239
|
+
for (const option of options) {
|
|
1240
|
+
const name = Symbol("indexer-union-variant");
|
|
1241
|
+
variants.set(name, createAndFinishType({
|
|
1242
|
+
kind: "UnionVariant",
|
|
1243
|
+
node: undefined,
|
|
1244
|
+
type: option,
|
|
1245
|
+
name,
|
|
1246
|
+
union,
|
|
1247
|
+
decorators: [],
|
|
1248
|
+
}));
|
|
1249
|
+
}
|
|
1250
|
+
return union;
|
|
1251
|
+
}
|
|
877
1252
|
function checkUnionExpression(node, mapper) {
|
|
878
1253
|
const unionType = createAndFinishType({
|
|
879
1254
|
kind: "Union",
|
|
@@ -910,13 +1285,6 @@ export function createChecker(program) {
|
|
|
910
1285
|
}
|
|
911
1286
|
return unionType;
|
|
912
1287
|
}
|
|
913
|
-
function checkValueOfExpression(node, mapper) {
|
|
914
|
-
const target = getTypeForNode(node.target, mapper);
|
|
915
|
-
return {
|
|
916
|
-
kind: "Value",
|
|
917
|
-
target,
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
1288
|
/**
|
|
921
1289
|
* Intersection produces a model type from the properties of its operands.
|
|
922
1290
|
* So this doesn't work if we don't have a known set of properties (e.g.
|
|
@@ -948,14 +1316,43 @@ export function createChecker(program) {
|
|
|
948
1316
|
name: `@${name}`,
|
|
949
1317
|
namespace,
|
|
950
1318
|
node,
|
|
951
|
-
target: checkFunctionParameter(node.target, mapper),
|
|
952
|
-
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper)),
|
|
1319
|
+
target: checkFunctionParameter(node.target, mapper, true),
|
|
1320
|
+
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, true)),
|
|
953
1321
|
implementation: implementation ?? (() => { }),
|
|
954
1322
|
});
|
|
955
1323
|
namespace.decoratorDeclarations.set(name, decoratorType);
|
|
956
1324
|
linkType(links, decoratorType, mapper);
|
|
1325
|
+
checkDecoratorLegacyMarshalling(decoratorType);
|
|
957
1326
|
return decoratorType;
|
|
958
1327
|
}
|
|
1328
|
+
function checkDecoratorLegacyMarshalling(decorator) {
|
|
1329
|
+
const marshalling = resolveDecoratorArgMarshalling(decorator);
|
|
1330
|
+
function reportDeprecatedLegacyMarshalling(param, message) {
|
|
1331
|
+
reportDeprecated(program, [
|
|
1332
|
+
`Parameter ${param.name} of decorator ${decorator.name} is using legacy marshalling but is accepting ${message}.`,
|
|
1333
|
+
`This will change in the future.`,
|
|
1334
|
+
'Add `export const $flags = {decoratorArgMarshalling: "new"}}` to your library to opt-in to the new marshalling behavior.',
|
|
1335
|
+
].join("\n"), param.node);
|
|
1336
|
+
}
|
|
1337
|
+
if (marshalling === "legacy") {
|
|
1338
|
+
for (const param of decorator.parameters) {
|
|
1339
|
+
if (param.type.valueType) {
|
|
1340
|
+
if (ignoreDiagnostics(isTypeAssignableTo(nullType, param.type.valueType, param.type))) {
|
|
1341
|
+
reportDeprecatedLegacyMarshalling(param, "null as a type");
|
|
1342
|
+
}
|
|
1343
|
+
else if (param.type.valueType.kind === "Enum" ||
|
|
1344
|
+
param.type.valueType.kind === "EnumMember" ||
|
|
1345
|
+
(isReflectionType(param.type.valueType) && param.type.valueType.name === "EnumMember")) {
|
|
1346
|
+
reportDeprecatedLegacyMarshalling(param, "enum members");
|
|
1347
|
+
}
|
|
1348
|
+
else if (ignoreDiagnostics(isTypeAssignableTo(param.type.valueType, getStdType("numeric"), param.type.valueType)) &&
|
|
1349
|
+
!canNumericConstraintBeJsNumber(param.type.valueType)) {
|
|
1350
|
+
reportDeprecatedLegacyMarshalling(param, "a numeric type that is not representable as a JS Number");
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
959
1356
|
function checkFunctionDeclaration(node, mapper) {
|
|
960
1357
|
const symbol = getMergedSymbol(node.symbol);
|
|
961
1358
|
const links = getSymbolLinks(symbol);
|
|
@@ -978,7 +1375,7 @@ export function createChecker(program) {
|
|
|
978
1375
|
name,
|
|
979
1376
|
namespace,
|
|
980
1377
|
node,
|
|
981
|
-
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper)),
|
|
1378
|
+
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, true)),
|
|
982
1379
|
returnType: node.returnType ? getTypeForNode(node.returnType, mapper) : unknownType,
|
|
983
1380
|
implementation: implementation ?? (() => { }),
|
|
984
1381
|
});
|
|
@@ -986,7 +1383,7 @@ export function createChecker(program) {
|
|
|
986
1383
|
linkType(links, functionType, mapper);
|
|
987
1384
|
return functionType;
|
|
988
1385
|
}
|
|
989
|
-
function checkFunctionParameter(node, mapper) {
|
|
1386
|
+
function checkFunctionParameter(node, mapper, mixed) {
|
|
990
1387
|
const links = getSymbolLinks(node.symbol);
|
|
991
1388
|
if (links.declaredType) {
|
|
992
1389
|
return links.declaredType;
|
|
@@ -998,24 +1395,62 @@ export function createChecker(program) {
|
|
|
998
1395
|
node.type.target.kind === SyntaxKind.ArrayExpression))) {
|
|
999
1396
|
reportCheckerDiagnostic(createDiagnostic({ code: "rest-parameter-array", target: node.type }));
|
|
1000
1397
|
}
|
|
1001
|
-
const
|
|
1002
|
-
const parameterType = createType({
|
|
1398
|
+
const base = {
|
|
1003
1399
|
kind: "FunctionParameter",
|
|
1004
1400
|
node,
|
|
1005
1401
|
name: node.id.sv,
|
|
1006
1402
|
optional: node.optional,
|
|
1007
1403
|
rest: node.rest,
|
|
1008
|
-
type,
|
|
1009
1404
|
implementation: node.symbol.value,
|
|
1010
|
-
}
|
|
1405
|
+
};
|
|
1406
|
+
let parameterType;
|
|
1407
|
+
if (mixed) {
|
|
1408
|
+
const type = node.type
|
|
1409
|
+
? getParamConstraintEntityForNode(node.type)
|
|
1410
|
+
: ({
|
|
1411
|
+
entityKind: "MixedParameterConstraint",
|
|
1412
|
+
type: unknownType,
|
|
1413
|
+
});
|
|
1414
|
+
parameterType = createType({
|
|
1415
|
+
...base,
|
|
1416
|
+
type,
|
|
1417
|
+
mixed: true,
|
|
1418
|
+
implementation: node.symbol.value,
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
else {
|
|
1422
|
+
parameterType = createType({
|
|
1423
|
+
...base,
|
|
1424
|
+
mixed: false,
|
|
1425
|
+
type: node.type ? getTypeForNode(node.type) : unknownType,
|
|
1426
|
+
implementation: node.symbol.value,
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1011
1429
|
linkType(links, parameterType, mapper);
|
|
1012
1430
|
return parameterType;
|
|
1013
1431
|
}
|
|
1014
|
-
function
|
|
1015
|
-
|
|
1016
|
-
|
|
1432
|
+
function getTypeOrValueOfTypeForNode(node, mapper) {
|
|
1433
|
+
switch (node.kind) {
|
|
1434
|
+
case SyntaxKind.ValueOfExpression:
|
|
1435
|
+
const target = getTypeForNode(node.target, mapper);
|
|
1436
|
+
return ["value", target];
|
|
1437
|
+
default:
|
|
1438
|
+
return ["type", getTypeForNode(node, mapper)];
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
function getParamConstraintEntityForNode(node, mapper) {
|
|
1442
|
+
switch (node.kind) {
|
|
1443
|
+
case SyntaxKind.UnionExpression:
|
|
1444
|
+
return checkMixedParameterConstraintUnion(node, mapper);
|
|
1445
|
+
default:
|
|
1446
|
+
const [kind, entity] = getTypeOrValueOfTypeForNode(node, mapper);
|
|
1447
|
+
return {
|
|
1448
|
+
entityKind: "MixedParameterConstraint",
|
|
1449
|
+
node: node,
|
|
1450
|
+
type: kind === "value" ? undefined : entity,
|
|
1451
|
+
valueType: kind === "value" ? entity : undefined,
|
|
1452
|
+
};
|
|
1017
1453
|
}
|
|
1018
|
-
return getTypeForNode(node, mapper);
|
|
1019
1454
|
}
|
|
1020
1455
|
function mergeModelTypes(node, options, mapper) {
|
|
1021
1456
|
const properties = createRekeyableMap();
|
|
@@ -1104,7 +1539,7 @@ export function createChecker(program) {
|
|
|
1104
1539
|
}
|
|
1105
1540
|
if (node.kind === SyntaxKind.NamespaceStatement) {
|
|
1106
1541
|
if (isArray(node.statements)) {
|
|
1107
|
-
node.statements.forEach((x) =>
|
|
1542
|
+
node.statements.forEach((x) => checkNode(x));
|
|
1108
1543
|
}
|
|
1109
1544
|
else if (node.statements) {
|
|
1110
1545
|
const subNs = checkNamespace(node.statements);
|
|
@@ -1397,7 +1832,10 @@ export function createChecker(program) {
|
|
|
1397
1832
|
break;
|
|
1398
1833
|
}
|
|
1399
1834
|
compilerAssert(node.parent, "Parent expected.");
|
|
1400
|
-
const containerType =
|
|
1835
|
+
const containerType = getTypeOrValueForNode(node.parent, mapper);
|
|
1836
|
+
if (containerType === null || isValue(containerType)) {
|
|
1837
|
+
return undefined;
|
|
1838
|
+
}
|
|
1401
1839
|
if (isAnonymous(containerType)) {
|
|
1402
1840
|
return undefined; // member of anonymous type cannot be referenced.
|
|
1403
1841
|
}
|
|
@@ -1746,9 +2184,9 @@ export function createChecker(program) {
|
|
|
1746
2184
|
}));
|
|
1747
2185
|
return undefined;
|
|
1748
2186
|
}
|
|
1749
|
-
else if (base.flags &
|
|
2187
|
+
else if (base.flags & 682 /* SymbolFlags.MemberContainer */) {
|
|
1750
2188
|
if (options.checkTemplateTypes && isTemplatedNode(base.declarations[0])) {
|
|
1751
|
-
const type = base.flags &
|
|
2189
|
+
const type = base.flags & 67108864 /* SymbolFlags.LateBound */
|
|
1752
2190
|
? base.type
|
|
1753
2191
|
: getTypeForNode(base.declarations[0], mapper);
|
|
1754
2192
|
if (isTemplateInstance(type)) {
|
|
@@ -1863,17 +2301,112 @@ export function createChecker(program) {
|
|
|
1863
2301
|
}
|
|
1864
2302
|
}
|
|
1865
2303
|
function checkStringTemplateExpresion(node, mapper) {
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2304
|
+
let hasType = false;
|
|
2305
|
+
let hasValue = false;
|
|
2306
|
+
const spanTypeOrValues = node.spans.map((span) => [span, checkNode(span.expression, mapper)]);
|
|
2307
|
+
for (const [_, typeOrValue] of spanTypeOrValues) {
|
|
2308
|
+
if (typeOrValue !== null) {
|
|
2309
|
+
if (isValue(typeOrValue)) {
|
|
2310
|
+
hasValue = true;
|
|
2311
|
+
}
|
|
2312
|
+
else if ("kind" in typeOrValue && typeOrValue.kind === "TemplateParameter") {
|
|
2313
|
+
if (typeOrValue.constraint) {
|
|
2314
|
+
if (typeOrValue.constraint.valueType) {
|
|
2315
|
+
hasValue = true;
|
|
2316
|
+
}
|
|
2317
|
+
if (typeOrValue.constraint.type) {
|
|
2318
|
+
hasType = true;
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
else {
|
|
2322
|
+
hasType = true;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
else {
|
|
2326
|
+
hasType = true;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
if (hasType && hasValue) {
|
|
2331
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2332
|
+
code: "mixed-string-template",
|
|
2333
|
+
target: node,
|
|
2334
|
+
}));
|
|
2335
|
+
return null;
|
|
2336
|
+
}
|
|
2337
|
+
if (hasValue) {
|
|
2338
|
+
let str = node.head.value;
|
|
2339
|
+
for (const [span, typeOrValue] of spanTypeOrValues) {
|
|
2340
|
+
if (typeOrValue !== null &&
|
|
2341
|
+
(!("kind" in typeOrValue) || typeOrValue.kind !== "TemplateParameter")) {
|
|
2342
|
+
compilerAssert(typeOrValue !== null && isValue(typeOrValue), "Expected value.");
|
|
2343
|
+
str += stringifyValueForTemplate(typeOrValue);
|
|
2344
|
+
}
|
|
2345
|
+
str += span.literal.value;
|
|
2346
|
+
}
|
|
2347
|
+
return checkStringValue(createLiteralType(str), undefined, node);
|
|
2348
|
+
}
|
|
2349
|
+
else {
|
|
2350
|
+
let hasNonStringElement = false;
|
|
2351
|
+
let stringValue = node.head.value;
|
|
2352
|
+
const spans = [createTemplateSpanLiteral(node.head)];
|
|
2353
|
+
for (const [span, typeOrValue] of spanTypeOrValues) {
|
|
2354
|
+
compilerAssert(typeOrValue !== null && !isValue(typeOrValue), "Expected type.");
|
|
2355
|
+
const type = typeOrValue.entityKind === "Indeterminate" ? typeOrValue.type : typeOrValue;
|
|
2356
|
+
const spanValue = createTemplateSpanValue(span.expression, type);
|
|
2357
|
+
spans.push(spanValue);
|
|
2358
|
+
const spanValueAsString = stringifyTypeForTemplate(type);
|
|
2359
|
+
if (spanValueAsString) {
|
|
2360
|
+
stringValue += spanValueAsString;
|
|
2361
|
+
}
|
|
2362
|
+
else {
|
|
2363
|
+
hasNonStringElement = true;
|
|
2364
|
+
}
|
|
2365
|
+
spans.push(createTemplateSpanLiteral(span.literal));
|
|
2366
|
+
stringValue += span.literal.value;
|
|
2367
|
+
}
|
|
2368
|
+
return createIndeterminateEntity(createType({
|
|
2369
|
+
kind: "StringTemplate",
|
|
2370
|
+
node,
|
|
2371
|
+
spans,
|
|
2372
|
+
stringValue: hasNonStringElement ? undefined : stringValue,
|
|
2373
|
+
}));
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
function createIndeterminateEntity(type) {
|
|
2377
|
+
return {
|
|
2378
|
+
entityKind: "Indeterminate",
|
|
2379
|
+
type,
|
|
2380
|
+
};
|
|
2381
|
+
}
|
|
2382
|
+
function stringifyTypeForTemplate(type) {
|
|
2383
|
+
switch (type.kind) {
|
|
2384
|
+
case "String":
|
|
2385
|
+
case "Number":
|
|
2386
|
+
case "Boolean":
|
|
2387
|
+
return String(type.value);
|
|
2388
|
+
case "StringTemplate":
|
|
2389
|
+
if (type.stringValue !== undefined) {
|
|
2390
|
+
return type.stringValue;
|
|
2391
|
+
}
|
|
2392
|
+
return undefined;
|
|
2393
|
+
default:
|
|
2394
|
+
return undefined;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
function stringifyValueForTemplate(value) {
|
|
2398
|
+
switch (value.valueKind) {
|
|
2399
|
+
case "StringValue":
|
|
2400
|
+
case "NumericValue":
|
|
2401
|
+
case "BooleanValue":
|
|
2402
|
+
return value.value.toString();
|
|
2403
|
+
default:
|
|
2404
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2405
|
+
code: "non-literal-string-template",
|
|
2406
|
+
target: value,
|
|
2407
|
+
}));
|
|
2408
|
+
return `[${value.valueKind}]`;
|
|
1870
2409
|
}
|
|
1871
|
-
const type = createType({
|
|
1872
|
-
kind: "StringTemplate",
|
|
1873
|
-
node,
|
|
1874
|
-
spans,
|
|
1875
|
-
});
|
|
1876
|
-
return type;
|
|
1877
2410
|
}
|
|
1878
2411
|
function createTemplateSpanLiteral(node) {
|
|
1879
2412
|
return createType({
|
|
@@ -1883,22 +2416,31 @@ export function createChecker(program) {
|
|
|
1883
2416
|
type: getLiteralType(node),
|
|
1884
2417
|
});
|
|
1885
2418
|
}
|
|
1886
|
-
function createTemplateSpanValue(node,
|
|
2419
|
+
function createTemplateSpanValue(node, type) {
|
|
1887
2420
|
return createType({
|
|
1888
2421
|
kind: "StringTemplateSpan",
|
|
1889
2422
|
node: node,
|
|
1890
2423
|
isInterpolated: true,
|
|
1891
|
-
type:
|
|
2424
|
+
type: type,
|
|
1892
2425
|
});
|
|
1893
2426
|
}
|
|
1894
2427
|
function checkStringLiteral(str) {
|
|
1895
|
-
return
|
|
2428
|
+
return {
|
|
2429
|
+
entityKind: "Indeterminate",
|
|
2430
|
+
type: getLiteralType(str),
|
|
2431
|
+
};
|
|
1896
2432
|
}
|
|
1897
2433
|
function checkNumericLiteral(num) {
|
|
1898
|
-
return
|
|
2434
|
+
return {
|
|
2435
|
+
entityKind: "Indeterminate",
|
|
2436
|
+
type: getLiteralType(num),
|
|
2437
|
+
};
|
|
1899
2438
|
}
|
|
1900
2439
|
function checkBooleanLiteral(bool) {
|
|
1901
|
-
return
|
|
2440
|
+
return {
|
|
2441
|
+
entityKind: "Indeterminate",
|
|
2442
|
+
type: getLiteralType(bool),
|
|
2443
|
+
};
|
|
1902
2444
|
}
|
|
1903
2445
|
function checkProgram() {
|
|
1904
2446
|
program.reportDuplicateSymbols(globalNamespaceNode.symbol.exports);
|
|
@@ -1947,7 +2489,7 @@ export function createChecker(program) {
|
|
|
1947
2489
|
}
|
|
1948
2490
|
function checkSourceFile(file) {
|
|
1949
2491
|
for (const statement of file.statements) {
|
|
1950
|
-
|
|
2492
|
+
checkNode(statement, undefined);
|
|
1951
2493
|
}
|
|
1952
2494
|
}
|
|
1953
2495
|
/**
|
|
@@ -2056,7 +2598,8 @@ export function createChecker(program) {
|
|
|
2056
2598
|
return false;
|
|
2057
2599
|
}
|
|
2058
2600
|
// Some of the mapper args are still template parameter so we shouldn't create the type.
|
|
2059
|
-
return !mapper.partial &&
|
|
2601
|
+
return (!mapper.partial &&
|
|
2602
|
+
mapper.args.every((t) => isValue(t) || t.entityKind === "Indeterminate" || t.kind !== "TemplateParameter"));
|
|
2060
2603
|
}
|
|
2061
2604
|
function checkModelExpression(node, mapper) {
|
|
2062
2605
|
const properties = createRekeyableMap();
|
|
@@ -2149,6 +2692,414 @@ export function createChecker(program) {
|
|
|
2149
2692
|
};
|
|
2150
2693
|
}
|
|
2151
2694
|
}
|
|
2695
|
+
function checkObjectValue(node, mapper, constraint) {
|
|
2696
|
+
const properties = checkObjectLiteralProperties(node, mapper);
|
|
2697
|
+
if (properties === null) {
|
|
2698
|
+
return null;
|
|
2699
|
+
}
|
|
2700
|
+
const preciseType = createTypeForObjectValue(node, properties);
|
|
2701
|
+
if (constraint && !checkTypeOfValueMatchConstraint(preciseType, constraint, node)) {
|
|
2702
|
+
return null;
|
|
2703
|
+
}
|
|
2704
|
+
return {
|
|
2705
|
+
entityKind: "Value",
|
|
2706
|
+
valueKind: "ObjectValue",
|
|
2707
|
+
node: node,
|
|
2708
|
+
properties,
|
|
2709
|
+
type: constraint ? constraint.type : preciseType,
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
function createTypeForObjectValue(node, properties) {
|
|
2713
|
+
const model = createType({
|
|
2714
|
+
kind: "Model",
|
|
2715
|
+
name: "",
|
|
2716
|
+
node,
|
|
2717
|
+
properties: createRekeyableMap(),
|
|
2718
|
+
decorators: [],
|
|
2719
|
+
derivedModels: [],
|
|
2720
|
+
sourceModels: [],
|
|
2721
|
+
});
|
|
2722
|
+
for (const prop of properties.values()) {
|
|
2723
|
+
model.properties.set(prop.name, createModelPropertyForObjectPropertyDescriptor(prop, model));
|
|
2724
|
+
}
|
|
2725
|
+
return finishType(model);
|
|
2726
|
+
}
|
|
2727
|
+
function createModelPropertyForObjectPropertyDescriptor(prop, parentModel) {
|
|
2728
|
+
return createAndFinishType({
|
|
2729
|
+
kind: "ModelProperty",
|
|
2730
|
+
node: prop.node,
|
|
2731
|
+
model: parentModel,
|
|
2732
|
+
optional: false,
|
|
2733
|
+
name: prop.name,
|
|
2734
|
+
type: prop.value.type,
|
|
2735
|
+
decorators: [],
|
|
2736
|
+
});
|
|
2737
|
+
}
|
|
2738
|
+
function checkObjectLiteralProperties(node, mapper) {
|
|
2739
|
+
const properties = new Map();
|
|
2740
|
+
let hasError = false;
|
|
2741
|
+
for (const prop of node.properties) {
|
|
2742
|
+
if ("id" in prop) {
|
|
2743
|
+
const value = getValueForNode(prop.value, mapper);
|
|
2744
|
+
if (value === null) {
|
|
2745
|
+
hasError = true;
|
|
2746
|
+
}
|
|
2747
|
+
else {
|
|
2748
|
+
properties.set(prop.id.sv, { name: prop.id.sv, value: value, node: prop });
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
else {
|
|
2752
|
+
const targetType = checkObjectSpreadProperty(prop.target, mapper);
|
|
2753
|
+
if (targetType) {
|
|
2754
|
+
for (const [name, value] of targetType.properties) {
|
|
2755
|
+
properties.set(name, { ...value });
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
return hasError ? null : properties;
|
|
2761
|
+
}
|
|
2762
|
+
function checkObjectSpreadProperty(targetNode, mapper) {
|
|
2763
|
+
const value = getValueForNode(targetNode, mapper);
|
|
2764
|
+
if (value === null) {
|
|
2765
|
+
return null;
|
|
2766
|
+
}
|
|
2767
|
+
if (value.valueKind !== "ObjectValue") {
|
|
2768
|
+
reportCheckerDiagnostic(createDiagnostic({ code: "spread-object", target: targetNode }));
|
|
2769
|
+
return null;
|
|
2770
|
+
}
|
|
2771
|
+
return value;
|
|
2772
|
+
}
|
|
2773
|
+
function checkArrayValue(node, mapper, constraint) {
|
|
2774
|
+
let hasError = false;
|
|
2775
|
+
const values = node.values.map((itemNode) => {
|
|
2776
|
+
const value = getValueForNode(itemNode, mapper);
|
|
2777
|
+
if (value === null) {
|
|
2778
|
+
hasError = true;
|
|
2779
|
+
}
|
|
2780
|
+
return value;
|
|
2781
|
+
});
|
|
2782
|
+
if (hasError) {
|
|
2783
|
+
return null;
|
|
2784
|
+
}
|
|
2785
|
+
const preciseType = createTypeForArrayValue(node, values);
|
|
2786
|
+
if (constraint && !checkTypeOfValueMatchConstraint(preciseType, constraint, node)) {
|
|
2787
|
+
return null;
|
|
2788
|
+
}
|
|
2789
|
+
return {
|
|
2790
|
+
entityKind: "Value",
|
|
2791
|
+
valueKind: "ArrayValue",
|
|
2792
|
+
node: node,
|
|
2793
|
+
values: values,
|
|
2794
|
+
type: constraint ? constraint.type : preciseType,
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
function createTypeForArrayValue(node, values) {
|
|
2798
|
+
return createAndFinishType({
|
|
2799
|
+
kind: "Tuple",
|
|
2800
|
+
node,
|
|
2801
|
+
values: values.map((x) => x.type),
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
function inferScalarForPrimitiveValue(type, literalType) {
|
|
2805
|
+
if (type === undefined) {
|
|
2806
|
+
return undefined;
|
|
2807
|
+
}
|
|
2808
|
+
switch (type.kind) {
|
|
2809
|
+
case "Scalar":
|
|
2810
|
+
if (ignoreDiagnostics(isTypeAssignableTo(literalType, type, literalType))) {
|
|
2811
|
+
return type;
|
|
2812
|
+
}
|
|
2813
|
+
return undefined;
|
|
2814
|
+
case "Union":
|
|
2815
|
+
let found = undefined;
|
|
2816
|
+
for (const variant of type.variants.values()) {
|
|
2817
|
+
const scalar = inferScalarForPrimitiveValue(variant.type, literalType);
|
|
2818
|
+
if (scalar) {
|
|
2819
|
+
if (found) {
|
|
2820
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2821
|
+
code: "ambiguous-scalar-type",
|
|
2822
|
+
format: {
|
|
2823
|
+
value: getTypeName(literalType),
|
|
2824
|
+
types: [found, scalar].map((x) => x.name).join(", "),
|
|
2825
|
+
example: found.name,
|
|
2826
|
+
},
|
|
2827
|
+
target: literalType,
|
|
2828
|
+
}));
|
|
2829
|
+
return undefined;
|
|
2830
|
+
}
|
|
2831
|
+
else {
|
|
2832
|
+
found = scalar;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
return found;
|
|
2837
|
+
default:
|
|
2838
|
+
return undefined;
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
function checkStringValue(literalType, constraint, node) {
|
|
2842
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
2843
|
+
return null;
|
|
2844
|
+
}
|
|
2845
|
+
let value;
|
|
2846
|
+
if (literalType.kind === "StringTemplate") {
|
|
2847
|
+
if (literalType.stringValue) {
|
|
2848
|
+
value = literalType.stringValue;
|
|
2849
|
+
}
|
|
2850
|
+
else {
|
|
2851
|
+
reportCheckerDiagnostics(explainStringTemplateNotSerializable(literalType));
|
|
2852
|
+
return null;
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
else {
|
|
2856
|
+
value = literalType.value;
|
|
2857
|
+
}
|
|
2858
|
+
const scalar = inferScalarForPrimitiveValue(constraint?.type, literalType);
|
|
2859
|
+
return {
|
|
2860
|
+
entityKind: "Value",
|
|
2861
|
+
valueKind: "StringValue",
|
|
2862
|
+
value,
|
|
2863
|
+
type: constraint ? constraint.type : literalType,
|
|
2864
|
+
scalar,
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
function checkNumericValue(literalType, constraint, node) {
|
|
2868
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
2869
|
+
return null;
|
|
2870
|
+
}
|
|
2871
|
+
const scalar = inferScalarForPrimitiveValue(constraint?.type, literalType);
|
|
2872
|
+
return {
|
|
2873
|
+
entityKind: "Value",
|
|
2874
|
+
valueKind: "NumericValue",
|
|
2875
|
+
value: Numeric(literalType.valueAsString),
|
|
2876
|
+
type: constraint ? constraint.type : literalType,
|
|
2877
|
+
scalar,
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
function checkBooleanValue(literalType, constraint, node) {
|
|
2881
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
2882
|
+
return null;
|
|
2883
|
+
}
|
|
2884
|
+
const scalar = inferScalarForPrimitiveValue(constraint?.type, literalType);
|
|
2885
|
+
return {
|
|
2886
|
+
entityKind: "Value",
|
|
2887
|
+
valueKind: "BooleanValue",
|
|
2888
|
+
value: literalType.value,
|
|
2889
|
+
type: constraint ? constraint.type : literalType,
|
|
2890
|
+
scalar,
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2893
|
+
function checkNullValue(literalType, constraint, node) {
|
|
2894
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
2895
|
+
return null;
|
|
2896
|
+
}
|
|
2897
|
+
return {
|
|
2898
|
+
entityKind: "Value",
|
|
2899
|
+
valueKind: "NullValue",
|
|
2900
|
+
type: constraint ? constraint.type : literalType,
|
|
2901
|
+
value: null,
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
function checkEnumValue(literalType, constraint, node) {
|
|
2905
|
+
if (constraint && !checkTypeOfValueMatchConstraint(literalType, constraint, node)) {
|
|
2906
|
+
return null;
|
|
2907
|
+
}
|
|
2908
|
+
return {
|
|
2909
|
+
entityKind: "Value",
|
|
2910
|
+
valueKind: "EnumValue",
|
|
2911
|
+
type: constraint ? constraint.type : literalType,
|
|
2912
|
+
value: literalType,
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
function checkCallExpressionTarget(node, mapper) {
|
|
2916
|
+
const target = checkTypeReference(node.target, mapper);
|
|
2917
|
+
if (target.kind === "Scalar" || target.kind === "ScalarConstructor") {
|
|
2918
|
+
return target;
|
|
2919
|
+
}
|
|
2920
|
+
else {
|
|
2921
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2922
|
+
code: "non-callable",
|
|
2923
|
+
format: { type: target.kind },
|
|
2924
|
+
target: node.target,
|
|
2925
|
+
}));
|
|
2926
|
+
return null;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
/** Check the arguments of the call expression are a single value of the given syntax. */
|
|
2930
|
+
function checkPrimitiveArg(node, scalar, valueKind) {
|
|
2931
|
+
if (node.arguments.length !== 1) {
|
|
2932
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2933
|
+
code: "invalid-primitive-init",
|
|
2934
|
+
target: node.target,
|
|
2935
|
+
}));
|
|
2936
|
+
return null;
|
|
2937
|
+
}
|
|
2938
|
+
const argNode = node.arguments[0];
|
|
2939
|
+
const value = getValueForNode(argNode, undefined);
|
|
2940
|
+
if (value === null) {
|
|
2941
|
+
return null; // error should already have been reported above.
|
|
2942
|
+
}
|
|
2943
|
+
if (value.valueKind !== valueKind) {
|
|
2944
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2945
|
+
code: "invalid-primitive-init",
|
|
2946
|
+
messageId: "invalidArg",
|
|
2947
|
+
format: { actual: value.valueKind, expected: valueKind },
|
|
2948
|
+
target: argNode,
|
|
2949
|
+
}));
|
|
2950
|
+
return null;
|
|
2951
|
+
}
|
|
2952
|
+
if (!checkValueOfType(value, scalar, argNode)) {
|
|
2953
|
+
return null;
|
|
2954
|
+
}
|
|
2955
|
+
return { ...value, scalar, type: scalar };
|
|
2956
|
+
}
|
|
2957
|
+
function createScalarValue(node, mapper, declaration) {
|
|
2958
|
+
let hasError = false;
|
|
2959
|
+
const minArgs = declaration.parameters.filter((x) => !x.optional && !x.rest).length ?? 0;
|
|
2960
|
+
const maxArgs = declaration.parameters[declaration.parameters.length - 1]?.rest
|
|
2961
|
+
? undefined
|
|
2962
|
+
: declaration.parameters.length;
|
|
2963
|
+
if (node.arguments.length < minArgs ||
|
|
2964
|
+
(maxArgs !== undefined && node.arguments.length > maxArgs)) {
|
|
2965
|
+
// In the case we have too little args then this decorator is not applicable.
|
|
2966
|
+
// If there is too many args then we can still run the decorator as long as the args are valid.
|
|
2967
|
+
if (node.arguments.length < minArgs) {
|
|
2968
|
+
hasError = true;
|
|
2969
|
+
}
|
|
2970
|
+
if (maxArgs === undefined) {
|
|
2971
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2972
|
+
code: "invalid-argument-count",
|
|
2973
|
+
messageId: "atLeast",
|
|
2974
|
+
format: { actual: node.arguments.length.toString(), expected: minArgs.toString() },
|
|
2975
|
+
target: node,
|
|
2976
|
+
}));
|
|
2977
|
+
}
|
|
2978
|
+
else {
|
|
2979
|
+
const expected = minArgs === maxArgs ? minArgs.toString() : `${minArgs}-${maxArgs}`;
|
|
2980
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
2981
|
+
code: "invalid-argument-count",
|
|
2982
|
+
format: { actual: node.arguments.length.toString(), expected },
|
|
2983
|
+
target: node,
|
|
2984
|
+
}));
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
const resolvedArgs = [];
|
|
2988
|
+
for (const [index, parameter] of declaration.parameters.entries()) {
|
|
2989
|
+
if (parameter.rest) {
|
|
2990
|
+
const restType = getIndexType(parameter.type);
|
|
2991
|
+
if (restType) {
|
|
2992
|
+
for (let i = index; i < node.arguments.length; i++) {
|
|
2993
|
+
const argNode = node.arguments[i];
|
|
2994
|
+
if (argNode) {
|
|
2995
|
+
const arg = getValueForNode(argNode, mapper, { kind: "argument", type: restType });
|
|
2996
|
+
if (arg === null) {
|
|
2997
|
+
hasError = true;
|
|
2998
|
+
continue;
|
|
2999
|
+
}
|
|
3000
|
+
if (checkValueOfType(arg, restType, argNode)) {
|
|
3001
|
+
resolvedArgs.push(arg);
|
|
3002
|
+
}
|
|
3003
|
+
else {
|
|
3004
|
+
hasError = true;
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
break;
|
|
3010
|
+
}
|
|
3011
|
+
const argNode = node.arguments[index];
|
|
3012
|
+
if (argNode) {
|
|
3013
|
+
const arg = getValueForNode(argNode, mapper, {
|
|
3014
|
+
kind: "argument",
|
|
3015
|
+
type: parameter.type,
|
|
3016
|
+
});
|
|
3017
|
+
if (arg === null) {
|
|
3018
|
+
hasError = true;
|
|
3019
|
+
continue;
|
|
3020
|
+
}
|
|
3021
|
+
if (checkValueOfType(arg, parameter.type, argNode)) {
|
|
3022
|
+
resolvedArgs.push(arg);
|
|
3023
|
+
}
|
|
3024
|
+
else {
|
|
3025
|
+
hasError = true;
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
if (hasError) {
|
|
3030
|
+
return null;
|
|
3031
|
+
}
|
|
3032
|
+
return {
|
|
3033
|
+
entityKind: "Value",
|
|
3034
|
+
valueKind: "ScalarValue",
|
|
3035
|
+
value: {
|
|
3036
|
+
name: declaration.name,
|
|
3037
|
+
args: resolvedArgs,
|
|
3038
|
+
},
|
|
3039
|
+
scalar: declaration.scalar,
|
|
3040
|
+
type: declaration.scalar,
|
|
3041
|
+
};
|
|
3042
|
+
}
|
|
3043
|
+
function checkCallExpression(node, mapper) {
|
|
3044
|
+
const target = checkCallExpressionTarget(node, mapper);
|
|
3045
|
+
if (target === null) {
|
|
3046
|
+
return null;
|
|
3047
|
+
}
|
|
3048
|
+
if (target.kind === "ScalarConstructor") {
|
|
3049
|
+
return createScalarValue(node, mapper, target);
|
|
3050
|
+
}
|
|
3051
|
+
if (areScalarsRelated(target, getStdType("string"))) {
|
|
3052
|
+
return checkPrimitiveArg(node, target, "StringValue");
|
|
3053
|
+
}
|
|
3054
|
+
else if (areScalarsRelated(target, getStdType("numeric"))) {
|
|
3055
|
+
return checkPrimitiveArg(node, target, "NumericValue");
|
|
3056
|
+
}
|
|
3057
|
+
else if (areScalarsRelated(target, getStdType("boolean"))) {
|
|
3058
|
+
return checkPrimitiveArg(node, target, "BooleanValue");
|
|
3059
|
+
}
|
|
3060
|
+
else {
|
|
3061
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3062
|
+
code: "named-init-required",
|
|
3063
|
+
format: { typeKind: target.kind },
|
|
3064
|
+
target: node.target,
|
|
3065
|
+
}));
|
|
3066
|
+
return null;
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
function checkTypeOfExpression(node, mapper) {
|
|
3070
|
+
const entity = checkNode(node.target, mapper, undefined);
|
|
3071
|
+
if (entity === null) {
|
|
3072
|
+
// Shouldn't need to emit error as we assume null value already emitted error when produced
|
|
3073
|
+
return errorType;
|
|
3074
|
+
}
|
|
3075
|
+
if (entity.entityKind === "Indeterminate") {
|
|
3076
|
+
return entity.type;
|
|
3077
|
+
}
|
|
3078
|
+
if (isType(entity)) {
|
|
3079
|
+
if (entity.kind === "TemplateParameter") {
|
|
3080
|
+
if (entity.constraint === undefined || entity.constraint.type !== undefined) {
|
|
3081
|
+
// means this template constraint will accept values
|
|
3082
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3083
|
+
code: "expect-value",
|
|
3084
|
+
messageId: "templateConstraint",
|
|
3085
|
+
format: { name: getTypeName(entity) },
|
|
3086
|
+
target: node.target,
|
|
3087
|
+
}));
|
|
3088
|
+
return errorType;
|
|
3089
|
+
}
|
|
3090
|
+
else if (entity.constraint.valueType) {
|
|
3091
|
+
return entity.constraint.valueType;
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3095
|
+
code: "expect-value",
|
|
3096
|
+
format: { name: getTypeName(entity) },
|
|
3097
|
+
target: node.target,
|
|
3098
|
+
}));
|
|
3099
|
+
return entity;
|
|
3100
|
+
}
|
|
3101
|
+
return entity.type;
|
|
3102
|
+
}
|
|
2152
3103
|
function createUnion(options) {
|
|
2153
3104
|
const variants = createRekeyableMap();
|
|
2154
3105
|
const union = createAndFinishType({
|
|
@@ -2229,6 +3180,15 @@ export function createChecker(program) {
|
|
|
2229
3180
|
}
|
|
2230
3181
|
}
|
|
2231
3182
|
break;
|
|
3183
|
+
case SyntaxKind.ScalarStatement:
|
|
3184
|
+
if (node.extends && node.extends.kind === SyntaxKind.TypeReference) {
|
|
3185
|
+
resolveAndCopyMembers(node.extends);
|
|
3186
|
+
}
|
|
3187
|
+
for (const member of node.members) {
|
|
3188
|
+
const name = member.id.sv;
|
|
3189
|
+
bindMember(name, member, 33554432 /* SymbolFlags.ScalarMember */);
|
|
3190
|
+
}
|
|
3191
|
+
break;
|
|
2232
3192
|
case SyntaxKind.ModelExpression:
|
|
2233
3193
|
for (const prop of node.properties) {
|
|
2234
3194
|
if (prop.kind === SyntaxKind.ModelSpreadProperty) {
|
|
@@ -2356,7 +3316,7 @@ export function createChecker(program) {
|
|
|
2356
3316
|
const sigTable = getOrCreateAugmentedSymbolTable(sig.metatypeMembers);
|
|
2357
3317
|
const sigParameterSym = sigTable.get("parameters");
|
|
2358
3318
|
if (sigParameterSym !== undefined) {
|
|
2359
|
-
const parametersSym = createSymbol(sigParameterSym.declarations[0], "parameters", 2 /* SymbolFlags.Model */ &
|
|
3319
|
+
const parametersSym = createSymbol(sigParameterSym.declarations[0], "parameters", 2 /* SymbolFlags.Model */ & 682 /* SymbolFlags.MemberContainer */);
|
|
2360
3320
|
copyMembersToContainer(parametersSym, sigParameterSym.members);
|
|
2361
3321
|
table.set("parameters", parametersSym);
|
|
2362
3322
|
table.set("returnType", sigTable.get("returnType"));
|
|
@@ -2381,17 +3341,17 @@ export function createChecker(program) {
|
|
|
2381
3341
|
return;
|
|
2382
3342
|
switch (type.kind) {
|
|
2383
3343
|
case "Model":
|
|
2384
|
-
type.symbol = createSymbol(type.node, type.name, 2 /* SymbolFlags.Model */ |
|
|
3344
|
+
type.symbol = createSymbol(type.node, type.name, 2 /* SymbolFlags.Model */ | 67108864 /* SymbolFlags.LateBound */);
|
|
2385
3345
|
mutate(type.symbol).type = type;
|
|
2386
3346
|
break;
|
|
2387
3347
|
case "Interface":
|
|
2388
|
-
type.symbol = createSymbol(type.node, type.name, 128 /* SymbolFlags.Interface */ |
|
|
3348
|
+
type.symbol = createSymbol(type.node, type.name, 128 /* SymbolFlags.Interface */ | 67108864 /* SymbolFlags.LateBound */);
|
|
2389
3349
|
mutate(type.symbol).type = type;
|
|
2390
3350
|
break;
|
|
2391
3351
|
case "Union":
|
|
2392
3352
|
if (!type.name)
|
|
2393
3353
|
return; // don't make a symbol for anonymous unions
|
|
2394
|
-
type.symbol = createSymbol(type.node, type.name, 512 /* SymbolFlags.Union */ |
|
|
3354
|
+
type.symbol = createSymbol(type.node, type.name, 512 /* SymbolFlags.Union */ | 67108864 /* SymbolFlags.LateBound */);
|
|
2395
3355
|
mutate(type.symbol).type = type;
|
|
2396
3356
|
break;
|
|
2397
3357
|
}
|
|
@@ -2404,6 +3364,11 @@ export function createChecker(program) {
|
|
|
2404
3364
|
lateBindMember(prop, 4 /* SymbolFlags.ModelProperty */);
|
|
2405
3365
|
}
|
|
2406
3366
|
break;
|
|
3367
|
+
case "Scalar":
|
|
3368
|
+
for (const member of type.constructors.values()) {
|
|
3369
|
+
lateBindMember(member, 33555780 /* SymbolFlags.Member */);
|
|
3370
|
+
}
|
|
3371
|
+
break;
|
|
2407
3372
|
case "Enum":
|
|
2408
3373
|
for (const member of type.members.values()) {
|
|
2409
3374
|
lateBindMember(member, 64 /* SymbolFlags.EnumMember */);
|
|
@@ -2425,7 +3390,7 @@ export function createChecker(program) {
|
|
|
2425
3390
|
// don't bind anything for union expressions
|
|
2426
3391
|
return;
|
|
2427
3392
|
}
|
|
2428
|
-
const sym = createSymbol(member.node, member.name, kind |
|
|
3393
|
+
const sym = createSymbol(member.node, member.name, kind | 67108864 /* SymbolFlags.LateBound */, containerSym);
|
|
2429
3394
|
mutate(sym).type = member;
|
|
2430
3395
|
compilerAssert(containerSym.members, "containerSym.members is undefined");
|
|
2431
3396
|
containerMembers ??= getOrCreateAugmentedSymbolTable(containerSym.members);
|
|
@@ -2611,7 +3576,14 @@ export function createChecker(program) {
|
|
|
2611
3576
|
else {
|
|
2612
3577
|
pendingResolutions.start(symId, ResolutionKind.Type);
|
|
2613
3578
|
type.type = getTypeForNode(prop.value, mapper);
|
|
2614
|
-
|
|
3579
|
+
if (prop.default) {
|
|
3580
|
+
const defaultValue = checkDefaultValue(prop.default, type.type);
|
|
3581
|
+
if (defaultValue !== null) {
|
|
3582
|
+
type.defaultValue = defaultValue;
|
|
3583
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
3584
|
+
type.default = checkLegacyDefault(prop.default);
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
2615
3587
|
if (links) {
|
|
2616
3588
|
linkType(links, type, mapper);
|
|
2617
3589
|
}
|
|
@@ -2641,43 +3613,42 @@ export function createChecker(program) {
|
|
|
2641
3613
|
],
|
|
2642
3614
|
};
|
|
2643
3615
|
}
|
|
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);
|
|
3616
|
+
function checkDefaultValue(defaultNode, type) {
|
|
2660
3617
|
if (isErrorType(type)) {
|
|
2661
|
-
|
|
3618
|
+
// if the prop type is an error we don't need to validate again.
|
|
3619
|
+
return null;
|
|
2662
3620
|
}
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
return errorType;
|
|
3621
|
+
const defaultValue = getValueForNode(defaultNode, undefined, {
|
|
3622
|
+
kind: "assignment",
|
|
3623
|
+
type,
|
|
3624
|
+
}, { legacyTupleAndModelCast: true });
|
|
3625
|
+
if (defaultValue === null) {
|
|
3626
|
+
return null;
|
|
2670
3627
|
}
|
|
2671
|
-
const [related, diagnostics] =
|
|
3628
|
+
const [related, diagnostics] = isValueOfType(defaultValue, type, defaultNode);
|
|
2672
3629
|
if (!related) {
|
|
2673
3630
|
reportCheckerDiagnostics(diagnostics);
|
|
2674
|
-
return
|
|
3631
|
+
return null;
|
|
2675
3632
|
}
|
|
2676
3633
|
else {
|
|
2677
|
-
return
|
|
3634
|
+
return { ...defaultValue, type };
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
/**
|
|
3638
|
+
* Fill in the legacy `.default` property.
|
|
3639
|
+
* We do do checking here we just keep existing behavior.
|
|
3640
|
+
*/
|
|
3641
|
+
function checkLegacyDefault(defaultNode) {
|
|
3642
|
+
const resolved = checkNode(defaultNode, undefined);
|
|
3643
|
+
if (resolved === null || isValue(resolved)) {
|
|
3644
|
+
return undefined;
|
|
2678
3645
|
}
|
|
3646
|
+
if (resolved.entityKind === "Indeterminate") {
|
|
3647
|
+
return resolved.type;
|
|
3648
|
+
}
|
|
3649
|
+
return resolved;
|
|
2679
3650
|
}
|
|
2680
|
-
function
|
|
3651
|
+
function checkDecoratorApplication(targetType, decNode, mapper) {
|
|
2681
3652
|
const sym = resolveTypeReferenceSym(decNode.target, undefined, true);
|
|
2682
3653
|
if (!sym) {
|
|
2683
3654
|
reportCheckerDiagnostic(createDiagnostic({
|
|
@@ -2695,7 +3666,6 @@ export function createChecker(program) {
|
|
|
2695
3666
|
return undefined;
|
|
2696
3667
|
}
|
|
2697
3668
|
const symbolLinks = getSymbolLinks(sym);
|
|
2698
|
-
let args = checkDecoratorArguments(decNode, mapper);
|
|
2699
3669
|
let hasError = false;
|
|
2700
3670
|
if (symbolLinks.declaredType === undefined) {
|
|
2701
3671
|
const decoratorDeclNode = sym.declarations.find((x) => x.kind === SyntaxKind.DecoratorDeclarationStatement);
|
|
@@ -2705,10 +3675,12 @@ export function createChecker(program) {
|
|
|
2705
3675
|
}
|
|
2706
3676
|
if (symbolLinks.declaredType) {
|
|
2707
3677
|
compilerAssert(symbolLinks.declaredType.kind === "Decorator", "Expected to find a decorator type.");
|
|
2708
|
-
|
|
2709
|
-
|
|
3678
|
+
if (!checkDecoratorTarget(targetType, symbolLinks.declaredType, decNode)) {
|
|
3679
|
+
hasError = true;
|
|
3680
|
+
}
|
|
2710
3681
|
}
|
|
2711
|
-
|
|
3682
|
+
const [argsHaveError, args] = checkDecoratorArguments(decNode, mapper, symbolLinks.declaredType);
|
|
3683
|
+
if (hasError || argsHaveError) {
|
|
2712
3684
|
return undefined;
|
|
2713
3685
|
}
|
|
2714
3686
|
return {
|
|
@@ -2718,62 +3690,121 @@ export function createChecker(program) {
|
|
|
2718
3690
|
args,
|
|
2719
3691
|
};
|
|
2720
3692
|
}
|
|
2721
|
-
function
|
|
2722
|
-
|
|
3693
|
+
function resolveDecoratorArgMarshalling(declaredType) {
|
|
3694
|
+
if (declaredType) {
|
|
3695
|
+
const location = getLocationContext(program, declaredType);
|
|
3696
|
+
if (location.type === "compiler") {
|
|
3697
|
+
return "new";
|
|
3698
|
+
}
|
|
3699
|
+
else if ((location.type === "library" || location.type === "project") &&
|
|
3700
|
+
location.flags?.decoratorArgMarshalling) {
|
|
3701
|
+
return location.flags.decoratorArgMarshalling;
|
|
3702
|
+
}
|
|
3703
|
+
else {
|
|
3704
|
+
return "legacy";
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
return "new";
|
|
3708
|
+
}
|
|
3709
|
+
/** Check the decorator target is valid */
|
|
3710
|
+
function checkDecoratorTarget(targetType, declaration, decoratorNode) {
|
|
2723
3711
|
const [targetValid] = isTypeAssignableTo(targetType, declaration.target.type, decoratorNode);
|
|
2724
3712
|
if (!targetValid) {
|
|
2725
|
-
hasError = true;
|
|
2726
3713
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2727
3714
|
code: "decorator-wrong-target",
|
|
2728
3715
|
messageId: "withExpected",
|
|
2729
3716
|
format: {
|
|
2730
3717
|
decorator: declaration.name,
|
|
2731
3718
|
to: getTypeName(targetType),
|
|
2732
|
-
expected:
|
|
3719
|
+
expected: getEntityName(declaration.target.type),
|
|
2733
3720
|
},
|
|
2734
3721
|
target: decoratorNode,
|
|
2735
3722
|
}));
|
|
2736
3723
|
}
|
|
2737
|
-
|
|
3724
|
+
return targetValid;
|
|
3725
|
+
}
|
|
3726
|
+
function checkDecoratorArguments(node, mapper, declaration) {
|
|
3727
|
+
// if we don't have a declaration we can just return the types or values if
|
|
3728
|
+
if (declaration === undefined) {
|
|
3729
|
+
return [
|
|
3730
|
+
false,
|
|
3731
|
+
node.arguments.map((argNode) => {
|
|
3732
|
+
let type = checkNode(argNode, mapper) ?? errorType;
|
|
3733
|
+
if (type.entityKind === "Indeterminate") {
|
|
3734
|
+
type = type.type;
|
|
3735
|
+
}
|
|
3736
|
+
return {
|
|
3737
|
+
value: type,
|
|
3738
|
+
jsValue: type,
|
|
3739
|
+
node: argNode,
|
|
3740
|
+
};
|
|
3741
|
+
}),
|
|
3742
|
+
];
|
|
3743
|
+
}
|
|
3744
|
+
let hasError = false;
|
|
3745
|
+
const minArgs = declaration.parameters.filter((x) => !x.optional && !x.rest).length ?? 0;
|
|
2738
3746
|
const maxArgs = declaration.parameters[declaration.parameters.length - 1]?.rest
|
|
2739
3747
|
? undefined
|
|
2740
3748
|
: declaration.parameters.length;
|
|
2741
|
-
if (
|
|
3749
|
+
if (node.arguments.length < minArgs ||
|
|
3750
|
+
(maxArgs !== undefined && node.arguments.length > maxArgs)) {
|
|
2742
3751
|
// In the case we have too little args then this decorator is not applicable.
|
|
2743
3752
|
// If there is too many args then we can still run the decorator as long as the args are valid.
|
|
2744
|
-
if (
|
|
3753
|
+
if (node.arguments.length < minArgs) {
|
|
2745
3754
|
hasError = true;
|
|
2746
3755
|
}
|
|
2747
3756
|
if (maxArgs === undefined) {
|
|
2748
3757
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2749
3758
|
code: "invalid-argument-count",
|
|
2750
3759
|
messageId: "atLeast",
|
|
2751
|
-
format: { actual:
|
|
2752
|
-
target:
|
|
3760
|
+
format: { actual: node.arguments.length.toString(), expected: minArgs.toString() },
|
|
3761
|
+
target: node,
|
|
2753
3762
|
}));
|
|
2754
3763
|
}
|
|
2755
3764
|
else {
|
|
2756
3765
|
const expected = minArgs === maxArgs ? minArgs.toString() : `${minArgs}-${maxArgs}`;
|
|
2757
3766
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2758
3767
|
code: "invalid-argument-count",
|
|
2759
|
-
format: { actual:
|
|
2760
|
-
target:
|
|
3768
|
+
format: { actual: node.arguments.length.toString(), expected },
|
|
3769
|
+
target: node,
|
|
2761
3770
|
}));
|
|
2762
3771
|
}
|
|
2763
3772
|
}
|
|
2764
3773
|
const resolvedArgs = [];
|
|
3774
|
+
const jsMarshalling = resolveDecoratorArgMarshalling(declaration);
|
|
3775
|
+
function resolveArg(argNode, perParamType) {
|
|
3776
|
+
const arg = getTypeOrValueForNode(argNode, mapper, {
|
|
3777
|
+
kind: "argument",
|
|
3778
|
+
constraint: perParamType,
|
|
3779
|
+
});
|
|
3780
|
+
if (arg !== null &&
|
|
3781
|
+
!(isType(arg) && isErrorType(arg)) &&
|
|
3782
|
+
checkArgumentAssignable(arg, perParamType, argNode)) {
|
|
3783
|
+
return {
|
|
3784
|
+
value: arg,
|
|
3785
|
+
node: argNode,
|
|
3786
|
+
jsValue: resolveDecoratorArgJsValue(arg, extractValueOfConstraints({
|
|
3787
|
+
kind: "argument",
|
|
3788
|
+
constraint: perParamType,
|
|
3789
|
+
}), jsMarshalling),
|
|
3790
|
+
};
|
|
3791
|
+
}
|
|
3792
|
+
else {
|
|
3793
|
+
return undefined;
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
2765
3796
|
for (const [index, parameter] of declaration.parameters.entries()) {
|
|
2766
3797
|
if (parameter.rest) {
|
|
2767
|
-
const restType =
|
|
3798
|
+
const restType = extractRestParamConstraint(parameter.type);
|
|
2768
3799
|
if (restType) {
|
|
2769
|
-
for (let i = index; i <
|
|
2770
|
-
const
|
|
2771
|
-
if (
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
}
|
|
2776
|
-
|
|
3800
|
+
for (let i = index; i < node.arguments.length; i++) {
|
|
3801
|
+
const argNode = node.arguments[i];
|
|
3802
|
+
if (argNode) {
|
|
3803
|
+
const arg = resolveArg(argNode, restType);
|
|
3804
|
+
if (arg) {
|
|
3805
|
+
resolvedArgs.push(arg);
|
|
3806
|
+
}
|
|
3807
|
+
else {
|
|
2777
3808
|
hasError = true;
|
|
2778
3809
|
}
|
|
2779
3810
|
}
|
|
@@ -2781,29 +3812,58 @@ export function createChecker(program) {
|
|
|
2781
3812
|
}
|
|
2782
3813
|
break;
|
|
2783
3814
|
}
|
|
2784
|
-
const
|
|
2785
|
-
if (
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
}
|
|
2790
|
-
|
|
3815
|
+
const argNode = node.arguments[index];
|
|
3816
|
+
if (argNode) {
|
|
3817
|
+
const arg = resolveArg(argNode, parameter.type);
|
|
3818
|
+
if (arg) {
|
|
3819
|
+
resolvedArgs.push(arg);
|
|
3820
|
+
}
|
|
3821
|
+
else {
|
|
2791
3822
|
hasError = true;
|
|
2792
3823
|
}
|
|
2793
3824
|
}
|
|
2794
3825
|
}
|
|
2795
3826
|
return [hasError, resolvedArgs];
|
|
2796
3827
|
}
|
|
3828
|
+
/** For a rest param of constraint T[] or valueof T[] return the T or valueof T */
|
|
3829
|
+
function extractRestParamConstraint(constraint) {
|
|
3830
|
+
let valueType;
|
|
3831
|
+
let type;
|
|
3832
|
+
if (constraint.valueType) {
|
|
3833
|
+
if (constraint.valueType.kind === "Model" &&
|
|
3834
|
+
isArrayModelType(program, constraint.valueType)) {
|
|
3835
|
+
valueType = constraint.valueType.indexer.value;
|
|
3836
|
+
}
|
|
3837
|
+
else {
|
|
3838
|
+
return undefined;
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
if (constraint.type) {
|
|
3842
|
+
if (constraint.type.kind === "Model" && isArrayModelType(program, constraint.type)) {
|
|
3843
|
+
type = constraint.type.indexer.value;
|
|
3844
|
+
}
|
|
3845
|
+
else {
|
|
3846
|
+
return undefined;
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
return {
|
|
3850
|
+
entityKind: "MixedParameterConstraint",
|
|
3851
|
+
type,
|
|
3852
|
+
valueType,
|
|
3853
|
+
};
|
|
3854
|
+
}
|
|
2797
3855
|
function getIndexType(type) {
|
|
2798
3856
|
return type.kind === "Model" ? type.indexer?.value : undefined;
|
|
2799
3857
|
}
|
|
2800
|
-
function resolveDecoratorArgJsValue(value,
|
|
2801
|
-
if (
|
|
2802
|
-
if (value
|
|
2803
|
-
return
|
|
3858
|
+
function resolveDecoratorArgJsValue(value, valueConstraint, jsMarshalling) {
|
|
3859
|
+
if (valueConstraint !== undefined) {
|
|
3860
|
+
if (isValue(value)) {
|
|
3861
|
+
return jsMarshalling === "legacy"
|
|
3862
|
+
? legacyMarshallTypeForJS(checker, value)
|
|
3863
|
+
: marshallTypeForJS(value, valueConstraint.type);
|
|
2804
3864
|
}
|
|
2805
|
-
else
|
|
2806
|
-
return
|
|
3865
|
+
else {
|
|
3866
|
+
return value;
|
|
2807
3867
|
}
|
|
2808
3868
|
}
|
|
2809
3869
|
return value;
|
|
@@ -2814,8 +3874,8 @@ export function createChecker(program) {
|
|
|
2814
3874
|
reportCheckerDiagnostic(createDiagnostic({
|
|
2815
3875
|
code: "invalid-argument",
|
|
2816
3876
|
format: {
|
|
2817
|
-
value:
|
|
2818
|
-
expected:
|
|
3877
|
+
value: getEntityName(argumentType),
|
|
3878
|
+
expected: getEntityName(parameterType),
|
|
2819
3879
|
},
|
|
2820
3880
|
target: diagnosticTarget,
|
|
2821
3881
|
}));
|
|
@@ -2826,7 +3886,7 @@ export function createChecker(program) {
|
|
|
2826
3886
|
const augmentDecoratorNodes = augmentDecoratorsForSym.get(sym) ?? [];
|
|
2827
3887
|
const decorators = [];
|
|
2828
3888
|
for (const decNode of augmentDecoratorNodes) {
|
|
2829
|
-
const decorator =
|
|
3889
|
+
const decorator = checkDecoratorApplication(targetType, decNode, mapper);
|
|
2830
3890
|
if (decorator) {
|
|
2831
3891
|
decorators.unshift(decorator);
|
|
2832
3892
|
}
|
|
@@ -2842,7 +3902,7 @@ export function createChecker(program) {
|
|
|
2842
3902
|
...node.decorators,
|
|
2843
3903
|
];
|
|
2844
3904
|
for (const decNode of decoratorNodes) {
|
|
2845
|
-
const decorator =
|
|
3905
|
+
const decorator = checkDecoratorApplication(targetType, decNode, mapper);
|
|
2846
3906
|
if (decorator) {
|
|
2847
3907
|
decorators.unshift(decorator);
|
|
2848
3908
|
}
|
|
@@ -2863,16 +3923,6 @@ export function createChecker(program) {
|
|
|
2863
3923
|
}
|
|
2864
3924
|
return decorators;
|
|
2865
3925
|
}
|
|
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
3926
|
function checkScalar(node, mapper) {
|
|
2877
3927
|
const links = getSymbolLinks(node.symbol);
|
|
2878
3928
|
if (links.declaredType && mapper === undefined) {
|
|
@@ -2885,10 +3935,12 @@ export function createChecker(program) {
|
|
|
2885
3935
|
kind: "Scalar",
|
|
2886
3936
|
name: node.id.sv,
|
|
2887
3937
|
node: node,
|
|
3938
|
+
constructors: new Map(),
|
|
2888
3939
|
namespace: getParentNamespaceType(node),
|
|
2889
3940
|
decorators,
|
|
2890
3941
|
derivedScalars: [],
|
|
2891
3942
|
});
|
|
3943
|
+
checkScalarConstructors(type, node, type.constructors, mapper);
|
|
2892
3944
|
linkType(links, type, mapper);
|
|
2893
3945
|
if (node.extends) {
|
|
2894
3946
|
type.baseScalar = checkScalarExtends(node, node.extends, mapper);
|
|
@@ -2939,6 +3991,43 @@ export function createChecker(program) {
|
|
|
2939
3991
|
}
|
|
2940
3992
|
return extendsType;
|
|
2941
3993
|
}
|
|
3994
|
+
function checkScalarConstructors(parentScalar, node, constructors, mapper) {
|
|
3995
|
+
for (const member of node.members) {
|
|
3996
|
+
const constructor = checkScalarConstructor(member, mapper, parentScalar);
|
|
3997
|
+
if (constructors.has(constructor.name)) {
|
|
3998
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
3999
|
+
code: "constructor-duplicate",
|
|
4000
|
+
format: { name: constructor.name.toString() },
|
|
4001
|
+
target: member,
|
|
4002
|
+
}));
|
|
4003
|
+
continue;
|
|
4004
|
+
}
|
|
4005
|
+
constructors.set(constructor.name, constructor);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
function checkScalarConstructor(node, mapper, parentScalar) {
|
|
4009
|
+
const name = node.id.sv;
|
|
4010
|
+
const links = getSymbolLinksForMember(node);
|
|
4011
|
+
if (links && links.declaredType && mapper === undefined) {
|
|
4012
|
+
// we're not instantiating this scalar constructor and we've already checked it
|
|
4013
|
+
return links.declaredType;
|
|
4014
|
+
}
|
|
4015
|
+
const member = createType({
|
|
4016
|
+
kind: "ScalarConstructor",
|
|
4017
|
+
scalar: parentScalar,
|
|
4018
|
+
name,
|
|
4019
|
+
node,
|
|
4020
|
+
parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, false)),
|
|
4021
|
+
});
|
|
4022
|
+
linkMapper(member, mapper);
|
|
4023
|
+
if (shouldCreateTypeForTemplate(node.parent, mapper)) {
|
|
4024
|
+
finishType(member);
|
|
4025
|
+
}
|
|
4026
|
+
if (links) {
|
|
4027
|
+
linkType(links, member, mapper);
|
|
4028
|
+
}
|
|
4029
|
+
return finishType(member);
|
|
4030
|
+
}
|
|
2942
4031
|
function checkAlias(node, mapper) {
|
|
2943
4032
|
const links = getSymbolLinks(node.symbol);
|
|
2944
4033
|
if (links.declaredType && mapper === undefined) {
|
|
@@ -2959,10 +4048,55 @@ export function createChecker(program) {
|
|
|
2959
4048
|
}
|
|
2960
4049
|
pendingResolutions.start(aliasSymId, ResolutionKind.Type);
|
|
2961
4050
|
const type = getTypeForNode(node.value, mapper);
|
|
2962
|
-
|
|
4051
|
+
if (!isValue(type)) {
|
|
4052
|
+
linkType(links, type, mapper);
|
|
4053
|
+
}
|
|
2963
4054
|
pendingResolutions.finish(aliasSymId, ResolutionKind.Type);
|
|
2964
4055
|
return type;
|
|
2965
4056
|
}
|
|
4057
|
+
function checkConst(node) {
|
|
4058
|
+
const links = getSymbolLinks(node.symbol);
|
|
4059
|
+
if (links.value !== undefined) {
|
|
4060
|
+
return links.value;
|
|
4061
|
+
}
|
|
4062
|
+
const type = node.type ? getTypeForNode(node.type, undefined) : undefined;
|
|
4063
|
+
const symId = getSymbolId(node.symbol);
|
|
4064
|
+
if (pendingResolutions.has(symId, ResolutionKind.Value)) {
|
|
4065
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
4066
|
+
code: "circular-const",
|
|
4067
|
+
format: { name: node.id.sv },
|
|
4068
|
+
target: node,
|
|
4069
|
+
}));
|
|
4070
|
+
return null;
|
|
4071
|
+
}
|
|
4072
|
+
pendingResolutions.start(symId, ResolutionKind.Value);
|
|
4073
|
+
const value = getValueForNode(node.value, undefined, type && { kind: "assignment", type });
|
|
4074
|
+
pendingResolutions.finish(symId, ResolutionKind.Value);
|
|
4075
|
+
if (value === null || (type && !checkValueOfType(value, type, node.id))) {
|
|
4076
|
+
links.value = null;
|
|
4077
|
+
return links.value;
|
|
4078
|
+
}
|
|
4079
|
+
links.value = type ? { ...value, type } : { ...value };
|
|
4080
|
+
return links.value;
|
|
4081
|
+
}
|
|
4082
|
+
function inferScalarsFromConstraints(value, type) {
|
|
4083
|
+
switch (value.valueKind) {
|
|
4084
|
+
case "BooleanValue":
|
|
4085
|
+
case "StringValue":
|
|
4086
|
+
case "NumericValue":
|
|
4087
|
+
if (value.scalar === undefined) {
|
|
4088
|
+
const scalar = inferScalarForPrimitiveValue(type, value.type);
|
|
4089
|
+
return { ...value, scalar };
|
|
4090
|
+
}
|
|
4091
|
+
return value;
|
|
4092
|
+
case "ArrayValue":
|
|
4093
|
+
case "ObjectValue":
|
|
4094
|
+
case "EnumValue":
|
|
4095
|
+
case "NullValue":
|
|
4096
|
+
case "ScalarValue":
|
|
4097
|
+
return value;
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
2966
4100
|
function checkEnum(node, mapper) {
|
|
2967
4101
|
const links = getSymbolLinks(node.symbol);
|
|
2968
4102
|
if (!links.type) {
|
|
@@ -3279,6 +4413,7 @@ export function createChecker(program) {
|
|
|
3279
4413
|
// If the type has an associated syntax node, check any directives that
|
|
3280
4414
|
// might be attached.
|
|
3281
4415
|
const createdType = typeDef;
|
|
4416
|
+
createdType.entityKind = "Type";
|
|
3282
4417
|
if (createdType.node) {
|
|
3283
4418
|
checkDirectives(createdType.node, createdType);
|
|
3284
4419
|
}
|
|
@@ -4024,6 +5159,7 @@ export function createChecker(program) {
|
|
|
4024
5159
|
kind: "Number",
|
|
4025
5160
|
value,
|
|
4026
5161
|
valueAsString,
|
|
5162
|
+
numericValue: Numeric(valueAsString),
|
|
4027
5163
|
});
|
|
4028
5164
|
break;
|
|
4029
5165
|
}
|
|
@@ -4036,7 +5172,7 @@ export function createChecker(program) {
|
|
|
4036
5172
|
throw new ProjectionError("Can't find decorator.");
|
|
4037
5173
|
compilerAssert(ref.flags & 16384 /* SymbolFlags.Decorator */, "should only resolve decorator symbols");
|
|
4038
5174
|
return createFunctionType((...args) => {
|
|
4039
|
-
ref.value({ program }, ...
|
|
5175
|
+
ref.value({ program }, ...args.map(unsafe_projectionArgumentMarshalForJS));
|
|
4040
5176
|
return voidType;
|
|
4041
5177
|
});
|
|
4042
5178
|
}
|
|
@@ -4061,7 +5197,7 @@ export function createChecker(program) {
|
|
|
4061
5197
|
else if (ref.flags & 131072 /* SymbolFlags.Function */) {
|
|
4062
5198
|
// TODO: store this in a symbol link probably?
|
|
4063
5199
|
const t = createFunctionType((...args) => {
|
|
4064
|
-
const retval = ref.value(program, ...
|
|
5200
|
+
const retval = ref.value(program, ...args.map(unsafe_projectionArgumentMarshalForJS));
|
|
4065
5201
|
return marshalProjectionReturn(retval, { functionName: node.sv });
|
|
4066
5202
|
});
|
|
4067
5203
|
return t;
|
|
@@ -4135,6 +5271,31 @@ export function createChecker(program) {
|
|
|
4135
5271
|
parts.push(current.sv);
|
|
4136
5272
|
return parts.reverse().join(".");
|
|
4137
5273
|
}
|
|
5274
|
+
/**
|
|
5275
|
+
* Check if the source type can be assigned to the target type and emit diagnostics
|
|
5276
|
+
* @param source Type of a value
|
|
5277
|
+
* @param constraint
|
|
5278
|
+
* @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
|
|
5279
|
+
*/
|
|
5280
|
+
function checkTypeOfValueMatchConstraint(source, constraint, diagnosticTarget) {
|
|
5281
|
+
const [related, diagnostics] = isTypeAssignableTo(source, constraint.type, diagnosticTarget);
|
|
5282
|
+
if (!related) {
|
|
5283
|
+
if (constraint.kind === "argument") {
|
|
5284
|
+
reportCheckerDiagnostic(createDiagnostic({
|
|
5285
|
+
code: "invalid-argument",
|
|
5286
|
+
format: {
|
|
5287
|
+
value: getEntityName(source),
|
|
5288
|
+
expected: getEntityName(constraint.type),
|
|
5289
|
+
},
|
|
5290
|
+
target: diagnosticTarget,
|
|
5291
|
+
}));
|
|
5292
|
+
}
|
|
5293
|
+
else {
|
|
5294
|
+
reportCheckerDiagnostics(diagnostics);
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5297
|
+
return related;
|
|
5298
|
+
}
|
|
4138
5299
|
/**
|
|
4139
5300
|
* Check if the source type can be assigned to the target type and emit diagnostics
|
|
4140
5301
|
* @param source Source type
|
|
@@ -4148,6 +5309,13 @@ export function createChecker(program) {
|
|
|
4148
5309
|
}
|
|
4149
5310
|
return related;
|
|
4150
5311
|
}
|
|
5312
|
+
function checkValueOfType(source, target, diagnosticTarget) {
|
|
5313
|
+
const [related, diagnostics] = isValueOfType(source, target, diagnosticTarget);
|
|
5314
|
+
if (!related) {
|
|
5315
|
+
reportCheckerDiagnostics(diagnostics);
|
|
5316
|
+
}
|
|
5317
|
+
return related;
|
|
5318
|
+
}
|
|
4151
5319
|
/**
|
|
4152
5320
|
* Check if the source type can be assigned to the target type.
|
|
4153
5321
|
* @param source Source type
|
|
@@ -4158,6 +5326,16 @@ export function createChecker(program) {
|
|
|
4158
5326
|
const [related, diagnostics] = isTypeAssignableToInternal(source, target, diagnosticTarget, new MultiKeyMap());
|
|
4159
5327
|
return [related === Related.true, diagnostics];
|
|
4160
5328
|
}
|
|
5329
|
+
/**
|
|
5330
|
+
* Check if the given Value type is of the given type.
|
|
5331
|
+
* @param source Value
|
|
5332
|
+
* @param target Target type
|
|
5333
|
+
* @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
|
|
5334
|
+
*/
|
|
5335
|
+
function isValueOfType(source, target, diagnosticTarget) {
|
|
5336
|
+
const [related, diagnostics] = isValueOfTypeInternal(source, target, diagnosticTarget, new MultiKeyMap());
|
|
5337
|
+
return [related === Related.true, diagnostics];
|
|
5338
|
+
}
|
|
4161
5339
|
function isTypeAssignableToInternal(source, target, diagnosticTarget, relationCache) {
|
|
4162
5340
|
const cached = relationCache.get([source, target]);
|
|
4163
5341
|
if (cached !== undefined) {
|
|
@@ -4168,26 +5346,44 @@ export function createChecker(program) {
|
|
|
4168
5346
|
return [result, diagnostics];
|
|
4169
5347
|
}
|
|
4170
5348
|
function isTypeAssignableToWorker(source, target, diagnosticTarget, relationCache) {
|
|
4171
|
-
// BACKCOMPAT:
|
|
4172
|
-
if (
|
|
4173
|
-
|
|
5349
|
+
// BACKCOMPAT: Allow certain type to be accepted as values
|
|
5350
|
+
if ("kind" in source &&
|
|
5351
|
+
"entityKind" in target &&
|
|
5352
|
+
source.kind === "TemplateParameter" &&
|
|
5353
|
+
source.constraint?.type &&
|
|
5354
|
+
source.constraint.valueType === undefined &&
|
|
5355
|
+
target.entityKind === "MixedParameterConstraint" &&
|
|
5356
|
+
target.valueType) {
|
|
5357
|
+
const [assignable] = isTypeAssignableToInternal(source.constraint.type, target.valueType, diagnosticTarget, relationCache);
|
|
4174
5358
|
if (assignable) {
|
|
4175
|
-
const constraint =
|
|
4176
|
-
reportDeprecated(program, `Template constrainted to '${constraint}' will not be assignable to '${
|
|
5359
|
+
const constraint = getEntityName(source.constraint);
|
|
5360
|
+
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
5361
|
return [Related.true, []];
|
|
4178
5362
|
}
|
|
4179
5363
|
}
|
|
4180
|
-
|
|
5364
|
+
if ("kind" in source && source.kind === "TemplateParameter") {
|
|
4181
5365
|
source = source.constraint ?? unknownType;
|
|
4182
5366
|
}
|
|
5367
|
+
if (target.entityKind === "Indeterminate") {
|
|
5368
|
+
target = target.type;
|
|
5369
|
+
}
|
|
4183
5370
|
if (source === target)
|
|
4184
5371
|
return [Related.true, []];
|
|
4185
|
-
if (target
|
|
4186
|
-
return
|
|
5372
|
+
if (isValue(target)) {
|
|
5373
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5374
|
+
}
|
|
5375
|
+
if (source.entityKind === "Indeterminate") {
|
|
5376
|
+
return isIndeterminateEntityAssignableTo(source, target, diagnosticTarget, relationCache);
|
|
4187
5377
|
}
|
|
4188
|
-
if (
|
|
5378
|
+
if (target.entityKind === "MixedParameterConstraint") {
|
|
5379
|
+
return isAssignableToMixedParameterConstraint(source, target, diagnosticTarget, relationCache);
|
|
5380
|
+
}
|
|
5381
|
+
if (isValue(source) || (source.entityKind === "MixedParameterConstraint" && source.valueType)) {
|
|
4189
5382
|
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
4190
5383
|
}
|
|
5384
|
+
if (source.entityKind === "MixedParameterConstraint") {
|
|
5385
|
+
return isTypeAssignableToInternal(source.type, target, diagnosticTarget, relationCache);
|
|
5386
|
+
}
|
|
4191
5387
|
const isSimpleTypeRelated = isSimpleTypeAssignableTo(source, target);
|
|
4192
5388
|
if (isSimpleTypeRelated === true) {
|
|
4193
5389
|
return [Related.true, []];
|
|
@@ -4227,19 +5423,21 @@ export function createChecker(program) {
|
|
|
4227
5423
|
else if (target.kind === "Model" &&
|
|
4228
5424
|
isArrayModelType(program, target) &&
|
|
4229
5425
|
source.kind === "Model") {
|
|
4230
|
-
|
|
5426
|
+
if (isArrayModelType(program, source)) {
|
|
5427
|
+
return hasIndexAndIsAssignableTo(source, target, diagnosticTarget, relationCache);
|
|
5428
|
+
}
|
|
5429
|
+
else {
|
|
5430
|
+
// For other models just fallback to unassignable
|
|
5431
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5432
|
+
}
|
|
4231
5433
|
}
|
|
4232
5434
|
else if (target.kind === "Model" && source.kind === "Model") {
|
|
4233
5435
|
return isModelRelatedTo(source, target, diagnosticTarget, relationCache);
|
|
4234
5436
|
}
|
|
4235
|
-
else if (target.kind === "Model" &&
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
return [Related.false, diagnostics];
|
|
4240
|
-
}
|
|
4241
|
-
}
|
|
4242
|
-
return [Related.true, []];
|
|
5437
|
+
else if (target.kind === "Model" &&
|
|
5438
|
+
isArrayModelType(program, target) &&
|
|
5439
|
+
source.kind === "Tuple") {
|
|
5440
|
+
return isTupleAssignableToArray(source, target, diagnosticTarget, relationCache);
|
|
4243
5441
|
}
|
|
4244
5442
|
else if (target.kind === "Tuple" && source.kind === "Tuple") {
|
|
4245
5443
|
return isTupleAssignableToTuple(source, target, diagnosticTarget, relationCache);
|
|
@@ -4252,18 +5450,60 @@ export function createChecker(program) {
|
|
|
4252
5450
|
}
|
|
4253
5451
|
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
4254
5452
|
}
|
|
4255
|
-
function
|
|
4256
|
-
|
|
4257
|
-
|
|
5453
|
+
function isIndeterminateEntityAssignableTo(indeterminate, target, diagnosticTarget, relationCache) {
|
|
5454
|
+
const [typeRelated, typeDiagnostics] = isTypeAssignableToInternal(indeterminate.type, target, diagnosticTarget, relationCache);
|
|
5455
|
+
if (typeRelated) {
|
|
5456
|
+
return [Related.true, []];
|
|
4258
5457
|
}
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
5458
|
+
if (target.entityKind === "MixedParameterConstraint" && target.valueType) {
|
|
5459
|
+
const [valueRelated] = isTypeAssignableToInternal(indeterminate.type, target.valueType, diagnosticTarget, relationCache);
|
|
5460
|
+
if (valueRelated) {
|
|
5461
|
+
return [Related.true, []];
|
|
5462
|
+
}
|
|
4262
5463
|
}
|
|
4263
|
-
|
|
5464
|
+
return [Related.false, typeDiagnostics];
|
|
5465
|
+
}
|
|
5466
|
+
function isAssignableToValueType(source, target, diagnosticTarget, relationCache) {
|
|
5467
|
+
if (!isValue(source)) {
|
|
4264
5468
|
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
4265
5469
|
}
|
|
4266
|
-
return
|
|
5470
|
+
return isValueOfTypeInternal(source, target, diagnosticTarget, relationCache);
|
|
5471
|
+
}
|
|
5472
|
+
function isAssignableToMixedParameterConstraint(source, target, diagnosticTarget, relationCache) {
|
|
5473
|
+
if ("entityKind" in source && source.entityKind === "MixedParameterConstraint") {
|
|
5474
|
+
if (source.type && target.type) {
|
|
5475
|
+
const [variantAssignable, diagnostics] = isTypeAssignableToInternal(source.type, target.type, diagnosticTarget, relationCache);
|
|
5476
|
+
if (variantAssignable === Related.false) {
|
|
5477
|
+
return [Related.false, diagnostics];
|
|
5478
|
+
}
|
|
5479
|
+
return [Related.true, []];
|
|
5480
|
+
}
|
|
5481
|
+
if (source.valueType && target.valueType) {
|
|
5482
|
+
const [variantAssignable, diagnostics] = isTypeAssignableToInternal(source.valueType, target.valueType, diagnosticTarget, relationCache);
|
|
5483
|
+
if (variantAssignable === Related.false) {
|
|
5484
|
+
return [Related.false, diagnostics];
|
|
5485
|
+
}
|
|
5486
|
+
return [Related.true, []];
|
|
5487
|
+
}
|
|
5488
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5489
|
+
}
|
|
5490
|
+
if (target.type) {
|
|
5491
|
+
const [related] = isTypeAssignableToInternal(source, target.type, diagnosticTarget, relationCache);
|
|
5492
|
+
if (related) {
|
|
5493
|
+
return [Related.true, []];
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
if (target.valueType) {
|
|
5497
|
+
const [related] = isAssignableToValueType(source, target.valueType, diagnosticTarget, relationCache);
|
|
5498
|
+
if (related) {
|
|
5499
|
+
return [Related.true, []];
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
|
|
5503
|
+
}
|
|
5504
|
+
/** Check if the value is assignable to the given type. */
|
|
5505
|
+
function isValueOfTypeInternal(source, target, diagnosticTarget, relationCache) {
|
|
5506
|
+
return isTypeAssignableToInternal(source.type, target, diagnosticTarget, relationCache);
|
|
4267
5507
|
}
|
|
4268
5508
|
function isReflectionType(type) {
|
|
4269
5509
|
return (type.kind === "Model" &&
|
|
@@ -4276,7 +5516,7 @@ export function createChecker(program) {
|
|
|
4276
5516
|
return isNumericLiteralRelatedTo(source, target);
|
|
4277
5517
|
case "String":
|
|
4278
5518
|
case "StringTemplate":
|
|
4279
|
-
return
|
|
5519
|
+
return isStringLiteralRelatedTo(source, target);
|
|
4280
5520
|
case "Boolean":
|
|
4281
5521
|
return areScalarsRelated(target, getStdType("boolean"));
|
|
4282
5522
|
case "Scalar":
|
|
@@ -4314,7 +5554,12 @@ export function createChecker(program) {
|
|
|
4314
5554
|
return false;
|
|
4315
5555
|
}
|
|
4316
5556
|
if (target.kind === "String") {
|
|
4317
|
-
return source.kind === "String" &&
|
|
5557
|
+
return ((source.kind === "String" && source.value === target.value) ||
|
|
5558
|
+
(source.kind === "StringTemplate" && source.stringValue === target.value));
|
|
5559
|
+
}
|
|
5560
|
+
if (target.kind === "StringTemplate" && target.stringValue) {
|
|
5561
|
+
return ((source.kind === "String" && source.value === target.stringValue) ||
|
|
5562
|
+
(source.kind === "StringTemplate" && source.stringValue === target.stringValue));
|
|
4318
5563
|
}
|
|
4319
5564
|
if (target.kind === "Number") {
|
|
4320
5565
|
return source.kind === "Number" && target.value === source.value;
|
|
@@ -4322,6 +5567,29 @@ export function createChecker(program) {
|
|
|
4322
5567
|
return undefined;
|
|
4323
5568
|
}
|
|
4324
5569
|
function isNumericLiteralRelatedTo(source, target) {
|
|
5570
|
+
// First check that the source numeric literal is assignable to the target scalar
|
|
5571
|
+
if (!isNumericAssignableToNumericScalar(source.numericValue, target)) {
|
|
5572
|
+
return false;
|
|
5573
|
+
}
|
|
5574
|
+
const min = getMinValueAsNumeric(program, target);
|
|
5575
|
+
const max = getMaxValueAsNumeric(program, target);
|
|
5576
|
+
const minExclusive = getMinValueExclusiveAsNumeric(program, target);
|
|
5577
|
+
const maxExclusive = getMaxValueExclusiveAsNumeric(program, target);
|
|
5578
|
+
if (min && source.numericValue.lt(min)) {
|
|
5579
|
+
return false;
|
|
5580
|
+
}
|
|
5581
|
+
if (minExclusive && source.numericValue.lte(minExclusive)) {
|
|
5582
|
+
return false;
|
|
5583
|
+
}
|
|
5584
|
+
if (max && source.numericValue.gt(max)) {
|
|
5585
|
+
return false;
|
|
5586
|
+
}
|
|
5587
|
+
if (maxExclusive && source.numericValue.gte(maxExclusive)) {
|
|
5588
|
+
return false;
|
|
5589
|
+
}
|
|
5590
|
+
return true;
|
|
5591
|
+
}
|
|
5592
|
+
function isNumericAssignableToNumericScalar(source, target) {
|
|
4325
5593
|
// if the target does not derive from numeric, then it can't be assigned a numeric literal
|
|
4326
5594
|
if (!areScalarsRelated(target, getStdType("numeric"))) {
|
|
4327
5595
|
return false;
|
|
@@ -4338,7 +5606,7 @@ export function createChecker(program) {
|
|
|
4338
5606
|
return true;
|
|
4339
5607
|
if (target.name === "decimal128")
|
|
4340
5608
|
return true;
|
|
4341
|
-
const isInt =
|
|
5609
|
+
const isInt = source.isInteger;
|
|
4342
5610
|
if (target.name === "integer")
|
|
4343
5611
|
return isInt;
|
|
4344
5612
|
if (target.name === "float")
|
|
@@ -4346,7 +5614,25 @@ export function createChecker(program) {
|
|
|
4346
5614
|
if (!(target.name in numericRanges))
|
|
4347
5615
|
return false;
|
|
4348
5616
|
const [low, high, options] = numericRanges[target.name];
|
|
4349
|
-
return source.
|
|
5617
|
+
return source.gte(low) && source.lte(high) && (!options.int || isInt);
|
|
5618
|
+
}
|
|
5619
|
+
function isStringLiteralRelatedTo(source, target) {
|
|
5620
|
+
if (!areScalarsRelated(target, getStdType("string"))) {
|
|
5621
|
+
return false;
|
|
5622
|
+
}
|
|
5623
|
+
if (source.kind === "StringTemplate") {
|
|
5624
|
+
return true;
|
|
5625
|
+
}
|
|
5626
|
+
const len = source.value.length;
|
|
5627
|
+
const min = getMinLength(program, target);
|
|
5628
|
+
const max = getMaxLength(program, target);
|
|
5629
|
+
if (min && len < min) {
|
|
5630
|
+
return false;
|
|
5631
|
+
}
|
|
5632
|
+
if (max && len > max) {
|
|
5633
|
+
return false;
|
|
5634
|
+
}
|
|
5635
|
+
return true;
|
|
4350
5636
|
}
|
|
4351
5637
|
function isModelRelatedTo(source, target, diagnosticTarget, relationCache) {
|
|
4352
5638
|
relationCache.set([source, target], Related.maybe);
|
|
@@ -4396,8 +5682,30 @@ export function createChecker(program) {
|
|
|
4396
5682
|
}
|
|
4397
5683
|
}
|
|
4398
5684
|
}
|
|
5685
|
+
else if (shouldCheckExcessProperties(source)) {
|
|
5686
|
+
for (const [propName, prop] of remainingProperties) {
|
|
5687
|
+
if (shouldCheckExcessProperty(prop)) {
|
|
5688
|
+
diagnostics.push(createDiagnostic({
|
|
5689
|
+
code: "unexpected-property",
|
|
5690
|
+
format: {
|
|
5691
|
+
propertyName: propName,
|
|
5692
|
+
type: getEntityName(target),
|
|
5693
|
+
},
|
|
5694
|
+
target: prop,
|
|
5695
|
+
}));
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
}
|
|
4399
5699
|
return [diagnostics.length === 0 ? Related.true : Related.false, diagnostics];
|
|
4400
5700
|
}
|
|
5701
|
+
/** If we should check for excess properties on the given model. */
|
|
5702
|
+
function shouldCheckExcessProperties(model) {
|
|
5703
|
+
return model.node?.kind === SyntaxKind.ObjectLiteral;
|
|
5704
|
+
}
|
|
5705
|
+
/** If we should check for this specific property */
|
|
5706
|
+
function shouldCheckExcessProperty(prop) {
|
|
5707
|
+
return (prop.node?.kind === SyntaxKind.ObjectLiteralProperty && prop.node.parent === prop.model?.node);
|
|
5708
|
+
}
|
|
4401
5709
|
function getProperty(model, name) {
|
|
4402
5710
|
return (model.properties.get(name) ??
|
|
4403
5711
|
(model.baseModel !== undefined ? getProperty(model.baseModel, name) : undefined));
|
|
@@ -4430,6 +5738,51 @@ export function createChecker(program) {
|
|
|
4430
5738
|
}
|
|
4431
5739
|
return isTypeAssignableToInternal(source.indexer.value, target.indexer.value, diagnosticTarget, relationCache);
|
|
4432
5740
|
}
|
|
5741
|
+
function isTupleAssignableToArray(source, target, diagnosticTarget, relationCache) {
|
|
5742
|
+
const minItems = getMinItems(program, target);
|
|
5743
|
+
const maxItems = getMaxItems(program, target);
|
|
5744
|
+
if (minItems !== undefined && source.values.length < minItems) {
|
|
5745
|
+
return [
|
|
5746
|
+
Related.false,
|
|
5747
|
+
[
|
|
5748
|
+
createDiagnostic({
|
|
5749
|
+
code: "unassignable",
|
|
5750
|
+
messageId: "withDetails",
|
|
5751
|
+
format: {
|
|
5752
|
+
sourceType: getEntityName(source),
|
|
5753
|
+
targetType: getTypeName(target),
|
|
5754
|
+
details: `Source has ${source.values.length} element(s) but target requires ${minItems}.`,
|
|
5755
|
+
},
|
|
5756
|
+
target: diagnosticTarget,
|
|
5757
|
+
}),
|
|
5758
|
+
],
|
|
5759
|
+
];
|
|
5760
|
+
}
|
|
5761
|
+
if (maxItems !== undefined && source.values.length > maxItems) {
|
|
5762
|
+
return [
|
|
5763
|
+
Related.false,
|
|
5764
|
+
[
|
|
5765
|
+
createDiagnostic({
|
|
5766
|
+
code: "unassignable",
|
|
5767
|
+
messageId: "withDetails",
|
|
5768
|
+
format: {
|
|
5769
|
+
sourceType: getEntityName(source),
|
|
5770
|
+
targetType: getTypeName(target),
|
|
5771
|
+
details: `Source has ${source.values.length} element(s) but target only allows ${maxItems}.`,
|
|
5772
|
+
},
|
|
5773
|
+
target: diagnosticTarget,
|
|
5774
|
+
}),
|
|
5775
|
+
],
|
|
5776
|
+
];
|
|
5777
|
+
}
|
|
5778
|
+
for (const item of source.values) {
|
|
5779
|
+
const [related, diagnostics] = isTypeAssignableToInternal(item, target.indexer.value, diagnosticTarget, relationCache);
|
|
5780
|
+
if (!related) {
|
|
5781
|
+
return [Related.false, diagnostics];
|
|
5782
|
+
}
|
|
5783
|
+
}
|
|
5784
|
+
return [Related.true, []];
|
|
5785
|
+
}
|
|
4433
5786
|
function isTupleAssignableToTuple(source, target, diagnosticTarget, relationCache) {
|
|
4434
5787
|
if (source.values.length !== target.values.length) {
|
|
4435
5788
|
return [
|
|
@@ -4439,7 +5792,7 @@ export function createChecker(program) {
|
|
|
4439
5792
|
code: "unassignable",
|
|
4440
5793
|
messageId: "withDetails",
|
|
4441
5794
|
format: {
|
|
4442
|
-
sourceType:
|
|
5795
|
+
sourceType: getEntityName(source),
|
|
4443
5796
|
targetType: getTypeName(target),
|
|
4444
5797
|
details: `Source has ${source.values.length} element(s) but target requires ${target.values.length}.`,
|
|
4445
5798
|
},
|
|
@@ -4492,7 +5845,7 @@ export function createChecker(program) {
|
|
|
4492
5845
|
function createUnassignableDiagnostic(source, target, diagnosticTarget) {
|
|
4493
5846
|
return createDiagnostic({
|
|
4494
5847
|
code: "unassignable",
|
|
4495
|
-
format: { targetType:
|
|
5848
|
+
format: { targetType: getEntityName(target), value: getEntityName(source) },
|
|
4496
5849
|
target: diagnosticTarget,
|
|
4497
5850
|
});
|
|
4498
5851
|
}
|
|
@@ -4516,22 +5869,6 @@ export function createChecker(program) {
|
|
|
4516
5869
|
function isAnonymous(type) {
|
|
4517
5870
|
return !("name" in type) || typeof type.name !== "string" || !type.name;
|
|
4518
5871
|
}
|
|
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
5872
|
/**
|
|
4536
5873
|
* Find all named models that could have been the source of the given
|
|
4537
5874
|
* property. This includes the named parents of all property sources in a
|
|
@@ -4831,7 +6168,7 @@ function reportDeprecation(program, target, message, reportFunc) {
|
|
|
4831
6168
|
function applyDecoratorToType(program, decApp, target) {
|
|
4832
6169
|
compilerAssert("decorators" in target, "Cannot apply decorator to non-decoratable type", target);
|
|
4833
6170
|
for (const arg of decApp.args) {
|
|
4834
|
-
if (isErrorType(arg.value)) {
|
|
6171
|
+
if (isType(arg.value) && isErrorType(arg.value)) {
|
|
4835
6172
|
// If one of the decorator argument is an error don't run it.
|
|
4836
6173
|
return;
|
|
4837
6174
|
}
|
|
@@ -4886,23 +6223,6 @@ function createDecoratorContext(program, decApp) {
|
|
|
4886
6223
|
},
|
|
4887
6224
|
};
|
|
4888
6225
|
}
|
|
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
6226
|
function isTemplatedNode(node) {
|
|
4907
6227
|
return "templateParameters" in node && node.templateParameters.length > 0;
|
|
4908
6228
|
}
|
|
@@ -4926,9 +6246,10 @@ const ReflectionNameToKind = {
|
|
|
4926
6246
|
const _assertReflectionNameToKind = ReflectionNameToKind;
|
|
4927
6247
|
var ResolutionKind;
|
|
4928
6248
|
(function (ResolutionKind) {
|
|
4929
|
-
ResolutionKind[ResolutionKind["
|
|
4930
|
-
ResolutionKind[ResolutionKind["
|
|
4931
|
-
ResolutionKind[ResolutionKind["
|
|
6249
|
+
ResolutionKind[ResolutionKind["Value"] = 0] = "Value";
|
|
6250
|
+
ResolutionKind[ResolutionKind["Type"] = 1] = "Type";
|
|
6251
|
+
ResolutionKind[ResolutionKind["BaseType"] = 2] = "BaseType";
|
|
6252
|
+
ResolutionKind[ResolutionKind["Constraint"] = 3] = "Constraint";
|
|
4932
6253
|
})(ResolutionKind || (ResolutionKind = {}));
|
|
4933
6254
|
class PendingResolutions {
|
|
4934
6255
|
#data = new Map();
|
|
@@ -4964,4 +6285,19 @@ const defaultSymbolResolutionOptions = {
|
|
|
4964
6285
|
resolveDecorators: false,
|
|
4965
6286
|
checkTemplateTypes: true,
|
|
4966
6287
|
};
|
|
6288
|
+
/**
|
|
6289
|
+
* Convert LEGACY for projection.
|
|
6290
|
+
* THIS IS BROKEN. Some decorators will not receive the correct type.
|
|
6291
|
+
* It has been broken since the introduction of valueof.
|
|
6292
|
+
* As projection as put on hold as long as versioning works we are in a good state.
|
|
6293
|
+
*/
|
|
6294
|
+
function unsafe_projectionArgumentMarshalForJS(arg) {
|
|
6295
|
+
if (arg.kind === "Boolean" || arg.kind === "String" || arg.kind === "Number") {
|
|
6296
|
+
return arg.value;
|
|
6297
|
+
}
|
|
6298
|
+
else if (arg.kind === "StringTemplate") {
|
|
6299
|
+
return arg.stringValue;
|
|
6300
|
+
}
|
|
6301
|
+
return arg;
|
|
6302
|
+
}
|
|
4967
6303
|
//# sourceMappingURL=checker.js.map
|