@typespec/compiler 0.60.0-dev.9 → 0.61.0-dev.0

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.
@@ -10,14 +10,13 @@ import { validateInheritanceDiscriminatedUnions } from "./helpers/discriminator-
10
10
  import { getLocationContext } from "./helpers/location-context.js";
11
11
  import { explainStringTemplateNotSerializable } from "./helpers/string-template-utils.js";
12
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
13
  import { canNumericConstraintBeJsNumber, legacyMarshallTypeForJS, marshallTypeForJS, } from "./js-marshaller.js";
15
14
  import { createDiagnostic } from "./messages.js";
16
- import { numericRanges } from "./numeric-ranges.js";
17
15
  import { Numeric } from "./numeric.js";
18
16
  import { exprIsBareIdentifier, getFirstAncestor, getIdentifierContext, hasParseError, visitChildren, } from "./parser.js";
19
17
  import { createProjectionMembers } from "./projection-members.js";
20
- import { getFullyQualifiedSymbolName, getParentTemplateNode, isArrayModelType, isErrorType, isNeverType, isNullType, isTemplateInstance, isType, isUnknownType, isValue, isVoidType, } from "./type-utils.js";
18
+ import { createTypeRelationChecker } from "./type-relation-checker.js";
19
+ import { getFullyQualifiedSymbolName, getParentTemplateNode, isArrayModelType, isErrorType, isNullType, isTemplateInstance, isType, isValue, } from "./type-utils.js";
21
20
  import { IdentifierKind, SyntaxKind, } from "./types.js";
