From 0a5da2fdc3dd5f5e7e3192c80b30a5b0b77b64ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 22 Sep 2022 21:06:00 +0200 Subject: [PATCH] Make function properties context-sensitive based on their return statements --- src/compiler/checker.ts | 9 +++-- ...ithContextSensitiveReturnStatement.symbols | 32 +++++++++++++++++ ...yWithContextSensitiveReturnStatement.types | 36 +++++++++++++++++++ ...ertyWithContextSensitiveReturnStatement.ts | 15 ++++++++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.symbols create mode 100644 tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.types create mode 100644 tests/cases/compiler/inferPropertyWithContextSensitiveReturnStatement.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8541917621bb4..937a5c202d1e1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17588,8 +17588,13 @@ namespace ts { } function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) { - // TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value. - return !node.typeParameters && !getEffectiveReturnTypeNode(node) && !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body); + if (node.typeParameters || getEffectiveReturnTypeNode(node) || !node.body) { + return false; + } + if (node.body.kind !== SyntaxKind.Block) { + return isContextSensitive(node.body); + } + return !!forEachReturnStatement(node.body as Block, (statement) => !!statement.expression && isContextSensitive(statement.expression)); } function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { diff --git a/tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.symbols b/tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.symbols new file mode 100644 index 0000000000000..1947ea8f7d120 --- /dev/null +++ b/tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.symbols @@ -0,0 +1,32 @@ +=== tests/cases/compiler/inferPropertyWithContextSensitiveReturnStatement.ts === +// repro #50687 + +declare function repro(config: { +>repro : Symbol(repro, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 0, 0)) +>T : Symbol(T, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 2, 23)) +>config : Symbol(config, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 2, 26)) + + params: T; +>params : Symbol(params, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 2, 35)) +>T : Symbol(T, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 2, 23)) + + callback: () => (params: T) => number; +>callback : Symbol(callback, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 3, 12)) +>params : Symbol(params, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 4, 19)) +>T : Symbol(T, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 2, 23)) + +}): void; + +repro({ +>repro : Symbol(repro, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 0, 0)) + + params: 1, +>params : Symbol(params, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 7, 7)) + + callback: () => { return a => a + 1 }, +>callback : Symbol(callback, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 8, 12)) +>a : Symbol(a, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 9, 26)) +>a : Symbol(a, Decl(inferPropertyWithContextSensitiveReturnStatement.ts, 9, 26)) + +}); + diff --git a/tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.types b/tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.types new file mode 100644 index 0000000000000..24383ff66feaa --- /dev/null +++ b/tests/baselines/reference/inferPropertyWithContextSensitiveReturnStatement.types @@ -0,0 +1,36 @@ +=== tests/cases/compiler/inferPropertyWithContextSensitiveReturnStatement.ts === +// repro #50687 + +declare function repro(config: { +>repro : (config: { params: T; callback: () => (params: T) => number; }) => void +>config : { params: T; callback: () => (params: T) => number; } + + params: T; +>params : T + + callback: () => (params: T) => number; +>callback : () => (params: T) => number +>params : T + +}): void; + +repro({ +>repro({ params: 1, callback: () => { return a => a + 1 },}) : void +>repro : (config: { params: T; callback: () => (params: T) => number; }) => void +>{ params: 1, callback: () => { return a => a + 1 },} : { params: number; callback: () => (a: number) => number; } + + params: 1, +>params : number +>1 : 1 + + callback: () => { return a => a + 1 }, +>callback : () => (a: number) => number +>() => { return a => a + 1 } : () => (a: number) => number +>a => a + 1 : (a: number) => number +>a : number +>a + 1 : number +>a : number +>1 : 1 + +}); + diff --git a/tests/cases/compiler/inferPropertyWithContextSensitiveReturnStatement.ts b/tests/cases/compiler/inferPropertyWithContextSensitiveReturnStatement.ts new file mode 100644 index 0000000000000..67bbed7bafcc3 --- /dev/null +++ b/tests/cases/compiler/inferPropertyWithContextSensitiveReturnStatement.ts @@ -0,0 +1,15 @@ +// @noEmit: true +// @strict: true + + +// repro #50687 + +declare function repro(config: { + params: T; + callback: () => (params: T) => number; +}): void; + +repro({ + params: 1, + callback: () => { return a => a + 1 }, +});