Skip to content

Commit 6b94bae

Browse files
authored
Fix #11396: Make error message referene Promise explicitly (#11982)
* Simplify the checking for async function return type * Fix #11396: Make error message referene `Promise` explicitly
1 parent 137c99b commit 6b94bae

File tree

3 files changed

+57
-82
lines changed

3 files changed

+57
-82
lines changed

src/compiler/checker.ts

+51-80
Original file line numberDiff line numberDiff line change
@@ -13073,7 +13073,7 @@ namespace ts {
1307313073
function createPromiseReturnType(func: FunctionLikeDeclaration, promisedType: Type) {
1307413074
const promiseType = createPromiseType(promisedType);
1307513075
if (promiseType === emptyObjectType) {
13076-
error(func, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
13076+
error(func, Diagnostics.An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option);
1307713077
return unknownType;
1307813078
}
1307913079

@@ -15515,36 +15515,6 @@ namespace ts {
1551515515
}
1551615516
}
1551715517

15518-
/**
15519-
* Checks that the return type provided is an instantiation of the global Promise<T> type
15520-
* and returns the awaited type of the return type.
15521-
*
15522-
* @param returnType The return type of a FunctionLikeDeclaration
15523-
* @param location The node on which to report the error.
15524-
*/
15525-
function checkCorrectPromiseType(returnType: Type, location: Node, diagnostic: DiagnosticMessage, typeName?: string) {
15526-
if (returnType === unknownType) {
15527-
// The return type already had some other error, so we ignore and return
15528-
// the unknown type.
15529-
return unknownType;
15530-
}
15531-
15532-
const globalPromiseType = getGlobalPromiseType();
15533-
if (globalPromiseType === emptyGenericType
15534-
|| globalPromiseType === getTargetType(returnType)) {
15535-
// Either we couldn't resolve the global promise type, which would have already
15536-
// reported an error, or we could resolve it and the return type is a valid type
15537-
// reference to the global type. In either case, we return the awaited type for
15538-
// the return type.
15539-
return checkAwaitedType(returnType, location, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
15540-
}
15541-
15542-
// The promise type was not a valid type reference to the global promise type, so we
15543-
// report an error and return the unknown type.
15544-
error(location, diagnostic, typeName);
15545-
return unknownType;
15546-
}
15547-
1554815518
/**
1554915519
* Checks the return type of an async function to ensure it is a compatible
1555015520
* Promise implementation.
@@ -15559,11 +15529,6 @@ namespace ts {
1555915529
* @param node The signature to check
1556015530
*/
1556115531
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration): Type {
15562-
if (languageVersion >= ScriptTarget.ES2015) {
15563-
const returnType = getTypeFromTypeNode(node.type);
15564-
return checkCorrectPromiseType(returnType, node.type, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type);
15565-
}
15566-
1556715532
// As part of our emit for an async function, we will need to emit the entity name of
1556815533
// the return type annotation as an expression. To meet the necessary runtime semantics
1556915534
// for __awaiter, we must also check that the type of the declaration (e.g. the static
@@ -15588,61 +15553,67 @@ namespace ts {
1558815553
// then<U>(...): Promise<U>;
1558915554
// }
1559015555
//
15556+
const returnType = getTypeFromTypeNode(node.type);
1559115557

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);
15596-
const promiseType = getTypeFromTypeNode(node.type);
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-
}
15558+
if (languageVersion >= ScriptTarget.ES2015) {
15559+
if (returnType === unknownType) {
15560+
return unknownType;
15561+
}
15562+
const globalPromiseType = getGlobalPromiseType();
15563+
if (globalPromiseType !== emptyGenericType && globalPromiseType !== getTargetType(returnType)) {
15564+
// The promise type was not a valid type reference to the global promise type, so we
15565+
// report an error and return the unknown type.
15566+
error(node.type, Diagnostics.The_return_type_of_an_async_function_or_method_must_be_the_global_Promise_T_type);
15567+
return unknownType;
1560515568
}
15606-
return unknownType;
1560715569
}
15570+
else {
15571+
// Always mark the type node as referenced if it points to a value
15572+
markTypeNodeAsReferenced(node.type);
1560815573

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;
15612-
}
15574+
if (returnType === unknownType) {
15575+
return unknownType;
15576+
}
1561315577

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-
}
15578+
const promiseConstructorName = getEntityNameFromTypeNode(node.type);
15579+
if (promiseConstructorName === undefined) {
15580+
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(returnType));
15581+
return unknownType;
15582+
}
1562015583

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-
}
15584+
const promiseConstructorSymbol = resolveEntityName(promiseConstructorName, SymbolFlags.Value, /*ignoreErrors*/ true);
15585+
const promiseConstructorType = promiseConstructorSymbol ? getTypeOfSymbol(promiseConstructorSymbol) : unknownType;
15586+
if (promiseConstructorType === unknownType) {
15587+
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));
15588+
return unknownType;
15589+
}
1562815590

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)) {
15631-
return unknownType;
15632-
}
15591+
const globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType();
15592+
if (globalPromiseConstructorLikeType === emptyObjectType) {
15593+
// If we couldn't resolve the global PromiseConstructorLike type we cannot verify
15594+
// compatibility with __awaiter.
15595+
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));
15596+
return unknownType;
15597+
}
1563315598

