@@ -15546,31 +15546,24 @@ namespace ts {
15546
15546
}
15547
15547
15548
15548
/**
15549
- * Checks the return type of an async function to ensure it is a compatible
15550
- * Promise implementation.
15551
- * @param node The signature to check
15552
- * @param returnType The return type for the function
15553
- * @remarks
15554
- * This checks that an async function has a valid Promise-compatible return type,
15555
- * and returns the *awaited type* of the promise. An async function has a valid
15556
- * Promise-compatible return type if the resolved value of the return type has a
15557
- * construct signature that takes in an `initializer` function that in turn supplies
15558
- * a `resolve` function as one of its arguments and results in an object with a
15559
- * callable `then` signature.
15560
- */
15549
+ * Checks the return type of an async function to ensure it is a compatible
15550
+ * Promise implementation.
15551
+ *
15552
+ * This checks that an async function has a valid Promise-compatible return type,
15553
+ * and returns the *awaited type* of the promise. An async function has a valid
15554
+ * Promise-compatible return type if the resolved value of the return type has a
15555
+ * construct signature that takes in an `initializer` function that in turn supplies
15556
+ * a `resolve` function as one of its arguments and results in an object with a
15557
+ * callable `then` signature.
15558
+ *
15559
+ * @param node The signature to check
15560
+ */
15561
15561
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration): Type {
15562
15562
if (languageVersion >= ScriptTarget.ES2015) {
15563
15563
const returnType = getTypeFromTypeNode(node.type);
15564
15564
return checkCorrectPromiseType(returnType, node.type, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type);
15565
15565
}
15566
15566
15567
- const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType();
15568
- if (globalPromiseConstructorLikeType === emptyObjectType) {
15569
- // If we couldn't resolve the global PromiseConstructorLike type we cannot verify
15570
- // compatibility with __awaiter.
15571
- return unknownType;
15572
- }
15573
-
15574
15567
// As part of our emit for an async function, we will need to emit the entity name of
15575
15568
// the return type annotation as an expression. To meet the necessary runtime semantics
15576
15569
// for __awaiter, we must also check that the type of the declaration (e.g. the static
@@ -15595,42 +15588,56 @@ namespace ts {
15595
15588
// then<U>(...): Promise<U>;
15596
15589
// }
15597
15590
//
15598
- // When we get the type of the `Promise` symbol here, we get the type of the static
15599
- // side of the `Promise` class, which would be `{ new <T>(...): Promise<T> }`.
15600
15591
15592
+ // Always mark the type node as referenced if it points to a value
15593
+ markTypeNodeAsReferenced(node.type);
15594
+
15595
+ const promiseConstructorName = getEntityNameFromTypeNode(node.type);
15601
15596
const promiseType = getTypeFromTypeNode(node.type);
15602
- if (promiseType === unknownType && compilerOptions.isolatedModules) {
15603
- // If we are compiling with isolatedModules, we may not be able to resolve the
15604
- // type as a value. As such, we will just return unknownType;
15597
+ if (promiseType === unknownType) {
15598
+ if (!compilerOptions.isolatedModules) {
15599
+ if (promiseConstructorName) {
15600
+ error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName));
15601
+ }
15602
+ else {
15603
+ error(node.type, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
15604
+ }
15605
+ }
15605
15606
return unknownType;
15606
15607
}
15607
15608
15608
- const promiseConstructor = getNodeLinks(node.type).resolvedSymbol;
15609
- if (!promiseConstructor || !symbolIsValue(promiseConstructor)) {
15610
- // try to fall back to global promise type.
15611
- const typeName = promiseConstructor
15612
- ? symbolToString(promiseConstructor)
15613
- : typeToString(promiseType);
15614
- return checkCorrectPromiseType(promiseType, node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type, typeName);
15609
+ if (promiseConstructorName === undefined) {
15610
+ error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, typeToString(promiseType));
15611
+ return unknownType;
15615
15612
}
15616
15613
15617
- // If the Promise constructor, resolved locally, is an alias symbol we should mark it as referenced.
15618
- checkReturnTypeAnnotationAsExpression(node);
15614
+ const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true);
15615
+ const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : unknownType;
15616
+ if (promiseConstructorType === unknownType) {
15617
+ error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName));
15618
+ return unknownType;
15619
+ }
15619
15620
15620
- // Validate the promise constructor type.
15621
- const promiseConstructorType = getTypeOfSymbol(promiseConstructor);
15622
- if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type)) {
15621
+ const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType();
15622
+ if (globalPromiseConstructorLikeType === emptyObjectType) {
15623
+ // If we couldn't resolve the global PromiseConstructorLike type we cannot verify
15624
+ // compatibility with __awaiter.
15625
+ error(node.type, Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value, entityNameToString(promiseConstructorName));
15626
+ return unknownType;
15627
+ }
15628
+
15629
+ if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node.type,
15630
+ Diagnostics.Type_0_is_not_a_valid_async_function_return_type_in_ES5_SlashES3_because_it_does_not_refer_to_a_Promise_compatible_constructor_value)) {
15623
15631
return unknownType;
15624
15632
}
15625
15633
15626
15634
// Verify there is no local declaration that could collide with the promise constructor.
15627
- const promiseName = getEntityNameFromTypeNode(node.type);
15628
- const promiseNameOrNamespaceRoot = getFirstIdentifier(promiseName);
15629
- const rootSymbol = getSymbol(node.locals, promiseNameOrNamespaceRoot.text, SymbolFlags.Value);
15630
- if (rootSymbol) {
15631
- error(rootSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions,
15632
- promiseNameOrNamespaceRoot.text,
15633
- getFullyQualifiedName(promiseConstructor));
15635
+ const rootName = promiseConstructorName && getFirstIdentifier(promiseConstructorName);
15636
+ const collidingSymbol = getSymbol(node.locals, rootName.text, SymbolFlags.Value);
15637
+ if (collidingSymbol) {
15638
+ error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions,
15639
+ rootName.text,
15640
+ entityNameToString(promiseConstructorName));
15634
15641
return unknownType;
15635
15642
}
15636
15643
@@ -15688,44 +15695,19 @@ namespace ts {
15688
15695
errorInfo);
15689
15696
}
15690
15697
15691
- /** Checks a type reference node as an expression. */
15692
- function checkTypeNodeAsExpression(node: TypeNode) {
15693
- // When we are emitting type metadata for decorators, we need to try to check the type
15694
- // as if it were an expression so that we can emit the type in a value position when we
15695
- // serialize the type metadata.
15696
- if (node && node.kind === SyntaxKind.TypeReference) {
15697
- const root = getFirstIdentifier((<TypeReferenceNode>node).typeName);
15698
- const meaning = root.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace;
15699
- // Resolve type so we know which symbol is referenced
15700
- const rootSymbol = resolveName(root, root.text, meaning | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
15701
- // Resolved symbol is alias
15702
- if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) {
15703
- const aliasTarget = resolveAlias(rootSymbol);
15704
- // If alias has value symbol - mark alias as referenced
15705
- if (aliasTarget.flags & SymbolFlags.Value && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol))) {
15706
- markAliasSymbolAsReferenced(rootSymbol);
15707
- }
15708
- }
15709
- }
15710
- }
15711
-
15712
15698
/**
15713
- * Checks the type annotation of an accessor declaration or property declaration as
15714
- * an expression if it is a type reference to a type with a value declaration.
15715
- */
15716
- function checkTypeAnnotationAsExpression(node: VariableLikeDeclaration) {
15717
- checkTypeNodeAsExpression((<PropertyDeclaration>node).type);
15718
- }
15719
-
15720
- function checkReturnTypeAnnotationAsExpression(node: FunctionLikeDeclaration) {
15721
- checkTypeNodeAsExpression(node.type);
15722
- }
15723
-
15724
- /** Checks the type annotation of the parameters of a function/method or the constructor of a class as expressions */
15725
- function checkParameterTypeAnnotationsAsExpressions(node: FunctionLikeDeclaration) {
15726
- // ensure all type annotations with a value declaration are checked as an expression
15727
- for (const parameter of node.parameters) {
15728
- checkTypeAnnotationAsExpression(parameter);
15699
+ * If a TypeNode can be resolved to a value symbol imported from an external module, it is
15700
+ * marked as referenced to prevent import elision.
15701
+ */
15702
+ function markTypeNodeAsReferenced(node: TypeNode) {
15703
+ const typeName = node && getEntityNameFromTypeNode(node);
15704
+ const rootName = typeName && getFirstIdentifier(typeName);
15705
+ const rootSymbol = rootName && resolveName(rootName, rootName.text, (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
15706
+ if (rootSymbol
15707
+ && rootSymbol.flags & SymbolFlags.Alias
15708
+ && symbolIsValue(rootSymbol)
15709
+ && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol))) {
15710
+ markAliasSymbolAsReferenced(rootSymbol);
15729
15711
}
15730
15712
}
15731
15713
@@ -15751,20 +15733,25 @@ namespace ts {
15751
15733
case SyntaxKind.ClassDeclaration:
15752
15734
const constructor = getFirstConstructorWithBody(<ClassDeclaration>node);
15753
15735
if (constructor) {
15754
- checkParameterTypeAnnotationsAsExpressions(constructor);
15736
+ for (const parameter of constructor.parameters) {
15737
+ markTypeNodeAsReferenced(parameter.type);
15738
+ }
15755
15739
}
15756
15740
break;
15757
15741
15758
15742
case SyntaxKind.MethodDeclaration:
15759
15743
case SyntaxKind.GetAccessor:
15760
15744
case SyntaxKind.SetAccessor:
15761
- checkParameterTypeAnnotationsAsExpressions(<FunctionLikeDeclaration>node);
15762
- checkReturnTypeAnnotationAsExpression(<FunctionLikeDeclaration>node);
15745
+ for (const parameter of (<FunctionLikeDeclaration>node).parameters) {
15746
+ markTypeNodeAsReferenced(parameter.type);
15747
+ }
15748
+
15749
+ markTypeNodeAsReferenced((<FunctionLikeDeclaration>node).type);
15763
15750
break;
15764
15751
15765
15752
case SyntaxKind.PropertyDeclaration:
15766
15753
case SyntaxKind.Parameter:
15767
- checkTypeAnnotationAsExpression( <PropertyDeclaration | ParameterDeclaration>node);
15754
+ markTypeNodeAsReferenced(( <PropertyDeclaration | ParameterDeclaration>node).type );
15768
15755
break;
15769
15756
}
15770
15757
}
@@ -18476,9 +18463,33 @@ namespace ts {
18476
18463
function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] {
18477
18464
throwIfNonDiagnosticsProducing();
18478
18465
if (sourceFile) {
18466
+ // Some global diagnostics are deferred until they are needed and
18467
+ // may not be reported in the firt call to getGlobalDiagnostics.
18468
+ // We should catch these changes and report them.
18469
+ const previousGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
18470
+ const previousGlobalDiagnosticsSize = previousGlobalDiagnostics.length;
18471
+
18479
18472
checkSourceFile(sourceFile);
18480
- return diagnostics.getDiagnostics(sourceFile.fileName);
18473
+
18474
+ const semanticDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
18475
+ const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
18476
+ if (currentGlobalDiagnostics !== previousGlobalDiagnostics) {
18477
+ // If the arrays are not the same reference, new diagnostics were added.
18478
+ const deferredGlobalDiagnostics = relativeComplement(previousGlobalDiagnostics, currentGlobalDiagnostics, compareDiagnostics);
18479
+ return concatenate(deferredGlobalDiagnostics, semanticDiagnostics);
18480
+ }
18481
+ else if (previousGlobalDiagnosticsSize === 0 && currentGlobalDiagnostics.length > 0) {
18482
+ // If the arrays are the same reference, but the length has changed, a single
18483
+ // new diagnostic was added as DiagnosticCollection attempts to reuse the
18484
+ // same array.
18485
+ return concatenate(currentGlobalDiagnostics, semanticDiagnostics);
18486
+ }
18487
+
18488
+ return semanticDiagnostics;
18481
18489
}
18490
+
18491
+ // Global diagnostics are always added when a file is not provided to
18492
+ // getDiagnostics
18482
18493
forEach(host.getSourceFiles(), checkSourceFile);
18483
18494
return diagnostics.getDiagnostics();
18484
18495
}
0 commit comments