Skip to content

Commit fe3a05e

Browse files
author
Andy
authored
A function should be context-sensitive if its return expression is (#17697)
* A function should be context-sensitive if its return expression is * Remove outdated comment * Fix typo
1 parent 4c82450 commit fe3a05e

9 files changed

+75
-28
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8405,16 +8405,17 @@ namespace ts {
84058405
if (forEach(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) {
84068406
return true;
84078407
}
8408-
// For arrow functions we now know we're not context sensitive.
8409-
if (node.kind === SyntaxKind.ArrowFunction) {
8410-
return false;
8408+
if (node.kind !== SyntaxKind.ArrowFunction) {
8409+
// If the first parameter is not an explicit 'this' parameter, then the function has
8410+
// an implicit 'this' parameter which is subject to contextual typing.
8411+
const parameter = firstOrUndefined(node.parameters);
8412+
if (!(parameter && parameterIsThisKeyword(parameter))) {
8413+
return true;
8414+
}
84118415
}
8412-
// If the first parameter is not an explicit 'this' parameter, then the function has
8413-
// an implicit 'this' parameter which is subject to contextual typing. Otherwise we
8414-
// know that all parameters (including 'this') have type annotations and nothing is
8415-
// subject to contextual typing.
8416-
const parameter = firstOrUndefined(node.parameters);
8417-
return !(parameter && parameterIsThisKeyword(parameter));
8416+
8417+
// TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value.
8418+
return node.body.kind === SyntaxKind.Block ? false : isContextSensitive(node.body);
84188419
}
84198420

84208421
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//// [contextualTypingFunctionReturningFunction2.ts]
2+
declare function f(n: number): void;
3+
declare function f(cb: () => (n: number) => number): void;
4+
5+
f(() => n => n);
6+
7+
8+
//// [contextualTypingFunctionReturningFunction2.js]
9+
f(function () { return function (n) { return n; }; });
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts ===
2+
declare function f(n: number): void;
3+
>f : Symbol(f, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 0), Decl(contextualTypingFunctionReturningFunction2.ts, 0, 36))
4+
>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 19))
5+
6+
declare function f(cb: () => (n: number) => number): void;
7+
>f : Symbol(f, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 0), Decl(contextualTypingFunctionReturningFunction2.ts, 0, 36))
8+
>cb : Symbol(cb, Decl(contextualTypingFunctionReturningFunction2.ts, 1, 19))
9+
>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 1, 30))
10+
11+
f(() => n => n);
12+
>f : Symbol(f, Decl(contextualTypingFunctionReturningFunction2.ts, 0, 0), Decl(contextualTypingFunctionReturningFunction2.ts, 0, 36))
13+
>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 3, 7))
14+
>n : Symbol(n, Decl(contextualTypingFunctionReturningFunction2.ts, 3, 7))
15+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/compiler/contextualTypingFunctionReturningFunction2.ts ===
2+
declare function f(n: number): void;
3+
>f : { (n: number): void; (cb: () => (n: number) => number): void; }
4+
>n : number
5+
6+
declare function f(cb: () => (n: number) => number): void;
7+
>f : { (n: number): void; (cb: () => (n: number) => number): void; }
8+
>cb : () => (n: number) => number
9+
>n : number
10+
11+
f(() => n => n);
12+
>f(() => n => n) : void
13+
>f : { (n: number): void; (cb: () => (n: number) => number): void; }
14+
>() => n => n : () => (n: number) => number
15+
>n => n : (n: number) => number
16+
>n : number
17+
>n : number
18+
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(2,22): error TS2339: Property 'foo' does not exist on type 'string'.
2-
tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,32): error TS2339: Property 'foo' does not exist on type 'string'.
3-
tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,38): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
2+
tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,32): error TS2339: Property 'foo' does not exist on type '""'.
3+
tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts(3,38): error TS2345: Argument of type '1' is not assignable to parameter of type '""'.
44

55

66
==== tests/cases/compiler/contextualTypingWithFixedTypeParameters1.ts (3 errors) ====
77
var f10: <T>(x: T, b: () => (a: T) => void, y: T) => T;
8-
f10('', () => a => a.foo, ''); // a is string
8+
f10('', () => a => a.foo, ''); // a is ""
99
~~~
1010
!!! error TS2339: Property 'foo' does not exist on type 'string'.
1111
var r9 = f10('', () => (a => a.foo), 1); // error
1212
~~~
13-
!!! error TS2339: Property 'foo' does not exist on type 'string'.
13+
!!! error TS2339: Property 'foo' does not exist on type '""'.
1414
~
15-
!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
15+
!!! error TS2345: Argument of type '1' is not assignable to parameter of type '""'.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//// [contextualTypingWithFixedTypeParameters1.ts]
22
var f10: <T>(x: T, b: () => (a: T) => void, y: T) => T;
3-
f10('', () => a => a.foo, ''); // a is string
3+
f10('', () => a => a.foo, ''); // a is ""
44
var r9 = f10('', () => (a => a.foo), 1); // error
55

66
//// [contextualTypingWithFixedTypeParameters1.js]
77
var f10;
8-
f10('', function () { return function (a) { return a.foo; }; }, ''); // a is string
8+
f10('', function () { return function (a) { return a.foo; }; }, ''); // a is ""
99
var r9 = f10('', function () { return (function (a) { return a.foo; }); }, 1); // error
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
interface I {
2-
a(s: string): void;
3-
b(): (n: number) => void;
4-
}
5-
6-
declare function f(i: I): void;
7-
8-
f({
9-
a: s => {},
10-
b: () => n => {},
11-
});
1+
interface I {
2+
a(s: string): void;
3+
b(): (n: number) => void;
4+
}
5+
6+
declare function f(i: I): void;
7+
8+
f({
9+
a: s => {},
10+
b: () => n => {},
11+
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare function f(n: number): void;
2+
declare function f(cb: () => (n: number) => number): void;
3+
4+
f(() => n => n);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
var f10: <T>(x: T, b: () => (a: T) => void, y: T) => T;
2-
f10('', () => a => a.foo, ''); // a is string
2+
f10('', () => a => a.foo, ''); // a is ""
33
var r9 = f10('', () => (a => a.foo), 1); // error

0 commit comments

Comments
 (0)