diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 25004df71e..a6736ac7c3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8405,16 +8405,17 @@ namespace ts { if (forEach(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) { return true; } - // For arrow functions we now know we're not context sensitive. - if (node.kind === SyntaxKind.ArrowFunction) { - return false; + if (node.kind !== SyntaxKind.ArrowFunction) { + // If the first parameter is not an explicit 'this' parameter, then the function has + // an implicit 'this' parameter which is subject to contextual typing. + const parameter = firstOrUndefined(node.parameters); + if (!(parameter && parameterIsThisKeyword(parameter))) { + return true; + } } - // If the first parameter is not an explicit 'this' parameter, then the function has - // an implicit 'this' parameter which is subject to contextual typing. Otherwise we - // know that all parameters (including 'this') have type annotations and nothing is - // subject to contextual typing. - const parameter = firstOrUndefined(node.parameters); - return !(parameter && parameterIsThisKeyword(parameter)); + + // TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value. + return node.body.kind === SyntaxKind.Block ? false : isContextSensitive(node.body); } function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { diff --git a/tests/baselines/reference/contextualTypingFunctionReturningFunction2.js b/tests/baselines/reference/contextualTypingFunctionReturningFunction2.js new file mode 100644 index 0000000000..88308dbe2e --- /dev/null +++ b/tests/baselines/reference/contextualTypingFunctionReturningFunction2.js @@ -0,0 +1,9 @@ +//// [contextualTypingFunctionReturningFunction2.ts] +declare function f(n: number): void; +declare function f(cb: () => (n: number) => number): void; + +f(() => n => n); + + +//// [contextualTypingFunctionReturningFunction2.js] +f(function () { return function (n) { return n; }; }); diff --git a/tests/baselines/reference/contextualTypingFunctionReturningFunction2.symbols b/tests/baselines/reference/contextualTypingFunctionReturningFunction2.symbols new file mode 100644 index 0000000000..9071bfc23d --- /dev/null +++ b/tests/baselines/reference/contextualTypingFunctionReturningFunction2.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts === +declare function f(n: number): void; +>f : Symbol(f, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 0), Decl(contextualTypingFunctionReturningFunction2.ts, 0, 36)) +>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 19)) + +declare function f(cb: () => (n: number) => number): void; +>f : Symbol(f, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 0), Decl(contextualTypingFunctionReturningFunction2.ts, 0, 36)) +>cb : Symbol(cb, Decl(contextualTypingFunctionReturningFunction2.ts, 1, 19)) +>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 1, 30)) + +f(() => n => n); +>f : Symbol(f, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 0), Decl(contextualTypingFunctionReturningFunction2.ts, 0, 36)) +>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 3, 7)) +>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 3, 7)) + diff --git a/tests/baselines/reference/contextualTypingFunctionReturningFunction2.types b/tests/baselines/reference/contextualTypingFunctionReturningFunction2.types new file mode 100644 index 0000000000..14126a0e0c --- /dev/null +++ b/tests/baselines/reference/contextualTypingFunctionReturningFunction2.types @@ -0,0 +1,18 @@ +=== tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts === +declare function f(n: number): void; +>f : { (n: number): void; (cb: () => (n: number) => number): void; } +>n : number + +declare function f(cb: () => (n: number) => number): void; +>f : { (n: number): void; (cb: () => (n: number) => number): void; } +>cb : () => (n: number) => number +>n : number + +f(() => n => n); +>f(() => n => n) : void +>f : { (n: number): void; (cb: () => (n: number) => number): void; } +>() => n => n : () => (n: number) => number +>n => n : (n: number) => number +>n : number +>n : number + diff --git a/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.errors.txt b/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.errors.txt index 95b3c66c26..0fe1e69d07 100644 --- a/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.errors.txt +++ b/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.errors.txt @@ -1,15 +1,15 @@ tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(2,22): error TS2339: Property 'foo' does not exist on type 'string'. -tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,32): error TS2339: Property 'foo' does not exist on type 'string'. -tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,38): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'. +tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,32): error TS2339: Property 'foo' does not exist on type '""'. +tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,38): error TS2345: Argument of type '1' is not assignable to parameter of type '""'. ==== tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts (3 errors) ==== var f10: (x: T, b: () => (a: T) => void, y: T) => T; - f10('', () => a => a.foo, ''); // a is string + f10('', () => a => a.foo, ''); // a is "" ~~~ !!! error TS2339: Property 'foo' does not exist on type 'string'. var r9 = f10('', () => (a => a.foo), 1); // error ~~~ -!!! error TS2339: Property 'foo' does not exist on type 'string'. +!!! error TS2339: Property 'foo' does not exist on type '""'. ~ -!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'. \ No newline at end of file +!!! error TS2345: Argument of type '1' is not assignable to parameter of type '""'. \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.js b/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.js index 55f7580b3f..b60a7c986a 100644 --- a/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.js +++ b/tests/baselines/reference/contextualTypingWithFixedTypeParameters1.js @@ -1,9 +1,9 @@ //// [contextualTypingWithFixedTypeParameters1.ts] var f10: (x: T, b: () => (a: T) => void, y: T) => T; -f10('', () => a => a.foo, ''); // a is string +f10('', () => a => a.foo, ''); // a is "" var r9 = f10('', () => (a => a.foo), 1); // error //// [contextualTypingWithFixedTypeParameters1.js] var f10; -f10('', function () { return function (a) { return a.foo; }; }, ''); // a is string +f10('', function () { return function (a) { return a.foo; }; }, ''); // a is "" var r9 = f10('', function () { return (function (a) { return a.foo; }); }, 1); // error diff --git a/tests/cases/compiler/contextualTypingFunctionReturningFunction.ts b/tests/cases/compiler/contextualTypingFunctionReturningFunction.ts index 2b371937f5..556f42f7eb 100644 --- a/tests/cases/compiler/contextualTypingFunctionReturningFunction.ts +++ b/tests/cases/compiler/contextualTypingFunctionReturningFunction.ts @@ -1,11 +1,11 @@ -interface I { - a(s: string): void; - b(): (n: number) => void; -} - -declare function f(i: I): void; - -f({ - a: s => {}, - b: () => n => {}, -}); +interface I { + a(s: string): void; + b(): (n: number) => void; +} + +declare function f(i: I): void; + +f({ + a: s => {}, + b: () => n => {}, +}); diff --git a/tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts b/tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts new file mode 100644 index 0000000000..9bcd34e4c0 --- /dev/null +++ b/tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts @@ -0,0 +1,4 @@ +declare function f(n: number): void; +declare function f(cb: () => (n: number) => number): void; + +f(() => n => n); diff --git a/tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts b/tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts index 1ea001057a..451e67092b 100644 --- a/tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts +++ b/tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts @@ -1,3 +1,3 @@ var f10: (x: T, b: () => (a: T) => void, y: T) => T; -f10('', () => a => a.foo, ''); // a is string +f10('', () => a => a.foo, ''); // a is "" var r9 = f10('', () => (a => a.foo), 1); // error \ No newline at end of file