From a203ace7afed24552fe52def1bc4116aca44a98d Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Thu, 23 May 2024 19:29:49 +0300 Subject: [PATCH] Ban inferred return type on async and generator functions. (#58628) --- src/compiler/checker.ts | 1 + src/compiler/expressionToTypeNode.ts | 4 ++ ...declarationAsyncAndGeneratorFunctions.d.ts | 71 +++++++++++++++++++ .../declarationAsyncAndGeneratorFunctions.js | 36 ++++++++++ .../declarationAsyncAndGeneratorFunctions.ts | 22 ++++++ 5 files changed, 134 insertions(+) create mode 100644 tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.d.ts create mode 100644 tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.js create mode 100644 tests/cases/transpile/declarationAsyncAndGeneratorFunctions.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d0c227b1541..44e9475162a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -48984,6 +48984,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getSingleReturnExpression(declaration: SignatureDeclaration | undefined): Expression | undefined { let candidateExpr: Expression | undefined; if (declaration && !nodeIsMissing((declaration as FunctionLikeDeclaration).body)) { + if (getFunctionFlags(declaration) & FunctionFlags.AsyncGenerator) return undefined; const body = (declaration as FunctionLikeDeclaration).body; if (body && isBlock(body)) { forEachReturnStatement(body, s => { diff --git a/src/compiler/expressionToTypeNode.ts b/src/compiler/expressionToTypeNode.ts index e2a5d6c9471..982be51efb3 100644 --- a/src/compiler/expressionToTypeNode.ts +++ b/src/compiler/expressionToTypeNode.ts @@ -14,10 +14,12 @@ import { Expression, forEachReturnStatement, FunctionExpression, + FunctionFlags, FunctionLikeDeclaration, GetAccessorDeclaration, getEffectiveReturnTypeNode, getEffectiveTypeAnnotationNode, + getFunctionFlags, getJSDocTypeAssertionType, getStrictOptionValue, HasInferredType, @@ -469,6 +471,8 @@ export function createSyntacticTypeNodeBuilder(options: CompilerOptions, resolve function typeFromSingleReturnExpression(declaration: FunctionLikeDeclaration | undefined, context: SyntacticTypeNodeBuilderContext): boolean | undefined { let candidateExpr: Expression | undefined; if (declaration && !nodeIsMissing(declaration.body)) { + if (getFunctionFlags(declaration) & FunctionFlags.AsyncGenerator) return undefined; + const body = declaration.body; if (body && isBlock(body)) { forEachReturnStatement(body, s => { diff --git a/tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.d.ts b/tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.d.ts new file mode 100644 index 00000000000..c7acdac65cc --- /dev/null +++ b/tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.d.ts @@ -0,0 +1,71 @@ +//// [declarationAsyncAndGeneratorFunctions.ts] //// +export async function asyncFn() { + return {} as Promise +} + +export async function asyncFn2() { + return {} as number +} + +export async function asyncFn3() { + return (await 42) as number; + } + +export function* generatorFn() { + return {} as number +} + +export async function* asyncGeneratorFn() { + return {} as number +} +//// [declarationAsyncAndGeneratorFunctions.d.ts] //// +export declare function asyncFn(): unknown; +export declare function asyncFn2(): unknown; +export declare function asyncFn3(): unknown; +export declare function generatorFn(): {}; +export declare function asyncGeneratorFn(): {}; + + +//// [Diagnostics reported] +declarationAsyncAndGeneratorFunctions.ts(1,23): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +declarationAsyncAndGeneratorFunctions.ts(5,23): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +declarationAsyncAndGeneratorFunctions.ts(9,23): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +declarationAsyncAndGeneratorFunctions.ts(13,18): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +declarationAsyncAndGeneratorFunctions.ts(17,24): error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. + + +==== declarationAsyncAndGeneratorFunctions.ts (5 errors) ==== + export async function asyncFn() { + ~~~~~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 declarationAsyncAndGeneratorFunctions.ts:1:23: Add a return type to the function declaration. + return {} as Promise + } + + export async function asyncFn2() { + ~~~~~~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 declarationAsyncAndGeneratorFunctions.ts:5:23: Add a return type to the function declaration. + return {} as number + } + + export async function asyncFn3() { + ~~~~~~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 declarationAsyncAndGeneratorFunctions.ts:9:23: Add a return type to the function declaration. + return (await 42) as number; + } + + export function* generatorFn() { + ~~~~~~~~~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 declarationAsyncAndGeneratorFunctions.ts:13:18: Add a return type to the function declaration. + return {} as number + } + + export async function* asyncGeneratorFn() { + ~~~~~~~~~~~~~~~~ +!!! error TS9007: Function must have an explicit return type annotation with --isolatedDeclarations. +!!! related TS9031 declarationAsyncAndGeneratorFunctions.ts:17:24: Add a return type to the function declaration. + return {} as number + } diff --git a/tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.js b/tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.js new file mode 100644 index 00000000000..9f0704cfd8a --- /dev/null +++ b/tests/baselines/reference/transpile/declarationAsyncAndGeneratorFunctions.js @@ -0,0 +1,36 @@ +//// [declarationAsyncAndGeneratorFunctions.ts] //// +export async function asyncFn() { + return {} as Promise +} + +export async function asyncFn2() { + return {} as number +} + +export async function asyncFn3() { + return (await 42) as number; + } + +export function* generatorFn() { + return {} as number +} + +export async function* asyncGeneratorFn() { + return {} as number +} +//// [declarationAsyncAndGeneratorFunctions.js] //// +export async function asyncFn() { + return {}; +} +export async function asyncFn2() { + return {}; +} +export async function asyncFn3() { + return (await 42); +} +export function* generatorFn() { + return {}; +} +export async function* asyncGeneratorFn() { + return {}; +} diff --git a/tests/cases/transpile/declarationAsyncAndGeneratorFunctions.ts b/tests/cases/transpile/declarationAsyncAndGeneratorFunctions.ts new file mode 100644 index 00000000000..fb280cdd580 --- /dev/null +++ b/tests/cases/transpile/declarationAsyncAndGeneratorFunctions.ts @@ -0,0 +1,22 @@ +// @declaration: true +// @target: esnext + +export async function asyncFn() { + return {} as Promise +} + +export async function asyncFn2() { + return {} as number +} + +export async function asyncFn3() { + return (await 42) as number; + } + +export function* generatorFn() { + return {} as number +} + +export async function* asyncGeneratorFn() { + return {} as number +} \ No newline at end of file