@typespec/compiler 0.57.0-dev.0 → 0.57.0-dev.4

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