@typespec/compiler 1.3.0-dev.10 → 1.3.0-dev.11

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
  }
@@ -1160,10 +1163,42 @@ export function createChecker(program, resolver) {
1160
1163
  // we're not instantiating this model and we've already checked it
1161
1164
  return links.declaredType;
1162
1165
  }
1166
+ const intersection = initModel(node);
1163
1167
  const options = node.options.map((o) => [o, getTypeForNode(o, mapper)]);
1164
- const type = mergeModelTypes(node.symbol, node, options, mapper);
1165
- linkType(links, type, mapper);
1166
- 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();
1167
1202
  }
1168
1203
  function checkDecoratorDeclaration(node, mapper) {
1169
1204
  const symbol = getMergedSymbol(node.symbol);
@@ -1268,18 +1303,8 @@ export function createChecker(program, resolver) {
1268
1303
  };
1269
1304
  }
1270
1305
  }
1271
- function mergeModelTypes(parentModelSym, node, options, mapper) {
1272
- const properties = createRekeyableMap();
1273
- const intersection = createType({
1274
- kind: "Model",
1275
- node,
1276
- name: "",
1277
- namespace: getParentNamespaceType(node),
1278
- properties: properties,
1279
- decorators: [],
1280
- derivedModels: [],
1281
- sourceModels: [],
1282
- });
1306
+ function mergeModelTypes(parentModelSym, node, options, mapper, intersection) {
1307
+ const properties = intersection.properties;
1283
1308
  const indexers = [];
1284
1309
  const modelOptions = options.filter((entry) => {
1285
1310
  const [optionNode, option] = entry;
@@ -1339,7 +1364,7 @@ export function createChecker(program, resolver) {
1339
1364
  else if (indexers.length > 1) {
1340
1365
  intersection.indexer = {
1341
1366
  key: indexers[0].key,
1342
- 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)),
1343
1368
  };
1344
1369
  }
1345
1370
  linkMapper(intersection, mapper);
@@ -1476,7 +1501,6 @@ export function createChecker(program, resolver) {
1476
1501
  }
1477
1502
  const namespace = getParentNamespaceType(node);
1478
1503
  const name = node.id.sv;
1479
- let decorators = [];
1480
1504
  const { resolvedSymbol: parameterModelSym } = resolver.resolveMetaMemberByName(symbol, "parameters");
1481
1505
  if (parameterModelSym?.members) {
1482
1506
  const members = resolver.getAugmentedSymbolTable(parameterModelSym.members);
@@ -1488,78 +1512,71 @@ export function createChecker(program, resolver) {
1488
1512
  }
1489
1513
  }
1490
1514
  }
1491
- // Is this a definition or reference?
1492
- let parameters, returnType, sourceOperation;
1493
- if (node.signature.kind === SyntaxKind.OperationSignatureReference) {
1494
- // Attempt to resolve the operation
1495
- const baseOperation = checkOperationIs(node, node.signature.baseOperation, mapper);
1496
- if (baseOperation) {
1497
- sourceOperation = baseOperation;
1498
- // Reference the same return type and create the parameters type
1499
- const clone = initializeClone(baseOperation.parameters, {
1500
- properties: createRekeyableMap(),
1501
- });
1502
- clone.properties = createRekeyableMap(Array.from(baseOperation.parameters.properties.entries()).map(([key, prop]) => [
1503
- key,
1504
- cloneTypeForSymbol(getMemberSymbol(parameterModelSym, prop.name), prop, {
1505
- model: clone,
1506
- sourceProperty: prop,
1507
- }),
1508
- ]));
1509
- parameters = finishType(clone);
1510
- returnType = baseOperation.returnType;
1511
- // Copy decorators from the base operation, inserting the base decorators first
1512
- decorators = [...baseOperation.decorators];
1513
- }
1514
- else {
1515
- // If we can't resolve the signature we return an empty model.
1516
- parameters = createAndFinishType({
1517
- kind: "Model",
1518
- name: "",
1519
- decorators: [],
1520
- properties: createRekeyableMap(),
1521
- derivedModels: [],
1522
- sourceModels: [],
1523
- });
1524
- returnType = voidType;
1525
- }
1526
- }
1527
- else {
1528
- parameters = getTypeForNode(node.signature.parameters, mapper);
1529
- returnType = getTypeForNode(node.signature.returnType, mapper);
1530
- }
1531
1515
  const operationType = createType({
1532
1516
  kind: "Operation",
1533
1517
  name,
1534
1518
  namespace,
1519
+ parameters: null,
1520
+ returnType: voidType,
1535
1521
  node,
1536
- parameters,
1537
- returnType,
1538
- decorators,
1539
- sourceOperation,
1522
+ decorators: [],
1540
1523
  interface: parentInterface,
1541
1524
  });
1542
1525
  if (links) {
1543
1526
  linkType(links, operationType, mapper);
1544
1527
  }
1545
- decorators.push(...checkDecorators(operationType, node, mapper));
1546
- operationType.parameters.namespace = namespace;
1547
1528
  const parent = node.parent;
1548
- linkMapper(operationType, mapper);
1549
- if (parent.kind === SyntaxKind.InterfaceStatement) {
1550
- if (shouldCreateTypeForTemplate(parent, mapper) &&
1551
- shouldCreateTypeForTemplate(node, mapper)) {
1552
- finishType(operationType);
1553
- }
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 });
1554
1536
  }