22
21
  /**
23
22
  * Maps type arguments to type instantiation.
@@ -122,14 +121,16 @@ export function createChecker(program) {
122
121
  createFunctionType,
123
122
  createLiteralType,
124
123
  finishType,
125
- isTypeAssignableTo,
126
124
  isStdType,
127
125
  getStdType,
128
126
  resolveTypeReference,
129
127
  getValueForNode,
130
128
  getTypeOrValueForNode,
131
129
  getValueExactType,
130
+ isTypeAssignableTo: undefined,
132
131
  };
132
+ const relation = createTypeRelationChecker(program, checker);
133
+ checker.isTypeAssignableTo = relation.isTypeAssignableTo;
133
134
  const projectionMembers = createProjectionMembers(checker);
134
135
  return checker;
135
136
  function reportCheckerDiagnostic(diagnostic) {
@@ -534,7 +535,8 @@ export function createChecker(program) {
534
535
  }
535
536
  function canTryLegacyCast(target, constraint) {
536
537
  return Boolean(constraint?.valueType &&
537
- !(constraint.type && ignoreDiagnostics(isTypeAssignableTo(target, constraint.type, target))));
538
+ !(constraint.type &&
539
+ ignoreDiagnostics(relation.isTypeAssignableTo(target, constraint.type, target))));
538
540
  }
539
541
  /**
540
542
  * Gets a type or value depending on the node and current constraint.
@@ -1353,15 +1355,16 @@ export function createChecker(program) {
1353
1355
  if (marshalling === "legacy") {
1354
1356
  for (const param of decorator.parameters) {
1355
1357
  if (param.type.valueType) {
1356
- if (ignoreDiagnostics(isTypeAssignableTo(nullType, param.type.valueType, param.type))) {
1358
+ if (ignoreDiagnostics(relation.isTypeAssignableTo(nullType, param.type.valueType, param.type))) {
1357
1359
  reportDeprecatedLegacyMarshalling(param, "null as a type");
1358
1360
  }
1359
1361
  else if (param.type.valueType.kind === "Enum" ||
1360
1362
  param.type.valueType.kind === "EnumMember" ||
1361
- (isReflectionType(param.type.valueType) && param.type.valueType.name === "EnumMember")) {
1363
+ (relation.isReflectionType(param.type.valueType) &&
1364
+ param.type.valueType.name === "EnumMember")) {
1362
1365
  reportDeprecatedLegacyMarshalling(param, "enum members");
1363
1366
  }
1364
- else if (ignoreDiagnostics(isTypeAssignableTo(param.type.valueType, getStdType("numeric"), param.type.valueType)) &&
1367
+ else if (ignoreDiagnostics(relation.isTypeAssignableTo(param.type.valueType, getStdType("numeric"), param.type.valueType)) &&
1365
1368
  !canNumericConstraintBeJsNumber(param.type.valueType)) {
1366
1369
  reportDeprecatedLegacyMarshalling(param, "a numeric type that is not representable as a JS Number");
1367
1370
  }
@@ -2918,7 +2921,7 @@ export function createChecker(program) {
2918
2921
  ]);
2919
2922
  return;
2920
2923
  }
2921
- const [valid, diagnostics] = isTypeAssignableTo(property.type, indexer.value, diagnosticTarget);
2924
+ const [valid, diagnostics] = relation.isTypeAssignableTo(property.type, indexer.value, diagnosticTarget);
2922
2925
  if (!valid)
2923
2926
  reportCheckerDiagnostic(createDiagnostic({
2924
2927
  code: "incompatible-indexer",
@@ -3092,7 +3095,7 @@ export function createChecker(program) {
3092
3095
  }
3093
3096
  switch (type.kind) {
3094
3097
  case "Scalar":
3095
- if (ignoreDiagnostics(isTypeAssignableTo(literalType, type, literalType))) {
3098
+ if (ignoreDiagnostics(checker.isTypeAssignableTo(literalType, type, literalType))) {
3096
3099
  return type;
3097
3100
  }
3098
3101
  return undefined;
@@ -3333,13 +3336,13 @@ export function createChecker(program) {
3333
3336
  if (target.kind === "ScalarConstructor") {
3334
3337
  return createScalarValue(node, mapper, target);
3335
3338
  }
3336
- if (areScalarsRelated(target, getStdType("string"))) {
3339
+ if (relation.areScalarsRelated(target, getStdType("string"))) {
3337
3340
  return checkPrimitiveArg(node, target, "StringValue");
3338
3341
  }
3339
- else if (areScalarsRelated(target, getStdType("numeric"))) {
3342
+ else if (relation.areScalarsRelated(target, getStdType("numeric"))) {
3340
3343
  return checkPrimitiveArg(node, target, "NumericValue");
3341
3344
  }
3342
- else if (areScalarsRelated(target, getStdType("boolean"))) {
3345
+ else if (relation.areScalarsRelated(target, getStdType("boolean"))) {
3343
3346
  return checkPrimitiveArg(node, target, "BooleanValue");
3344
3347
  }
3345
3348
  else {
@@ -3419,7 +3422,7 @@ export function createChecker(program) {
3419
3422
  }
3420
3423
  const overriddenProp = getOverriddenProperty(newProp);
3421
3424
  if (overriddenProp) {
3422
- const [isAssignable, _] = isTypeAssignableTo(newProp.type, overriddenProp.type, newProp);
3425
+ const [isAssignable, _] = relation.isTypeAssignableTo(newProp.type, overriddenProp.type, newProp);
3423
3426
  const parentType = getTypeName(overriddenProp.type);
3424
3427
  const newPropType = getTypeName(newProp.type);
3425
3428
  let invalid = false;
@@ -3920,7 +3923,7 @@ export function createChecker(program) {
3920
3923
  if (defaultValue === null) {
3921
3924
  return null;
3922
3925
  }
3923
- const [related, diagnostics] = isValueOfType(defaultValue, type, defaultNode);
3926
+ const [related, diagnostics] = relation.isValueOfType(defaultValue, type, defaultNode);
3924
3927
  if (!related) {
3925
3928
  reportCheckerDiagnostics(diagnostics);
3926
3929
  return null;
@@ -4003,7 +4006,7 @@ export function createChecker(program) {
4003
4006
  }
4004
4007
  /** Check the decorator target is valid */
