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

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