1555
- else {
1556
- if (shouldCreateTypeForTemplate(node, mapper)) {
1557
- 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
+ });
1558
1561
  }
1559
- if (mapper === undefined) {
1560
- 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();
1561
1567
  }
1562
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
+ }
1563
1580
  return operationType;
1564
1581
  }
1565
1582
  function checkOperationIs(operation, opReference, mapper) {
@@ -2419,6 +2436,20 @@ export function createChecker(program, resolver) {
2419
2436
  checkSourceFile(file);
2420
2437
  }
2421
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);
2422
2453
  }
2423
2454
  function checkDuplicateSymbols() {
2424
2455
  program.reportDuplicateSymbols(resolver.symbols.global.exports);
@@ -2523,65 +2554,67 @@ export function createChecker(program, resolver) {
2523
2554
  }
2524
2555
  }
2525
2556
  const isBase = checkModelIs(node, node.is, mapper);
2526
- if (isBase) {
2527
- type.sourceModel = isBase;
2528
- type.sourceModels.push({ usage: "is", model: isBase });
2529
- // copy decorators
2530
- decorators.push(...isBase.decorators);
2531
- if (isBase.indexer) {
2532
- type.indexer = isBase.indexer;
2533
- }
2534
- }
2535
- if (isBase) {
2536
- for (const prop of isBase.properties.values()) {
2537
- const memberSym = getMemberSymbol(node.symbol, prop.name);
2538
- const newProp = cloneTypeForSymbol(memberSym, prop, {
2539
- sourceProperty: prop,
2540
- model: type,
2541
- });
2542
- linkIndirectMember(node, newProp, mapper);
2543
- 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
+ }
2544
2588
  }
2545
- }
2546
- if (isBase) {
2547
- type.baseModel = isBase.baseModel;
2548
- }
2549
- else if (node.extends) {
2550
- type.baseModel = checkClassHeritage(node, node.extends, mapper);
2551
2589
  if (type.baseModel) {
2552
- copyDeprecation(type.baseModel, type);
2590
+ type.baseModel.derivedModels.push(type);
2553
2591
  }
2554
- }
2555
- if (type.baseModel) {
2556
- type.baseModel.derivedModels.push(type);
2557
- }
2558
- // Hold on to the model type that's being defined so that it
2559
- // can be referenced
2560
- if (mapper === undefined) {
2561
- type.namespace?.models.set(type.name, type);
2562
- }
2563
- // Evaluate the properties after
2564
- checkModelProperties(node, type.properties, type, mapper);
2565
- decorators.push(...checkDecorators(type, node, mapper));
2566
- linkMapper(type, mapper);
2567
- if (shouldCreateTypeForTemplate(node, mapper)) {
2568
- finishType(type);
2569
- }
2570
- const indexer = getIndexer(program, type);
2571
- if (type.name === "Array" && isInTypeSpecNamespace(type)) {
2572
- stdTypes.Array = type;
2573
- }
2574
- else if (type.name === "Record" && isInTypeSpecNamespace(type)) {
2575
- stdTypes.Record = type;
2576
- }
2577
- if (indexer) {
2578
- type.indexer = indexer;
2579
- }
2580
- lateBindMemberContainer(type);
2581
- 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
+ });
2582
2615
  return type;