4005
4008
  function checkDecoratorTarget(targetType, declaration, decoratorNode) {
4006
- const [targetValid] = isTypeAssignableTo(targetType, declaration.target.type, decoratorNode);
4009
+ const [targetValid] = relation.isTypeAssignableTo(targetType, declaration.target.type, decoratorNode);
4007
4010
  if (!targetValid) {
4008
4011
  reportCheckerDiagnostic(createDiagnostic({
4009
4012
  code: "decorator-wrong-target",
@@ -4164,7 +4167,7 @@ export function createChecker(program) {
4164
4167
  return value;
4165
4168
  }
4166
4169
  function checkArgumentAssignable(argumentType, parameterType, diagnosticTarget) {
4167
- const [valid] = isTypeAssignableTo(argumentType, parameterType, diagnosticTarget);
4170
+ const [valid] = relation.isTypeAssignableTo(argumentType, parameterType, diagnosticTarget);
4168
4171
  if (!valid) {
4169
4172
  reportCheckerDiagnostic(createDiagnostic({
4170
4173
  code: "invalid-argument",
@@ -5599,7 +5602,7 @@ export function createChecker(program) {
5599
5602
  * @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
5600
5603
  */
5601
5604
  function checkTypeOfValueMatchConstraint(source, constraint, diagnosticTarget) {
5602
- const [related, diagnostics] = isTypeAssignableTo(source, constraint.type, diagnosticTarget);
5605
+ const [related, diagnostics] = relation.isTypeAssignableTo(source, constraint.type, diagnosticTarget);
5603
5606
  if (!related) {
5604
5607
  if (constraint.kind === "argument") {
5605
5608
  reportCheckerDiagnostic(createDiagnostic({
@@ -5624,552 +5627,19 @@ export function createChecker(program) {
5624
5627
  * @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
5625
5628
  */
5626
5629
  function checkTypeAssignable(source, target, diagnosticTarget) {
5627
- const [related, diagnostics] = isTypeAssignableTo(source, target, diagnosticTarget);
5630
+ const [related, diagnostics] = relation.isTypeAssignableTo(source, target, diagnosticTarget);
5628
5631
  if (!related) {
5629
5632
  reportCheckerDiagnostics(diagnostics);
5630
5633
  }
5631
5634
  return related;
5632
5635
  }
5633
5636
  function checkValueOfType(source, target, diagnosticTarget) {
5634
- const [related, diagnostics] = isValueOfType(source, target, diagnosticTarget);
5637
+ const [related, diagnostics] = relation.isValueOfType(source, target, diagnosticTarget);
5635
5638
  if (!related) {
5636
5639
  reportCheckerDiagnostics(diagnostics);
5637
5640
  }
5638
5641
  return related;
5639
5642
  }
5640
- /**
5641
- * Check if the source type can be assigned to the target type.
5642
- * @param source Source type
5643
- * @param target Target type
5644
- * @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
5645
- */
5646
- function isTypeAssignableTo(source, target, diagnosticTarget) {
5647
- const [related, diagnostics] = isTypeAssignableToInternal(source, target, diagnosticTarget, new MultiKeyMap());
5648
- return [related === Related.true, diagnostics];
5649
- }
5650
- /**
5651
- * Check if the given Value type is of the given type.
5652
- * @param source Value
5653
- * @param target Target type
5654
- * @param diagnosticTarget Target for the diagnostic, unless something better can be inferred.
5655
- */
5656
- function isValueOfType(source, target, diagnosticTarget) {
5657
- const [related, diagnostics] = isValueOfTypeInternal(source, target, diagnosticTarget, new MultiKeyMap());
5658
- return [related === Related.true, diagnostics];
5659
- }
5660
- function isTypeAssignableToInternal(source, target, diagnosticTarget, relationCache) {
5661
- const cached = relationCache.get([source, target]);
5662
- if (cached !== undefined) {
5663
- return [cached, []];
5664
- }
5665
- const [result, diagnostics] = isTypeAssignableToWorker(source, target, diagnosticTarget, new MultiKeyMap());
5666
- relationCache.set([source, target], result);
5667
- return [result, diagnostics];
5668
- }
5669
- function isTypeAssignableToWorker(source, target, diagnosticTarget, relationCache) {
5670
- // BACKCOMPAT: Allow certain type to be accepted as values
5671
- if ("kind" in source &&
5672
- "entityKind" in target &&
5673
- source.kind === "TemplateParameter" &&
5674
- source.constraint?.type &&
5675
- source.constraint.valueType === undefined &&
5676
- target.entityKind === "MixedParameterConstraint" &&
5677
- target.valueType) {
5678
- const [assignable] = isTypeAssignableToInternal(source.constraint.type, target.valueType, diagnosticTarget, relationCache);
5679
- if (assignable) {
5680
- const constraint = getEntityName(source.constraint);
5681
- reportDeprecated(program, `Template constrainted to '${constraint}' will not be assignable to '${getEntityName(target)}' in the future. Update the constraint to be 'valueof ${constraint}'`, diagnosticTarget);
5682
- return [Related.true, []];
5683
- }
5684
- }
5685
- if ("kind" in source && source.kind === "TemplateParameter") {
5686
- source = source.constraint ?? unknownType;
5687
- }
5688
- if (target.entityKind === "Indeterminate") {
5689
- target = target.type;
5690
- }
5691
- if (source === target)
5692
- return [Related.true, []];
5693
- if (isValue(target)) {
5694
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5695
- }
5696
- if (source.entityKind === "Indeterminate") {
5697
- return isIndeterminateEntityAssignableTo(source, target, diagnosticTarget, relationCache);
5698
- }
5699
- if (target.entityKind === "MixedParameterConstraint") {
5700
- return isAssignableToMixedParameterConstraint(source, target, diagnosticTarget, relationCache);
5701
- }
5702
- if (isValue(source) || (source.entityKind === "MixedParameterConstraint" && source.valueType)) {
5703
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5704
- }
5705
- if (source.entityKind === "MixedParameterConstraint") {
5706
- return isTypeAssignableToInternal(source.type, target, diagnosticTarget, relationCache);
5707
- }
5708
- const isSimpleTypeRelated = isSimpleTypeAssignableTo(source, target);
5709
- if (isSimpleTypeRelated === true) {
5710
- return [Related.true, []];
5711
- }
5712
- else if (isSimpleTypeRelated === false) {
5713
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5714
- }
5715
- if (source.kind === "Union") {
5716
- for (const variant of source.variants.values()) {
5717
- const [variantAssignable] = isTypeAssignableToInternal(variant.type, target, diagnosticTarget, relationCache);
5718
- if (!variantAssignable) {
5719
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5720
- }
5721
- }
5722
- return [Related.true, []];
5723
- }
5724
- if (target.kind === "Model" &&
5725
- source.kind === "Model" &&
5726
- target.name !== "object" &&
5727
- target.indexer === undefined &&
5728
- source.indexer &&
5729
- source.indexer.key.name === "integer") {
5730
- return [
5731
- Related.false,
5732
- [
5733
- createDiagnostic({
5734
- code: "missing-index",
5735
- format: {
5736
- indexType: getTypeName(source.indexer.key),
5737
- sourceType: getTypeName(target),
5738
- },
5739
- target: diagnosticTarget,
5740
- }),
5741
- ],
5742
- ];
5743
- }
5744
- else if (target.kind === "Model" &&
5745
- isArrayModelType(program, target) &&
5746
- source.kind === "Model") {
5747
- if (isArrayModelType(program, source)) {
5748
- return hasIndexAndIsAssignableTo(source, target, diagnosticTarget, relationCache);
5749
- }
5750
- else {
5751
- // For other models just fallback to unassignable
5752
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5753
- }
5754
- }
5755
- else if (target.kind === "Model" && source.kind === "Model") {
5756
- return isModelRelatedTo(source, target, diagnosticTarget, relationCache);
5757
- }
5758
- else if (target.kind === "Model" &&
5759
- isArrayModelType(program, target) &&
5760
- source.kind === "Tuple") {
5761
- return isTupleAssignableToArray(source, target, diagnosticTarget, relationCache);
5762
- }
5763
- else if (target.kind === "Tuple" && source.kind === "Tuple") {
5764
- return isTupleAssignableToTuple(source, target, diagnosticTarget, relationCache);
5765
- }
5766
- else if (target.kind === "Union") {
5767
- return isAssignableToUnion(source, target, diagnosticTarget, relationCache);
5768
- }
5769
- else if (target.kind === "Enum") {
5770
- return isAssignableToEnum(source, target, diagnosticTarget);
5771
- }
5772
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5773
- }
5774
- function isIndeterminateEntityAssignableTo(indeterminate, target, diagnosticTarget, relationCache) {
5775
- const [typeRelated, typeDiagnostics] = isTypeAssignableToInternal(indeterminate.type, target, diagnosticTarget, relationCache);
5776
- if (typeRelated) {
5777
- return [Related.true, []];
5778
- }
5779
- if (target.entityKind === "MixedParameterConstraint" && target.valueType) {
5780
- const [valueRelated] = isTypeAssignableToInternal(indeterminate.type, target.valueType, diagnosticTarget, relationCache);
5781
- if (valueRelated) {
5782
- return [Related.true, []];
5783
- }
5784
- }
5785
- return [Related.false, typeDiagnostics];
5786
- }
5787
- function isAssignableToValueType(source, target, diagnosticTarget, relationCache) {
5788
- if (!isValue(source)) {
5789
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5790
- }
5791
- return isValueOfTypeInternal(source, target, diagnosticTarget, relationCache);
5792
- }
5793
- function isAssignableToMixedParameterConstraint(source, target, diagnosticTarget, relationCache) {
5794
- if ("entityKind" in source && source.entityKind === "MixedParameterConstraint") {
5795
- if (source.type && target.type) {
5796
- const [variantAssignable, diagnostics] = isTypeAssignableToInternal(source.type, target.type, diagnosticTarget, relationCache);
5797
- if (variantAssignable === Related.false) {
5798
- return [Related.false, diagnostics];
5799
- }
5800
- return [Related.true, []];
5801
- }
5802
- if (source.valueType && target.valueType) {
5803
- const [variantAssignable, diagnostics] = isTypeAssignableToInternal(source.valueType, target.valueType, diagnosticTarget, relationCache);
5804
- if (variantAssignable === Related.false) {
5805
- return [Related.false, diagnostics];
5806
- }
5807
- return [Related.true, []];
5808
- }
5809
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5810
- }
5811
- if (target.type) {
5812
- const [related] = isTypeAssignableToInternal(source, target.type, diagnosticTarget, relationCache);
5813
- if (related) {
5814
- return [Related.true, []];
5815
- }
5816
- }
5817
- if (target.valueType) {
5818
- const [related] = isAssignableToValueType(source, target.valueType, diagnosticTarget, relationCache);
5819
- if (related) {
5820
- return [Related.true, []];
5821
- }
5822
- }
5823
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
5824
- }
5825
- /** Check if the value is assignable to the given type. */
5826
- function isValueOfTypeInternal(source, target, diagnosticTarget, relationCache) {
5827
- return isTypeAssignableToInternal(source.type, target, diagnosticTarget, relationCache);
5828
- }
5829
- function isReflectionType(type) {
5830
- return (type.kind === "Model" &&
5831
- type.namespace?.name === "Reflection" &&
5832
- type.namespace?.namespace?.name === "TypeSpec");
5833
- }
5834
- function isRelatedToScalar(source, target) {
5835
- switch (source.kind) {
5836
- case "Number":
5837
- return isNumericLiteralRelatedTo(source, target);
5838
- case "String":
5839
- case "StringTemplate":
5840
- return isStringLiteralRelatedTo(source, target);
5841
- case "Boolean":
5842
- return areScalarsRelated(target, getStdType("boolean"));
5843
- case "Scalar":
5844
- return areScalarsRelated(source, target);
5845
- case "Union":
5846
- return undefined;
5847
- default:
5848
- return false;
5849
- }
5850
- }
5851
- function areScalarsRelated(source, target) {
5852
- let current = source;
5853
- while (current) {
5854
- if (current === target) {
5855
- return true;
5856
- }
5857
- current = current.baseScalar;
5858
- }
5859
- return false;
5860
- }
5861
- function isSimpleTypeAssignableTo(source, target) {
5862
- if (isNeverType(source))
5863
- return true;
5864
- if (isVoidType(target))
5865
- return false;
5866
- if (isUnknownType(target))
5867
- return true;
5868
- if (isReflectionType(target)) {
5869
- return source.kind === ReflectionNameToKind[target.name];
5870
- }
5871
- if (target.kind === "Scalar") {
5872
- return isRelatedToScalar(source, target);
5873
- }
5874
- if (source.kind === "Scalar" && target.kind === "Model") {
5875
- return false;
5876
- }
5877
- if (target.kind === "String") {
5878
- return ((source.kind === "String" && source.value === target.value) ||
5879
- (source.kind === "StringTemplate" && source.stringValue === target.value));
5880
- }
5881
- if (target.kind === "StringTemplate" && target.stringValue) {
5882
- return ((source.kind === "String" && source.value === target.stringValue) ||
5883
- (source.kind === "StringTemplate" && source.stringValue === target.stringValue));
5884
- }
5885
- if (target.kind === "Number") {
5886
- return source.kind === "Number" && target.value === source.value;
5887
- }
5888
- return undefined;
5889
- }
5890
- function isNumericLiteralRelatedTo(source, target) {
5891
- // First check that the source numeric literal is assignable to the target scalar
5892
- if (!isNumericAssignableToNumericScalar(source.numericValue, target)) {
5893
- return false;
5894
- }
5895
- const min = getMinValueAsNumeric(program, target);
5896
- const max = getMaxValueAsNumeric(program, target);
5897
- const minExclusive = getMinValueExclusiveAsNumeric(program, target);
5898
- const maxExclusive = getMaxValueExclusiveAsNumeric(program, target);
5899
- if (min && source.numericValue.lt(min)) {
5900
- return false;
5901
- }
5902
- if (minExclusive && source.numericValue.lte(minExclusive)) {
5903
- return false;
5904
- }
5905
- if (max && source.numericValue.gt(max)) {
5906
- return false;
5907
- }
5908
- if (maxExclusive && source.numericValue.gte(maxExclusive)) {
5909
- return false;
5910
- }
5911
- return true;
5912
- }
5913
- function isNumericAssignableToNumericScalar(source, target) {
5914
- // if the target does not derive from numeric, then it can't be assigned a numeric literal
5915
- if (!areScalarsRelated(target.projectionBase ?? target, getStdType("numeric"))) {
5916
- return false;
5917
- }
5918
- // With respect to literal assignability a custom numeric scalar is
5919
- // equivalent to its nearest TypeSpec.* base. Adjust target accordingly.
5920
- while (!target.namespace || !isTypeSpecNamespace(target.namespace)) {
5921
- compilerAssert(target.baseScalar, "Should not be possible to be derived from TypeSpec.numeric and not have a base when not in TypeSpec namespace.");
5922
- target = target.baseScalar;
5923
- }
5924
- if (target.name === "numeric")
5925
- return true;
5926
- if (target.name === "decimal")
5927
- return true;
5928
- if (target.name === "decimal128")
5929
- return true;
5930
- const isInt = source.isInteger;
5931
- if (target.name === "integer")
5932
- return isInt;
5933
- if (target.name === "float")
5934
- return true;
5935
- if (!(target.name in numericRanges))
5936
- return false;
5937
- const [low, high, options] = numericRanges[target.name];
5938
- return source.gte(low) && source.lte(high) && (!options.int || isInt);
5939
- }
5940
- function isStringLiteralRelatedTo(source, target) {
5941
- if (!areScalarsRelated(target.projectionBase ?? target, getStdType("string"))) {
5942
- return false;
5943
- }
5944
- if (source.kind === "StringTemplate") {
5945
- return true;
5946
- }
5947
- const len = source.value.length;
5948
- const min = getMinLength(program, target);
5949
- const max = getMaxLength(program, target);
5950
- if (min && len < min) {
5951
- return false;
5952
- }
5953
- if (max && len > max) {
5954
- return false;
5955
- }
5956
- return true;
5957
- }
5958
- function isModelRelatedTo(source, target, diagnosticTarget, relationCache) {
5959
- relationCache.set([source, target], Related.maybe);
5960
- const diagnostics = [];
5961
- const remainingProperties = new Map(source.properties);
5962
- for (const prop of walkPropertiesInherited(target)) {
5963
- const sourceProperty = getProperty(source, prop.name);
5964
- if (sourceProperty === undefined) {
5965
- if (!prop.optional) {
5966
- diagnostics.push(createDiagnostic({
5967
- code: "missing-property",
5968
- format: {
5969
- propertyName: prop.name,
5970
- sourceType: getTypeName(source),
5971
- targetType: getTypeName(target),
5972
- },
5973
- target: source,
5974
- }));
5975
- }
5976
- }
5977
- else {
5978
- remainingProperties.delete(prop.name);
5979
- if (sourceProperty.optional && !prop.optional) {
5980
- diagnostics.push(createDiagnostic({
5981
- code: "property-required",
5982
- format: {
5983
- propName: prop.name,
5984
- targetType: getTypeName(target),
5985
- },
5986
- target: diagnosticTarget,
5987
- }));
5988
- }
5989
- const [related, propDiagnostics] = isTypeAssignableToInternal(sourceProperty.type, prop.type, diagnosticTarget, relationCache);
5990
- if (!related) {
5991
- diagnostics.push(...propDiagnostics);
5992
- }
5993
- }
5994
- }
5995
- if (target.indexer) {
5996
- const [_, indexerDiagnostics] = arePropertiesAssignableToIndexer(remainingProperties, target.indexer.value, diagnosticTarget, relationCache);
5997
- diagnostics.push(...indexerDiagnostics);
5998
- // For anonymous models we don't need an indexer
5999
- if (source.name !== "" && target.indexer.key.name !== "integer") {
6000
- const [related, indexDiagnostics] = hasIndexAndIsAssignableTo(source, target, diagnosticTarget, relationCache);
6001
- if (!related) {
6002
- diagnostics.push(...indexDiagnostics);
6003
- }
6004
- }
6005
- }
6006
- else if (shouldCheckExcessProperties(source)) {
6007
- for (const [propName, prop] of remainingProperties) {
6008
- if (shouldCheckExcessProperty(prop)) {
6009
- diagnostics.push(createDiagnostic({
6010
- code: "unexpected-property",
6011
- format: {
6012
- propertyName: propName,
6013
- type: getEntityName(target),
6014
- },
6015
- target: prop,
6016
- }));
6017
- }
6018
- }
6019
- }
6020
- return [diagnostics.length === 0 ? Related.true : Related.false, diagnostics];
6021
- }
6022
- /** If we should check for excess properties on the given model. */
6023
- function shouldCheckExcessProperties(model) {
6024
- return model.node?.kind === SyntaxKind.ObjectLiteral;
6025
- }
6026
- /** If we should check for this specific property */
6027
- function shouldCheckExcessProperty(prop) {
6028
- return (prop.node?.kind === SyntaxKind.ObjectLiteralProperty && prop.node.parent === prop.model?.node);
6029
- }
6030
- function getProperty(model, name) {
6031
- return (model.properties.get(name) ??
6032
- (model.baseModel !== undefined ? getProperty(model.baseModel, name) : undefined));
6033
- }
6034
- function arePropertiesAssignableToIndexer(properties, indexerConstaint, diagnosticTarget, relationCache) {
6035
- for (const prop of properties.values()) {
6036
- const [related, diagnostics] = isTypeAssignableToInternal(prop.type, indexerConstaint, diagnosticTarget, relationCache);
6037
- if (!related) {
6038
- return [Related.false, diagnostics];
6039
- }
6040
- }
6041
- return [Related.true, []];
6042
- }
6043
- /** Check that the source model has an index, the index key match and the value of the source index is assignable to the target index. */
6044
- function hasIndexAndIsAssignableTo(source, target, diagnosticTarget, relationCache) {
6045
- if (source.indexer === undefined || source.indexer.key !== target.indexer.key) {
6046
- return [
6047
- Related.false,
6048
- [
6049
- createDiagnostic({
6050
- code: "missing-index",
6051
- format: {
6052
- indexType: getTypeName(target.indexer.key),
6053
- sourceType: getTypeName(source),
6054
- },
6055
- target: diagnosticTarget,
6056
- }),
6057
- ],
6058
- ];
6059
- }
6060
- return isTypeAssignableToInternal(source.indexer.value, target.indexer.value, diagnosticTarget, relationCache);
6061
- }
6062
- function isTupleAssignableToArray(source, target, diagnosticTarget, relationCache) {
6063
- const minItems = getMinItems(program, target);
6064
- const maxItems = getMaxItems(program, target);
6065
- if (minItems !== undefined && source.values.length < minItems) {
6066
- return [
6067
- Related.false,
6068
- [
6069
- createDiagnostic({
6070
- code: "unassignable",
6071
- messageId: "withDetails",
6072
- format: {
6073
- sourceType: getEntityName(source),
6074
- targetType: getTypeName(target),
6075
- details: `Source has ${source.values.length} element(s) but target requires ${minItems}.`,
6076
- },
6077
- target: diagnosticTarget,
6078
- }),
6079
- ],
6080
- ];
6081
- }
6082
- if (maxItems !== undefined && source.values.length > maxItems) {
6083
- return [
6084
- Related.false,
6085
- [
6086
- createDiagnostic({
6087
- code: "unassignable",
6088
- messageId: "withDetails",
6089
- format: {
6090
- sourceType: getEntityName(source),
6091
- targetType: getTypeName(target),
6092
- details: `Source has ${source.values.length} element(s) but target only allows ${maxItems}.`,
6093
- },
6094
- target: diagnosticTarget,
6095
- }),
6096
- ],
6097
- ];
6098
- }
6099
- for (const item of source.values) {
6100
- const [related, diagnostics] = isTypeAssignableToInternal(item, target.indexer.value, diagnosticTarget, relationCache);
6101
- if (!related) {
6102
- return [Related.false, diagnostics];
6103
- }
6104
- }
6105
- return [Related.true, []];
6106
- }
6107
- function isTupleAssignableToTuple(source, target, diagnosticTarget, relationCache) {
6108
- if (source.values.length !== target.values.length) {
6109
- return [
6110
- Related.false,
6111
- [
6112
- createDiagnostic({
6113
- code: "unassignable",
6114
- messageId: "withDetails",
6115
- format: {
6116
- sourceType: getEntityName(source),
6117
- targetType: getTypeName(target),
6118
- details: `Source has ${source.values.length} element(s) but target requires ${target.values.length}.`,
6119
- },
6120
- target: diagnosticTarget,
6121
- }),
6122
- ],
6123
- ];
6124
- }
6125
- for (const [index, sourceItem] of source.values.entries()) {
6126
- const targetItem = target.values[index];
6127
- const [related, diagnostics] = isTypeAssignableToInternal(sourceItem, targetItem, diagnosticTarget, relationCache);
6128
- if (!related) {
6129
- return [Related.false, diagnostics];
6130
- }
6131
- }
6132
- return [Related.true, []];
6133
- }
6134
- function isAssignableToUnion(source, target, diagnosticTarget, relationCache) {
6135
- if (source.kind === "UnionVariant" && source.union === target) {
6136
- return [Related.true, []];
6137
- }
6138
- for (const option of target.variants.values()) {
6139
- const [related] = isTypeAssignableToInternal(source, option.type, diagnosticTarget, relationCache);
6140
- if (related) {
6141
- return [Related.true, []];
6142
- }
6143
- }
6144
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
6145
- }
6146
- function isAssignableToEnum(source, target, diagnosticTarget) {
6147
- switch (source.kind) {
6148
- case "Enum":
6149
- if (source === target) {
6150
- return [Related.true, []];
6151
- }
6152
- else {
6153
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
6154
- }
6155
- case "EnumMember":
6156
- if (source.enum === target) {
6157
- return [Related.true, []];
6158
- }
6159
- else {
6160
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
6161
- }
6162
- default:
6163
- return [Related.false, [createUnassignableDiagnostic(source, target, diagnosticTarget)]];
6164
- }
6165
- }
6166
- function createUnassignableDiagnostic(source, target, diagnosticTarget) {
6167
- return createDiagnostic({
6168
- code: "unassignable",
6169
- format: { targetType: getEntityName(target), value: getEntityName(source) },
6170
- target: diagnosticTarget,
6171
- });
6172
- }
6173
5643
  function isStdType(type, stdType) {
6174
5644
  type = type.projectionBase ?? type;
6175
5645
  if ((type.kind !== "Model" && type.kind !== "Scalar") ||
@@ -6565,24 +6035,6 @@ function createDecoratorContext(program, decApp) {
6565
6035
  function isTemplatedNode(node) {
6566
6036
  return "templateParameters" in node && node.templateParameters.length > 0;
6567
6037
  }
6568
- /**
6569
- * Mapping from the reflection models to Type["kind"] value
6570
- */
6571
- const ReflectionNameToKind = {
6572
- Enum: "Enum",
6573
- EnumMember: "EnumMember",
6574
- Interface: "Interface",
6575
- Model: "Model",
6576
- ModelProperty: "ModelProperty",
6577
- Namespace: "Namespace",
6578
- Operation: "Operation",
6579
- Scalar: "Scalar",
6580
- TemplateParameter: "TemplateParameter",
6581
- Tuple: "Tuple",
6582
- Union: "Union",
6583
- UnionVariant: "UnionVariant",
6584
- };
6585
- const _assertReflectionNameToKind = ReflectionNameToKind;
6586
6038
  var ResolutionKind;
6587
6039
  (function (ResolutionKind) {
6588
6040
  ResolutionKind[ResolutionKind["Value"] = 0] = "Value";
@@ -6614,12 +6066,6 @@ class PendingResolutions {
6614
6066
  }
6615
6067
  }
6616
6068
  }
6617
- var Related;
6618
- (function (Related) {
6619
- Related[Related["false"] = 0] = "false";
6620
- Related[Related["true"] = 1] = "true";
6621
- Related[Related["maybe"] = 2] = "maybe";
6622
- })(Related || (Related = {}));
6623
6069
  const defaultSymbolResolutionOptions = {
6624
6070
  resolveDecorators: false,
6625
6071
  checkTemplateTypes: true,