@typespec/compiler 1.3.0-dev.9 → 1.3.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.
@@ -25,6 +25,7 @@ import { IdentifierKind, ResolutionResultFlags, SyntaxKind, } from "./types.js";
25
25
  const TypeInstantiationMap = class extends MultiKeyMap {
26
26
  };
27
27
  export function createChecker(program, resolver) {
28
+ const waitingForResolution = new Map();
28
29
  const stats = {
29
30
  createdTypes: 0,
30
31
  finishedTypes: 0,
@@ -41,11 +42,11 @@ export function createChecker(program, resolver) {
41
42
  const globalNamespaceType = createGlobalNamespaceType();
42
43
  // Caches the deprecation test of nodes in the program
43
44
  const nodeDeprecationMap = new Map();
44
- const errorType = createType({ kind: "Intrinsic", name: "ErrorType" });
45
- const voidType = createType({ kind: "Intrinsic", name: "void" });
46
- const neverType = createType({ kind: "Intrinsic", name: "never" });
47
- const unknownType = createType({ kind: "Intrinsic", name: "unknown" });
48
- const nullType = createType({ kind: "Intrinsic", name: "null" });
45
+ const errorType = createAndFinishType({ kind: "Intrinsic", name: "ErrorType" });
46
+ const voidType = createAndFinishType({ kind: "Intrinsic", name: "void" });
47
+ const neverType = createAndFinishType({ kind: "Intrinsic", name: "never" });
48
+ const unknownType = createAndFinishType({ kind: "Intrinsic", name: "unknown" });
49
+ const nullType = createAndFinishType({ kind: "Intrinsic", name: "null" });
49
50
  /**
50
51
  * Set keeping track of node pending type resolution.
51
52
  * Key is the SymId of a node. It can be retrieved with getNodeSymId(node)
@@ -553,6 +554,8 @@ export function createChecker(program, resolver) {
553
554
  pendingResolutions.finish(getNodeSym(node), ResolutionKind.Constraint);
554
555
  }
555
556
  if (node.default) {
557
+ // Set this to unknownType in case the default points back to the template itself causing failures
558
+ type.default = unknownType;
556
559
  type.default = checkTemplateParameterDefault(node.default, parentNode.templateParameters, index, type.constraint);
557
560
  }
558
561
  }
@@ -1119,6 +1122,7 @@ export function createChecker(program, resolver) {
1119
1122
  return Array.from(this.variants.values()).map((v) => v.type);
1120
1123
  },
1121
1124
  expression: true,
1125
+ namespace: getParentNamespaceType(node),
1122
1126
  variants: createRekeyableMap(),
1123
1127
  decorators: [],
1124
1128
  });
@@ -1159,10 +1163,42 @@ export function createChecker(program, resolver) {
1159
1163
  // we're not instantiating this model and we've already checked it
1160
1164
  return links.declaredType;
1161
1165
  }
1166
+ const intersection = initModel(node);
1162
1167
  const options = node.options.map((o) => [o, getTypeForNode(o, mapper)]);
1163
- const type = mergeModelTypes(node.symbol, node, options, mapper);
1164
- linkType(links, type, mapper);
1165
- return type;
1168
+ ensureResolved(options.map(([, type]) => type), intersection, () => {
1169
+ const type = mergeModelTypes(node.symbol, node, options, mapper, intersection);
1170
+ linkType(links, type, mapper);
1171
+ finishType(intersection);
1172
+ });
1173
+ return intersection;
1174
+ }
1175
+ function ensureResolved(types, awaitingType, callback) {
1176
+ const waitingFor = new Set();
1177
+ for (const type of types) {
1178
+ if (type === undefined)
1179
+ continue;
1180
+ if (type.creating) {
1181
+ waitingFor.add(type);
1182
+ }
1183
+ }
1184
+ function check() {
1185
+ if (waitingFor.size === 0) {
1186
+ callback();
1187
+ }
1188
+ }
1189
+ for (const type of waitingFor) {
1190
+ waitingForResolution.set(type, [
1191
+ ...(waitingForResolution.get(type) || []),
1192
+ [
1193
+ awaitingType,
1194
+ () => {
1195
+ waitingFor.delete(type);
1196
+ check();
1197
+ },
1198
+ ],
1199
+ ]);
1200
+ }
1201
+ check();
1166
1202
  }
1167
1203
  function checkDecoratorDeclaration(node, mapper) {
1168
1204
  const symbol = getMergedSymbol(node.symbol);
@@ -1267,18 +1303,8 @@ export function createChecker(program, resolver) {
1267
1303
  };
1268
1304
  }
1269
1305
  }
1270
- function mergeModelTypes(parentModelSym, node, options, mapper) {
1271
- const properties = createRekeyableMap();
1272
- const intersection = createType({
1273
- kind: "Model",
1274
- node,
1275
- name: "",
1276
- namespace: getParentNamespaceType(node),
1277
- properties: properties,
1278
- decorators: [],
1279
- derivedModels: [],
1280
- sourceModels: [],
1281
- });
1306
+ function mergeModelTypes(parentModelSym, node, options, mapper, intersection) {
1307
+ const properties = intersection.properties;
1282
1308
  const indexers = [];
1283
1309
  const modelOptions = options.filter((entry) => {
1284
1310
  const [optionNode, option] = entry;
@@ -1338,7 +1364,7 @@ export function createChecker(program, resolver) {
1338
1364
  else if (indexers.length > 1) {
1339
1365
  intersection.indexer = {
1340
1366
  key: indexers[0].key,
1341
- value: mergeModelTypes(undefined, node, indexers.map((x) => [x.value.node, x.value]), mapper),
1367
+ value: mergeModelTypes(undefined, node, indexers.map((x) => [x.value.node, x.value]), mapper, initModel(node)),
1342
1368
  };
1343
1369
  }
1344
1370
  linkMapper(intersection, mapper);
@@ -1408,7 +1434,8 @@ export function createChecker(program, resolver) {
1408
1434
  if (node === globalNamespaceType.node)
1409
1435
  return undefined;
1410
1436
  if (node.kind === SyntaxKind.ModelExpression ||
1411
- node.kind === SyntaxKind.IntersectionExpression) {
1437
+ node.kind === SyntaxKind.IntersectionExpression ||
1438
+ node.kind === SyntaxKind.UnionExpression) {
1412
1439
  let parent = node.parent;
1413
1440
  while (parent !== undefined) {
1414
1441
  if (parent.kind === SyntaxKind.AliasStatement ||
@@ -1419,7 +1446,8 @@ export function createChecker(program, resolver) {
1419
1446
  parent.kind === SyntaxKind.InterfaceStatement ||
1420
1447
  parent.kind === SyntaxKind.UnionStatement ||
1421
1448
  parent.kind === SyntaxKind.ModelExpression ||
1422
- parent.kind === SyntaxKind.IntersectionExpression) {
1449
+ parent.kind === SyntaxKind.IntersectionExpression ||
1450
+ parent.kind === SyntaxKind.UnionExpression) {
1423
1451
  return getParentNamespaceType(parent);
1424
1452
  }
1425
1453
  else {
@@ -1473,7 +1501,6 @@ export function createChecker(program, resolver) {
1473
1501
  }
1474
1502
  const namespace = getParentNamespaceType(node);
1475
1503
  const name = node.id.sv;
1476
- let decorators = [];
1477
1504
  const { resolvedSymbol: parameterModelSym } = resolver.resolveMetaMemberByName(symbol, "parameters");
1478
1505
  if (parameterModelSym?.members) {
1479
1506
  const members = resolver.getAugmentedSymbolTable(parameterModelSym.members);
@@ -1485,78 +1512,71 @@ export function createChecker(program, resolver) {
1485
1512
  }
1486
1513
  }
1487
1514
  }
1488
- // Is this a definition or reference?
1489
- let parameters, returnType, sourceOperation;
1490
- if (node.signature.kind === SyntaxKind.OperationSignatureReference) {
1491
- // Attempt to resolve the operation
1492
- const baseOperation = checkOperationIs(node, node.signature.baseOperation, mapper);
1493
- if (baseOperation) {
1494
- sourceOperation = baseOperation;
1495
- // Reference the same return type and create the parameters type
1496
- const clone = initializeClone(baseOperation.parameters, {
1497
- properties: createRekeyableMap(),
1498
- });
1499
- clone.properties = createRekeyableMap(Array.from(baseOperation.parameters.properties.entries()).map(([key, prop]) => [
1500
- key,
1501
- cloneTypeForSymbol(getMemberSymbol(parameterModelSym, prop.name), prop, {
1502
- model: clone,
1503
- sourceProperty: prop,
1504
- }),
1505
- ]));
1506
- parameters = finishType(clone);
1507
- returnType = baseOperation.returnType;
1508
- // Copy decorators from the base operation, inserting the base decorators first
1509
- decorators = [...baseOperation.decorators];
1510
- }
1511
- else {
1512
- // If we can't resolve the signature we return an empty model.
1513
- parameters = createAndFinishType({
1514
- kind: "Model",
1515
- name: "",
1516
- decorators: [],
1517
- properties: createRekeyableMap(),
1518
- derivedModels: [],
1519
- sourceModels: [],
1520
- });
1521
- returnType = voidType;
1522
- }
1523
- }
1524
- else {
1525
- parameters = getTypeForNode(node.signature.parameters, mapper);
1526
- returnType = getTypeForNode(node.signature.returnType, mapper);
1527
- }
1528
1515
  const operationType = createType({
1529
1516
  kind: "Operation",
1530
1517
  name,
1531
1518
  namespace,
1519
+ parameters: null,
1520
+ returnType: voidType,
1532
1521
  node,
1533
- parameters,
1534
- returnType,
1535
- decorators,
1536
- sourceOperation,
1522
+ decorators: [],
1537
1523
  interface: parentInterface,
1538
1524
  });
1539
1525
  if (links) {
1540
1526
  linkType(links, operationType, mapper);
1541
1527
  }
1542
- decorators.push(...checkDecorators(operationType, node, mapper));
1543
- operationType.parameters.namespace = namespace;
1544
1528
  const parent = node.parent;
1545
- linkMapper(operationType, mapper);
1546
- if (parent.kind === SyntaxKind.InterfaceStatement) {
1547
- if (shouldCreateTypeForTemplate(parent, mapper) &&
1548
- shouldCreateTypeForTemplate(node, mapper)) {
1549
- finishType(operationType);
1550
- }
1529
+ function finishOperation() {
1530
+ operationType.parameters.namespace = namespace;
1531
+ operationType.decorators.push(...checkDecorators(operationType, node, mapper));
1532
+ const runDecorators = parent.kind === SyntaxKind.InterfaceStatement
1533
+ ? shouldRunDecorators(parent, mapper) && shouldRunDecorators(node, mapper)
1534
+ : shouldRunDecorators(node, mapper);
1535
+ return finishType(operationType, { skipDecorators: !runDecorators });
1551
1536
  }
1552
- else {
1553
- if (shouldCreateTypeForTemplate(node, mapper)) {
1554
- finishType(operationType);
1537
+ // Is this a definition or reference?
1538
+ if (node.signature.kind === SyntaxKind.OperationSignatureReference) {
1539
+ // Attempt to resolve the operation
1540
+ const baseOperation = checkOperationIs(node, node.signature.baseOperation, mapper);
1541
+ if (baseOperation) {
1542
+ ensureResolved([baseOperation], operationType, () => {
1543
+ operationType.sourceOperation = baseOperation;
1544
+ // Reference the same return type and create the parameters type
1545
+ const clone = initializeClone(baseOperation.parameters, {
1546
+ properties: createRekeyableMap(),
1547
+ });
1548
+ clone.properties = createRekeyableMap(Array.from(baseOperation.parameters.properties.entries()).map(([key, prop]) => [
1549
+ key,
1550
+ cloneTypeForSymbol(getMemberSymbol(parameterModelSym, prop.name), prop, {
1551
+ model: clone,
1552
+ sourceProperty: prop,
1553
+ }),
1554
+ ]));
1555
+ operationType.parameters = finishType(clone);
1556
+ operationType.returnType = baseOperation.returnType;
1557
+ // Copy decorators from the base operation, inserting the base decorators first
1558
+ operationType.decorators.push(...baseOperation.decorators);
1559
+ finishOperation();
1560
+ });
1555
1561
  }
1556
- if (mapper === undefined) {
1557
- namespace?.operations.set(name, operationType);
1562
+ else {
1563
+ // If we can't resolve the signature we return an empty model.
1564
+ operationType.parameters = initModel();
1565
+ operationType.returnType = voidType;
1566
+ finishOperation();
1558
1567
  }
1559
1568
  }
1569
+ else {
1570
+ operationType.parameters = getTypeForNode(node.signature.parameters, mapper);
1571
+ operationType.returnType = getTypeForNode(node.signature.returnType, mapper);
1572
+ ensureResolved([operationType.parameters], operationType, () => {
1573
+ finishOperation();
1574
+ });
1575
+ }
1576
+ linkMapper(operationType, mapper);
1577
+ if (parent.kind !== SyntaxKind.InterfaceStatement && mapper === undefined) {
1578
+ namespace?.operations.set(name, operationType);
1579
+ }
1560
1580
  return operationType;
1561
1581
  }
1562
1582
  function checkOperationIs(operation, opReference, mapper) {
@@ -2416,6 +2436,20 @@ export function createChecker(program, resolver) {
2416
2436
  checkSourceFile(file);
2417
2437
  }
2418
2438
  internalDecoratorValidation();
2439
+ assertNoPendingResolutions();
2440
+ }
2441
+ function assertNoPendingResolutions() {
2442
+ if (waitingForResolution.size === 0) {
2443
+ return;
2444
+ }
2445
+ const message = [
2446
+ "Unexpected pending resolutions found",
2447
+ ...[...waitingForResolution.entries()].flatMap(([type, items]) => {
2448
+ const base = ` (${type.kind}) ${getTypeName(type)} => `;
2449
+ return items.map(([item], index) => `${index === 0 ? base : " ".repeat(base.length)}${getTypeName(item)}`);
2450
+ }),
2451
+ ].join("\n");
2452
+ compilerAssert(false, message);
2419
2453
  }
2420
2454
  function checkDuplicateSymbols() {
2421
2455
  program.reportDuplicateSymbols(resolver.symbols.global.exports);
@@ -2520,65 +2554,67 @@ export function createChecker(program, resolver) {
2520
2554
  }
2521
2555
  }
2522
2556
  const isBase = checkModelIs(node, node.is, mapper);
2523
- if (isBase) {
2524
- type.sourceModel = isBase;
2525
- type.sourceModels.push({ usage: "is", model: isBase });
2526
- // copy decorators
2527
- decorators.push(...isBase.decorators);
2528
- if (isBase.indexer) {
2529
- type.indexer = isBase.indexer;
2530
- }
2531
- }
2532
- if (isBase) {
2533
- for (const prop of isBase.properties.values()) {
2534
- const memberSym = getMemberSymbol(node.symbol, prop.name);
2535
- const newProp = cloneTypeForSymbol(memberSym, prop, {
2536
- sourceProperty: prop,
2537
- model: type,
2538
- });
2539
- linkIndirectMember(node, newProp, mapper);
2540
- type.properties.set(prop.name, newProp);
2557
+ ensureResolved([
2558
+ isBase,
2559
+ ...node.properties
2560
+ .filter((x) => x.kind === SyntaxKind.ModelSpreadProperty)
2561
+ .map((x) => checkSpreadTarget(node, x.target, mapper)),
2562
+ ], type, () => {
2563
+ if (isBase) {
2564
+ type.sourceModel = isBase;
2565
+ type.sourceModels.push({ usage: "is", model: isBase });
2566
+ decorators.push(...isBase.decorators);
2567
+ if (isBase.indexer) {
2568
+ type.indexer = isBase.indexer;
2569
+ }
2570
+ for (const prop of isBase.properties.values()) {
2571
+ const memberSym = getMemberSymbol(node.symbol, prop.name);
2572
+ const newProp = cloneTypeForSymbol(memberSym, prop, {
2573
+ sourceProperty: prop,
2574
+ model: type,
2575
+ });
2576
+ linkIndirectMember(node, newProp, mapper);
2577
+ type.properties.set(prop.name, newProp);
2578
+ }
2579
+ }
2580
+ if (isBase) {
2581
+ type.baseModel = isBase.baseModel;
2582
+ }
2583
+ else if (node.extends) {
2584
+ type.baseModel = checkClassHeritage(node, node.extends, mapper);
2585
+ if (type.baseModel) {
2586
+ copyDeprecation(type.baseModel, type);
2587
+ }
2541
2588
  }
2542
- }
2543
- if (isBase) {
2544
- type.baseModel = isBase.baseModel;
2545
- }
2546
- else if (node.extends) {
2547
- type.baseModel = checkClassHeritage(node, node.extends, mapper);
2548
2589
  if (type.baseModel) {
2549
- copyDeprecation(type.baseModel, type);
2590
+ type.baseModel.derivedModels.push(type);
2550
2591
  }
2551
- }
2552
- if (type.baseModel) {
2553
- type.baseModel.derivedModels.push(type);
2554
- }
2555
- // Hold on to the model type that's being defined so that it
2556
- // can be referenced
2557
- if (mapper === undefined) {
2558
- type.namespace?.models.set(type.name, type);
2559
- }
2560
- // Evaluate the properties after
2561
- checkModelProperties(node, type.properties, type, mapper);
2562
- decorators.push(...checkDecorators(type, node, mapper));
2563
- linkMapper(type, mapper);
2564
- if (shouldCreateTypeForTemplate(node, mapper)) {
2565
- finishType(type);
2566
- }
2567
- const indexer = getIndexer(program, type);
2568
- if (type.name === "Array" && isInTypeSpecNamespace(type)) {
2569
- stdTypes.Array = type;
2570
- }
2571
- else if (type.name === "Record" && isInTypeSpecNamespace(type)) {
2572
- stdTypes.Record = type;
2573
- }
2574
- if (indexer) {
2575
- type.indexer = indexer;
2576
- }
2577
- lateBindMemberContainer(type);
2578
- lateBindMembers(type);
2592
+ // Hold on to the model type that's being defined so that it
2593
+ // can be referenced
2594
+ if (mapper === undefined) {
2595
+ type.namespace?.models.set(type.name, type);
2596
+ }
2597
+ // Evaluate the properties after
2598
+ checkModelProperties(node, type.properties, type, mapper);
2599
+ decorators.push(...checkDecorators(type, node, mapper));
2600
+ linkMapper(type, mapper);
2601
+ finishType(type, { skipDecorators: !shouldRunDecorators(node, mapper) });
2602
+ lateBindMemberContainer(type);
2603
+ lateBindMembers(type);
2604
+ const indexer = getIndexer(program, type);
2605
+ if (type.name === "Array" && isInTypeSpecNamespace(type)) {
2606
+ stdTypes.Array = type;
2607
+ }
2608
+ else if (type.name === "Record" && isInTypeSpecNamespace(type)) {
2609
+ stdTypes.Record = type;
2610
+ }
2611
+ if (indexer) {
2612
+ type.indexer = indexer;
2613
+ }
2614
+ });
2579
2615
  return type;
2580
2616
  }
2581
- function shouldCreateTypeForTemplate(node, mapper) {
2617
+ function shouldRunDecorators(node, mapper) {
2582
2618
  // Node is not a template we should create the type.
2583
2619
  if (node.templateParameters.length === 0) {
2584
2620
  return true;
@@ -2597,22 +2633,17 @@ export function createChecker(program, resolver) {
2597
2633
  // we're not instantiating this model and we've already checked it
2598
2634
  return links.declaredType;
2599
2635
  }
2600
- const properties = createRekeyableMap();
2601
- const type = createType({
2602
- kind: "Model",
2603
- name: "",
2604
- node: node,
2605
- properties,
2606
- indexer: undefined,
2607
- namespace: getParentNamespaceType(node),
2608
- decorators: [],
2609
- derivedModels: [],
2610
- sourceModels: [],
2611
- });
2636
+ const type = initModel(node);
2637
+ const properties = type.properties;
2612
2638
  linkType(links, type, mapper);
2613
2639
  linkMapper(type, mapper);
2614
- checkModelProperties(node, properties, type, mapper);
2615
- return finishType(type);
2640
+ ensureResolved(node.properties
2641
+ .filter((x) => x.kind === SyntaxKind.ModelSpreadProperty)
2642
+ .map((x) => checkSpreadTarget(node, x.target, mapper)), type, () => {
2643
+ checkModelProperties(node, properties, type, mapper);
2644
+ finishType(type);
2645
+ });
2646
+ return type;
2616
2647
  }
2617
2648
  /** Find the indexer that applies to this model. Either defined on itself or from a base model */
2618
2649
  function findIndexer(model) {
@@ -3331,6 +3362,23 @@ export function createChecker(program, resolver) {
3331
3362
  }
3332
3363
  return isType;
3333
3364
  }
3365
+ /** Get the type for the spread target */
3366
+ function checkSpreadTarget(model, target, mapper) {
3367
+ const modelSymId = getNodeSym(model);
3368
+ const targetSym = resolver.getNodeLinks(target).resolvedSymbol;
3369
+ if (targetSym === modelSymId) {
3370
+ if (mapper === undefined) {
3371
+ reportCheckerDiagnostic(createDiagnostic({
3372
+ code: "spread-model",
3373
+ messageId: "selfSpread",
3374
+ target: target,
3375
+ }));
3376
+ }
3377
+ return undefined;
3378
+ }
3379
+ const type = getTypeForNode(target, mapper);
3380
+ return type;
3381
+ }
3334
3382
  function checkSpreadProperty(parentModelSym, targetNode, parentModel, mapper) {
3335
3383
  const targetType = getTypeForNode(targetNode, mapper);
3336
3384
  if (targetType.kind === "TemplateParameter" || isErrorType(targetType)) {
@@ -3344,13 +3392,6 @@ export function createChecker(program, resolver) {
3344
3392
  reportCheckerDiagnostic(createDiagnostic({ code: "spread-model", target: targetNode }), mapper);
3345
3393
  return [[], undefined];
3346
3394
  }
3347
- if (parentModel === targetType) {
3348
- reportCheckerDiagnostic(createDiagnostic({
3349
- code: "spread-model",
3350
- messageId: "selfSpread",
3351
- target: targetNode,
3352
- }));
3353
- }
3354
3395
  parentModel.sourceModels.push({ usage: "spread", model: targetType });
3355
3396
  const props = [];
3356
3397
  // copy each property
@@ -3422,15 +3463,16 @@ export function createChecker(program, resolver) {
3422
3463
  type.decorators = checkDecorators(type, prop, mapper);
3423
3464
  const parentTemplate = getParentTemplateNode(prop);
3424
3465
  linkMapper(type, mapper);
3425
- if (!parentTemplate || shouldCreateTypeForTemplate(parentTemplate, mapper)) {
3466
+ let runDecorators = false;
3467
+ if (!parentTemplate || shouldRunDecorators(parentTemplate, mapper)) {
3426
3468
  const docComment = docFromCommentForSym.get(sym);
3427
3469
  if (docComment) {
3428
3470
  type.decorators.unshift(createDocFromCommentDecorator("self", docComment));
3429
3471
  }
3430
- finishType(type);
3472
+ runDecorators = true;
3431
3473
  }
3432
3474
  pendingResolutions.finish(sym, ResolutionKind.Type);
3433
- return type;
3475
+ return finishType(type, { skipDecorators: !runDecorators });
3434
3476
  }
3435
3477
  function createDocFromCommentDecorator(key, doc) {
3436
3478
  return {
@@ -3806,13 +3848,10 @@ export function createChecker(program, resolver) {
3806
3848
  type.namespace?.scalars.set(type.name, type);
3807
3849
  }
3808
3850
  linkMapper(type, mapper);
3809
- if (shouldCreateTypeForTemplate(node, mapper)) {
3810
- finishType(type);
3811
- }
3812
3851
  if (isInTypeSpecNamespace(type)) {
3813
3852
  stdTypes[type.name] = type;
3814
3853
  }
3815
- return type;
3854
+ return finishType(type, { skipDecorators: !shouldRunDecorators(node, mapper) });
3816
3855
  }
3817
3856
  function checkScalarExtends(scalar, extendsRef, mapper) {
3818
3857
  const symId = getNodeSym(scalar);
@@ -3879,13 +3918,12 @@ export function createChecker(program, resolver) {
3879
3918
  parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, false)),
3880
3919
  });
3881
3920
  linkMapper(member, mapper);
3882
- if (shouldCreateTypeForTemplate(node.parent, mapper)) {
3883
- finishType(member);
3884
- }
3885
3921
  if (links) {
3886
3922
  linkType(links, member, mapper);
3887
3923
  }
3888
- return finishType(member);
3924
+ return finishType(member, {
3925
+ skipDecorators: !shouldRunDecorators(node.parent, mapper),
3926
+ });
3889
3927
  }
3890
3928
  function checkAlias(node, mapper) {
3891
3929
  const links = getSymbolLinks(node.symbol);
@@ -4054,15 +4092,14 @@ export function createChecker(program, resolver) {
4054
4092
  interfaceType.operations.set(key, value);
4055
4093
  }
4056
4094
  linkMapper(interfaceType, mapper);
4057
- if (shouldCreateTypeForTemplate(node, mapper)) {
4058
- finishType(interfaceType);
4059
- }
4060
4095
  if (mapper === undefined) {
4061
4096
  interfaceType.namespace?.interfaces.set(interfaceType.name, interfaceType);
4062
4097
  }
4063
4098
  lateBindMemberContainer(interfaceType);
4064
4099
  lateBindMembers(interfaceType);
4065
- return interfaceType;
4100
+ return finishType(interfaceType, {
4101
+ skipDecorators: !shouldRunDecorators(node, mapper),
4102
+ });
4066
4103
  }
4067
4104
  function checkInterfaceMembers(node, mapper, interfaceType) {
4068
4105
  const ownMembers = new Map();
@@ -4104,15 +4141,12 @@ export function createChecker(program, resolver) {
4104
4141
  unionType.decorators = checkDecorators(unionType, node, mapper);
4105
4142
  checkUnionVariants(unionType, node, variants, mapper);
4106
4143
  linkMapper(unionType, mapper);
4107
- if (shouldCreateTypeForTemplate(node, mapper)) {
4108
- finishType(unionType);
4109
- }
4110
4144
  if (mapper === undefined) {
4111
4145
  unionType.namespace?.unions.set(unionType.name, unionType);
4112
4146
  }
4113
4147
  lateBindMemberContainer(unionType);
4114
4148
  lateBindMembers(unionType);
4115
- return unionType;
4149
+ return finishType(unionType, { skipDecorators: !shouldRunDecorators(node, mapper) });
4116
4150
  }
4117
4151
  function checkUnionVariants(parentUnion, node, variants, mapper) {
4118
4152
  for (const variantNode of node.options) {
@@ -4147,13 +4181,12 @@ export function createChecker(program, resolver) {
4147
4181
  });
4148
4182
  variantType.decorators = checkDecorators(variantType, variantNode, mapper);
4149
4183
  linkMapper(variantType, mapper);
4150
- if (shouldCreateTypeForTemplate(variantNode.parent, mapper)) {
4151
- finishType(variantType);
4152
- }
4153
4184
  if (links) {
4154
4185
  linkType(links, variantType, mapper);
4155
4186
  }
4156
- return variantType;
4187
+ return finishType(variantType, {
4188
+ skipDecorators: !shouldRunDecorators(variantNode.parent, mapper),
4189
+ });
4157
4190
  }
4158
4191
  function isMemberNode(node) {
4159
4192
  return node.symbol && !!(node.symbol.flags & 65536 /* SymbolFlags.Member */);
@@ -4268,6 +4301,19 @@ export function createChecker(program, resolver) {
4268
4301
  createType(typeDef);
4269
4302
  return finishType(typeDef);
4270
4303
  }
4304
+ /** Initialize model type for the given node */
4305
+ function initModel(node) {
4306
+ return createType({
4307
+ kind: "Model",
4308
+ node,
4309
+ name: "",
4310
+ namespace: node && getParentNamespaceType(node),
4311
+ properties: createRekeyableMap(),
4312
+ decorators: [],
4313
+ derivedModels: [],
4314
+ sourceModels: [],
4315
+ });
4316
+ }
4271
4317
  /**
4272
4318
  * Given the own-properties of a type, returns a fully-initialized type.
4273
4319
  */
@@ -4275,6 +4321,7 @@ export function createChecker(program, resolver) {
4275
4321
  stats.createdTypes++;
4276
4322
  Object.setPrototypeOf(typeDef, typePrototype);
4277
4323
  typeDef.isFinished = false;
4324
+ typeDef.creating = true;
4278
4325
  // If the type has an associated syntax node, check any directives that
4279
4326
  // might be attached.
4280
4327
  const createdType = typeDef;
@@ -4284,9 +4331,29 @@ export function createChecker(program, resolver) {
4284
4331
  }
4285
4332
  return createdType;
4286
4333
  }
4287
- function finishType(typeDef) {
4334
+ function finishType(typeDef, options = {}) {
4288
4335
  stats.finishedTypes++;
4289
- return finishTypeForProgramAndChecker(program, typePrototype, typeDef);
4336
+ if (!options.skipDecorators) {
4337
+ if ("decorators" in typeDef) {
4338
+ for (const decApp of typeDef.decorators) {
4339
+ applyDecoratorToType(program, decApp, typeDef);
4340
+ }
4341
+ }
4342
+ typeDef.isFinished = true;
4343
+ Object.setPrototypeOf(typeDef, typePrototype);
4344
+ }
4345
+ markAsChecked(typeDef);
4346
+ return typeDef;
4347
+ }
4348
+ function markAsChecked(type) {
4349
+ if (!type.creating)
4350
+ return;
4351
+ delete type.creating;
4352
+ const pending = waitingForResolution.get(type);
4353
+ if (pending) {
4354
+ pending.forEach(([_, resolution]) => resolution());
4355
+ }
4356
+ waitingForResolution.delete(type);
4290
4357
  }
4291
4358
  function getLiteralType(node) {
4292
4359
  return createLiteralType(node.value, node);
@@ -4409,12 +4476,9 @@ export function createChecker(program, resolver) {
4409
4476
  * recursively by the caller.
4410
4477
  */
4411
4478
  function cloneType(type, additionalProps = {}) {
4412
- let clone = initializeClone(type, additionalProps);
4413
- if (type.isFinished) {
4414
- clone = finishType(clone);
4415
- }
4479
+ const clone = initializeClone(type, additionalProps);
4416
4480
  compilerAssert(clone.kind === type.kind, "cloneType must not change type kind");
4417
- return clone;
4481
+ return finishType(clone, { skipDecorators: !type.isFinished });
4418
4482
  }
4419
4483
  /**
4420
4484
  * Clone a type linking to the given symbol.
@@ -4470,7 +4534,7 @@ export function createChecker(program, resolver) {
4470
4534
  break;
4471
4535
  }
4472
4536
  program.literalTypes.set(value, type);
4473
- return type;
4537
+ return finishType(type);
4474
4538
  }
4475
4539
  /**
4476
4540
  * Check if the source type can be assigned to the target type and emit diagnostics
@@ -4705,7 +4769,7 @@ export function filterModelProperties(program, model, filter) {
4705
4769
  typekit.type.finishType(newProperty);
4706
4770
  }
4707
4771
  }
4708
- return finishTypeForProgram(program, newModel);
4772
+ return program.checker.finishType(newModel);
4709
4773
  }
4710
4774
  /**
4711
4775
  * Gets the property from the nearest base type that is overridden by the
@@ -4751,9 +4815,6 @@ function countPropertiesInherited(model, filter) {
4751
4815
  }
4752
4816
  return count;
4753
4817
  }
4754
- export function finishTypeForProgram(program, typeDef) {
4755
- return finishTypeForProgramAndChecker(program, program.checker.typePrototype, typeDef);
4756
- }
4757
4818
  function linkMapper(typeDef, mapper) {
4758
4819
  if (mapper) {
4759
4820
  compilerAssert(!typeDef.templateMapper, "Mapper provided but template arguments already set.");
@@ -4827,16 +4888,6 @@ function getDocContent(content) {
4827
4888
  }
4828
4889
  return docs.join("");
4829
4890
  }
4830
- function finishTypeForProgramAndChecker(program, typePrototype, typeDef) {
4831
- if ("decorators" in typeDef) {
4832
- for (const decApp of typeDef.decorators) {
4833
- applyDecoratorToType(program, decApp, typeDef);
4834
- }
4835
- }
4836
- Object.setPrototypeOf(typeDef, typePrototype);
4837
- typeDef.isFinished = true;
4838
- return typeDef;
4839
- }
4840
4891
  function reportDeprecation(program, target, message, reportFunc) {
4841
4892
  if (program.compilerOptions.ignoreDeprecated !== true) {
4842
4893
  reportFunc(createDiagnostic({