15634-
// Verify there is no local declaration that could collide with the promise constructor.
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));
15641-
return unknownType;
15599+
if (!checkTypeAssignableTo(promiseConstructorType, globalPromiseConstructorLikeType, node.type,
15600+
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)) {
15601+
return unknownType;
15602+
}
15603+
15604+
// Verify there is no local declaration that could collide with the promise constructor.
15605+
const rootName = promiseConstructorName && getFirstIdentifier(promiseConstructorName);
15606+
const collidingSymbol = getSymbol(node.locals, rootName.text, SymbolFlags.Value);
15607+
if (collidingSymbol) {
15608+
error(collidingSymbol.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions,
15609+
rootName.text,
15610+
entityNameToString(promiseConstructorName));
15611+
return unknownType;
15612+
}
1564215613
}
1564315614

1564415615
// Get and return the awaited type of the return type.
15645-
return checkAwaitedType(promiseType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
15616+
return checkAwaitedType(returnType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
1564615617
}
1564715618

1564815619
/** Check a decorator */

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,10 @@
19671967
"category": "Error",
19681968
"code": 2696
19691969
},
1970+
"An async function or method must return a 'Promise'. Make sure you have a declaration for 'Promise' or include 'ES2015' in your `--lib` option.": {
1971+
"category": "Error",
1972+
"code": 2697
1973+
},
19701974

19711975
"Import declaration '{0}' is using private name '{1}'.": {
19721976
"category": "Error",

tests/baselines/reference/asyncFunctionNoReturnType.errors.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error TS2318: Cannot find global type 'Promise'.
2-
tests/cases/compiler/asyncFunctionNoReturnType.ts(1,1): error TS1057: An async function or method must have a valid awaitable return type.
2+
tests/cases/compiler/asyncFunctionNoReturnType.ts(1,1): error TS2697: An async function or method must return a 'Promise'. Make sure you have a declaration for 'Promise' or include 'ES2015' in your `--lib` option.
33
tests/cases/compiler/asyncFunctionNoReturnType.ts(1,1): error TS7030: Not all code paths return a value.
44
tests/cases/compiler/asyncFunctionNoReturnType.ts(2,9): error TS2304: Cannot find name 'window'.
55
tests/cases/compiler/asyncFunctionNoReturnType.ts(3,9): error TS7030: Not all code paths return a value.
@@ -9,7 +9,7 @@ tests/cases/compiler/asyncFunctionNoReturnType.ts(3,9): error TS7030: Not all co
99
==== tests/cases/compiler/asyncFunctionNoReturnType.ts (4 errors) ====
1010
async () => {
1111
~~~~~~~~~~~~~
12-
!!! error TS1057: An async function or method must have a valid awaitable return type.
12+
!!! error TS2697: An async function or method must return a 'Promise'. Make sure you have a declaration for 'Promise' or include 'ES2015' in your `--lib` option.
1313
~~~~~~~~~~~~~
1414
!!! error TS7030: Not all code paths return a value.
1515
if (window)

0 commit comments

Comments
 (0)