2583
2616
  }
2584
- function shouldCreateTypeForTemplate(node, mapper) {
2617
+ function shouldRunDecorators(node, mapper) {
2585
2618
  // Node is not a template we should create the type.
2586
2619
  if (node.templateParameters.length === 0) {
2587
2620
  return true;
@@ -2600,22 +2633,17 @@ export function createChecker(program, resolver) {
2600
2633
  // we're not instantiating this model and we've already checked it
2601
2634
  return links.declaredType;
2602
2635
  }
2603
- const properties = createRekeyableMap();
2604
- const type = createType({
2605
- kind: "Model",
2606
- name: "",
2607
- node: node,
2608
- properties,
2609
- indexer: undefined,
2610
- namespace: getParentNamespaceType(node),
2611
- decorators: [],
2612
- derivedModels: [],
2613
- sourceModels: [],
2614
- });
2636
+ const type = initModel(node);
2637
+ const properties = type.properties;
2615
2638
  linkType(links, type, mapper);
2616
2639
  linkMapper(type, mapper);
2617
- checkModelProperties(node, properties, type, mapper);
2618
- 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;
2619
2647
  }
2620
2648
  /** Find the indexer that applies to this model. Either defined on itself or from a base model */
2621
2649
  function findIndexer(model) {
@@ -3334,6 +3362,23 @@ export function createChecker(program, resolver) {
3334
3362
  }
3335
3363
  return isType;
3336
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
+ }
3337
3382
  function checkSpreadProperty(parentModelSym, targetNode, parentModel, mapper) {
3338
3383
  const targetType = getTypeForNode(targetNode, mapper);
3339
3384
  if (targetType.kind === "TemplateParameter" || isErrorType(targetType)) {
@@ -3347,13 +3392,6 @@ export function createChecker(program, resolver) {
3347
3392
  reportCheckerDiagnostic(createDiagnostic({ code: "spread-model", target: targetNode }), mapper);
3348
3393
  return [[], undefined];
3349
3394
  }
3350
- if (parentModel === targetType) {
3351
- reportCheckerDiagnostic(createDiagnostic({
3352
- code: "spread-model",
3353
- messageId: "selfSpread",
3354
- target: targetNode,
3355
- }));
3356
- }
3357
3395
  parentModel.sourceModels.push({ usage: "spread", model: targetType });
3358
3396
  const props = [];
3359
3397
  // copy each property
@@ -3425,15 +3463,16 @@ export function createChecker(program, resolver) {
3425
3463
  type.decorators = checkDecorators(type, prop, mapper);
3426
3464
  const parentTemplate = getParentTemplateNode(prop);
3427
3465
  linkMapper(type, mapper);
3428
- if (!parentTemplate || shouldCreateTypeForTemplate(parentTemplate, mapper)) {
3466
+ let runDecorators = false;
3467
+ if (!parentTemplate || shouldRunDecorators(parentTemplate, mapper)) {
3429
3468
  const docComment = docFromCommentForSym.get(sym);
3430
3469
  if (docComment) {
3431
3470
  type.decorators.unshift(createDocFromCommentDecorator("self", docComment));
3432
3471
  }
3433
- finishType(type);
3472
+ runDecorators = true;
3434
3473
  }
3435
3474
  pendingResolutions.finish(sym, ResolutionKind.Type);
3436
- return type;
3475
+ return finishType(type, { skipDecorators: !runDecorators });
3437
3476
  }
3438
3477
  function createDocFromCommentDecorator(key, doc) {
3439
3478
  return {
@@ -3809,13 +3848,10 @@ export function createChecker(program, resolver) {
3809
3848
  type.namespace?.scalars.set(type.name, type);
3810
3849
  }
3811
3850
  linkMapper(type, mapper);
3812
- if (shouldCreateTypeForTemplate(node, mapper)) {
3813
- finishType(type);
3814
- }
3815
3851
  if (isInTypeSpecNamespace(type)) {
3816
3852
  stdTypes[type.name] = type;
3817
3853
  }
3818
- return type;
3854
+ return finishType(type, { skipDecorators: !shouldRunDecorators(node, mapper) });
3819
3855
  }
3820
3856
  function checkScalarExtends(scalar, extendsRef, mapper) {
3821
3857
  const symId = getNodeSym(scalar);
@@ -3882,13 +3918,12 @@ export function createChecker(program, resolver) {
3882
3918
  parameters: node.parameters.map((x) => checkFunctionParameter(x, mapper, false)),
3883
3919
  });
3884
3920
  linkMapper(member, mapper);
3885
- if (shouldCreateTypeForTemplate(node.parent, mapper)) {
3886
- finishType(member);
3887
- }
3888
3921
  if (links) {
3889
3922
  linkType(links, member, mapper);
3890
3923
  }
3891
- return finishType(member);
3924
+ return finishType(member, {
3925
+ skipDecorators: !shouldRunDecorators(node.parent, mapper),
3926
+ });
3892
3927
  }
3893
3928
  function checkAlias(node, mapper) {
3894
3929
  const links = getSymbolLinks(node.symbol);
@@ -4057,15 +4092,14 @@ export function createChecker(program, resolver) {
4057
4092
  interfaceType.operations.set(key, value);
4058
4093
  }
4059
4094
  linkMapper(interfaceType, mapper);
4060
- if (shouldCreateTypeForTemplate(node, mapper)) {
4061
- finishType(interfaceType);
4062
- }
4063
4095
  if (mapper === undefined) {
4064
4096
  interfaceType.namespace?.interfaces.set(interfaceType.name, interfaceType);
4065
4097
  }
4066
4098
  lateBindMemberContainer(interfaceType);
4067
4099
  lateBindMembers(interfaceType);
4068
- return interfaceType;
4100
+ return finishType(interfaceType, {
4101
+ skipDecorators: !shouldRunDecorators(node, mapper),
4102
+ });
4069
4103
  }
4070
4104
  function checkInterfaceMembers(node, mapper, interfaceType) {
4071
4105
  const ownMembers = new Map();
@@ -4107,15 +4141,12 @@ export function createChecker(program, resolver) {
4107
4141
  unionType.decorators = checkDecorators(unionType, node, mapper);
4108
4142
  checkUnionVariants(unionType, node, variants, mapper);
4109
4143
  linkMapper(unionType, mapper);
4110
- if (shouldCreateTypeForTemplate(node, mapper)) {
4111
- finishType(unionType);
4112
- }
4113
4144
  if (mapper === undefined) {
4114
4145
  unionType.namespace?.unions.set(unionType.name, unionType);
4115
4146
  }
4116
4147
  lateBindMemberContainer(unionType);
4117
4148
  lateBindMembers(unionType);
4118
- return unionType;
4149
+ return finishType(unionType, { skipDecorators: !shouldRunDecorators(node, mapper) });
4119
4150
  }
4120
4151
  function checkUnionVariants(parentUnion, node, variants, mapper) {
4121
4152
  for (const variantNode of node.options) {
@@ -4150,13 +4181,12 @@ export function createChecker(program, resolver) {
4150
4181
  });
4151
4182
  variantType.decorators = checkDecorators(variantType, variantNode, mapper);
4152
4183
  linkMapper(variantType, mapper);
4153
- if (shouldCreateTypeForTemplate(variantNode.parent, mapper)) {
4154
- finishType(variantType);
4155
- }
4156
4184
  if (links) {
4157
4185
  linkType(links, variantType, mapper);
4158
4186
  }
4159
- return variantType;
4187
+ return finishType(variantType, {
4188
+ skipDecorators: !shouldRunDecorators(variantNode.parent, mapper),
4189
+ });
4160
4190
  }
4161
4191
  function isMemberNode(node) {
4162
4192
  return node.symbol && !!(node.symbol.flags & 65536 /* SymbolFlags.Member */);
@@ -4271,6 +4301,19 @@ export function createChecker(program, resolver) {
4271
4301
  createType(typeDef);
4272
4302
  return finishType(typeDef);
4273
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
+ }
4274
4317
  /**
4275
4318
  * Given the own-properties of a type, returns a fully-initialized type.
4276
4319
  */
@@ -4278,6 +4321,7 @@ export function createChecker(program, resolver) {
4278
4321
  stats.createdTypes++;
4279
4322
  Object.setPrototypeOf(typeDef, typePrototype);
4280
4323
  typeDef.isFinished = false;
4324
+ typeDef.creating = true;
4281
4325
  // If the type has an associated syntax node, check any directives that
4282
4326
  // might be attached.
4283
4327
  const createdType = typeDef;
@@ -4287,9 +4331,29 @@ export function createChecker(program, resolver) {
4287
4331
  }
4288
4332
  return createdType;
4289
4333
  }
4290
- function finishType(typeDef) {
4334
+ function finishType(typeDef, options = {}) {
4291
4335
  stats.finishedTypes++;
4292
- 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);
4293
4357
  }
4294
4358
  function getLiteralType(node) {
4295
4359
  return createLiteralType(node.value, node);
@@ -4412,12 +4476,9 @@ export function createChecker(program, resolver) {
4412
4476
  * recursively by the caller.
4413
4477
  */
4414
4478
  function cloneType(type, additionalProps = {}) {
4415
- let clone = initializeClone(type, additionalProps);
4416
- if (type.isFinished) {
4417
- clone = finishType(clone);
4418
- }
4479
+ const clone = initializeClone(type, additionalProps);
4419
4480
  compilerAssert(clone.kind === type.kind, "cloneType must not change type kind");
4420
- return clone;
4481
+ return finishType(clone, { skipDecorators: !type.isFinished });
4421
4482
  }
4422
4483
  /**
4423
4484
  * Clone a type linking to the given symbol.
@@ -4473,7 +4534,7 @@ export function createChecker(program, resolver) {
4473
4534
  break;
4474
4535
  }
4475
4536
  program.literalTypes.set(value, type);
4476
- return type;
4537
+ return finishType(type);
4477
4538
  }
4478
4539
  /**
4479
4540
  * Check if the source type can be assigned to the target type and emit diagnostics
@@ -4708,7 +4769,7 @@ export function filterModelProperties(program, model, filter) {
4708
4769
  typekit.type.finishType(newProperty);
4709
4770
  }
4710
4771
  }
4711
- return finishTypeForProgram(program, newModel);
4772
+ return program.checker.finishType(newModel);
4712
4773
  }
4713
4774
  /**
4714
4775
  * Gets the property from the nearest base type that is overridden by the
@@ -4754,9 +4815,6 @@ function countPropertiesInherited(model, filter) {
4754
4815
  }
4755
4816
  return count;
4756
4817
  }
4757
- export function finishTypeForProgram(program, typeDef) {
4758
- return finishTypeForProgramAndChecker(program, program.checker.typePrototype, typeDef);
4759
- }
4760
4818
  function linkMapper(typeDef, mapper) {
4761
4819
  if (mapper) {
4762
4820
  compilerAssert(!typeDef.templateMapper, "Mapper provided but template arguments already set.");
@@ -4830,16 +4888,6 @@ function getDocContent(content) {
4830
4888
  }
4831
4889
  return docs.join("");
4832
4890
  }
4833
- function finishTypeForProgramAndChecker(program, typePrototype, typeDef) {
4834
- if ("decorators" in typeDef) {
4835
- for (const decApp of typeDef.decorators) {
4836
- applyDecoratorToType(program, decApp, typeDef);
4837
- }
4838
- }
4839
- Object.setPrototypeOf(typeDef, typePrototype);
4840
- typeDef.isFinished = true;
4841
- return typeDef;
4842
- }
4843
4891
  function reportDeprecation(program, target, message, reportFunc) {
4844
4892
  if (program.compilerOptions.ignoreDeprecated !== true) {
4845
4893
  reportFunc(createDiagnostic({