Skip to content

Commit c874409

Browse files
committed
Limit scope of instantiation to only when likely needed
1 parent 87063a6 commit c874409

File tree

5 files changed

+22
-17
lines changed

5 files changed

+22
-17
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13026,7 +13026,7 @@ namespace ts {
1302613026

1302713027
function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, checkMode?: CheckMode) {
1302813028
const objectLiteral = <ObjectLiteralExpression>element.parent;
13029-
const type = getApparentTypeOfContextualType(objectLiteral, checkMode);
13029+
const type = getInstantiatedContextualType(objectLiteral, checkMode);
1303013030
if (type) {
1303113031
if (!hasDynamicName(element)) {
1303213032
// For a (non-symbol) computed property, there is no reason to look up the name
@@ -13122,6 +13122,17 @@ namespace ts {
1312213122
return type && getApparentType(type);
1312313123
}
1312413124

13125+
/**
13126+
* This must be called when a contextual type function is attempting to dig into a type to contextually type a subexpression
13127+
* Otherwise, contextual typing stops when a type argument is encountered, and `any` is ued instead.
13128+
*/
13129+
function getInstantiatedContextualType(node: Expression, checkMode?: CheckMode): Type {
13130+
if (checkMode === CheckMode.Inferential && node.contextualType && node.contextualMapper) {
13131+
return instantiateType(node.contextualType, node.contextualMapper);
13132+
}
13133+
return getContextualType(node, checkMode);
13134+
}
13135+
1312513136
/**
1312613137
* Woah! Do you really want to use this function?
1312713138
*
@@ -13145,12 +13156,6 @@ namespace ts {
1314513156
return undefined;
1314613157
}
1314713158
if (node.contextualType) {
13148-
if (checkMode & CheckMode.Inferential) {
13149-
const mapper = getContextualMapper(node);
13150-
if (mapper) {
13151-
return instantiateType(node.contextualType, mapper);
13152-
}
13153-
}
1315413159
return node.contextualType;
1315513160
}
1315613161
const parent = node.parent;
@@ -16848,7 +16853,7 @@ namespace ts {
1684816853

1684916854
// Check if function expression is contextually typed and assign parameter types if so.
1685016855
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
16851-
const contextualSignature = getContextualSignature(node);
16856+
const contextualSignature = getContextualSignature(node); // Intentionally do not pass check mode; resolve without instantiation
1685216857
// If a type check is started at a function expression that is an argument of a function call, obtaining the
1685316858
// contextual type may recursively get back to here during overload resolution of the call. If so, we will have
1685416859
// already assigned contextual types.

tests/baselines/reference/functionConstraintSatisfaction.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ var r = foo(new Function());
4444
>Function : FunctionConstructor
4545

4646
var r1 = foo((x) => x);
47-
>r1 : Function
48-
>foo((x) => x) : Function
47+
>r1 : (x: any) => any
48+
>foo((x) => x) : (x: any) => any
4949
>foo : <T extends Function>(x: T) => T
5050
>(x) => x : (x: any) => any
5151
>x : any
@@ -60,8 +60,8 @@ var r2 = foo((x: string[]) => x);
6060
>x : string[]
6161

6262
var r3 = foo(function (x) { return x });
63-
>r3 : Function
64-
>foo(function (x) { return x }) : Function
63+
>r3 : (x: any) => any
64+
>foo(function (x) { return x }) : (x: any) => any
6565
>foo : <T extends Function>(x: T) => T
6666
>function (x) { return x } : (x: any) => any
6767
>x : any

tests/baselines/reference/inferentialTypingUsingApparentType2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function foo<T extends { m(p: string): number }>(x: T): T {
1313
}
1414

1515
foo({ m(x) { return x.length } });
16-
>foo({ m(x) { return x.length } }) : { m(x: string): number; }
16+
>foo({ m(x) { return x.length } }) : { m(p: string): number; }
1717
>foo : <T extends { m(p: string): number; }>(x: T) => T
1818
>{ m(x) { return x.length } } : { m(x: string): number; }
1919
>m : (x: string) => number

tests/baselines/reference/inferringAnyFunctionType5.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ function f<T extends { q: (p1: number) => number }>(p: T): T {
1313
}
1414

1515
var v = f({ q: x => x });
16-
>v : { q: (x: number) => number; }
17-
>f({ q: x => x }) : { q: (x: number) => number; }
16+
>v : { q: (p1: number) => number; }
17+
>f({ q: x => x }) : { q: (p1: number) => number; }
1818
>f : <T extends { q: (p1: number) => number; }>(p: T) => T
1919
>{ q: x => x } : { q: (x: number) => number; }
2020
>q : (x: number) => number

tests/baselines/reference/promisePermutations3.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ tests/cases/compiler/promisePermutations3.ts(159,21): error TS2345: Argument of
7171
Types of parameters 'onfulfilled' and 'success' are incompatible.
7272
Types of parameters 'value' and 'value' are incompatible.
7373
Type 'number' is not assignable to type 'string'.
74-
tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of type '{ <T>(x: T): IPromise<T>; <T>(x: T, y: T): Promise<T>; }' is not assignable to parameter of type '(value: {}) => Promise<any>'.
74+
tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of type '{ <T>(x: T): IPromise<T>; <T>(x: T, y: T): Promise<T>; }' is not assignable to parameter of type '(value: (x: any) => any) => Promise<any>'.
7575
Type 'IPromise<any>' is not assignable to type 'Promise<any>'.
7676
Types of property 'then' are incompatible.
7777
Type '<U>(success?: (value: any) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise<U>' is not assignable to type '{ <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>; <U>(success?: (value: any) => Promise<U>, error?: (error: any) => Promise<U>, progress?: (progress: any) => void): Promise<U>; <U>(success?: (value: any) => Promise<U>, error?: (error: any) => U, progress?: (progress: any) => void): Promise<U>; <U>(success?: (value: any) => U, error?: (error: any) => Promise<U>, progress?: (progress: any) => void): Promise<U>; <U>(success?: (value: any) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise<U>; }'.
@@ -352,7 +352,7 @@ tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of
352352
var s12a = s12.then(testFunction12, testFunction12, testFunction12); // ok
353353
var s12b = s12.then(testFunction12P, testFunction12P, testFunction12P); // ok
354354
~~~~~~~~~~~~~~~
355-
!!! error TS2345: Argument of type '{ <T>(x: T): IPromise<T>; <T>(x: T, y: T): Promise<T>; }' is not assignable to parameter of type '(value: {}) => Promise<any>'.
355+
!!! error TS2345: Argument of type '{ <T>(x: T): IPromise<T>; <T>(x: T, y: T): Promise<T>; }' is not assignable to parameter of type '(value: (x: any) => any) => Promise<any>'.
356356
!!! error TS2345: Type 'IPromise<any>' is not assignable to type 'Promise<any>'.
357357
!!! error TS2345: Types of property 'then' are incompatible.
358358
!!! error TS2345: Type '<U>(success?: (value: any) => U, error?: (error: any) => U, progress?: (progress: any) => void) => IPromise<U>' is not assignable to type '{ <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>; <U>(success?: (value: any) => Promise<U>, error?: (error: any) => Promise<U>, progress?: (progress: any) => void): Promise<U>; <U>(success?: (value: any) => Promise<U>, error?: (error: any) => U, progress?: (progress: any) => void): Promise<U>; <U>(success?: (value: any) => U, error?: (error: any) => Promise<U>, progress?: (progress: any) => void): Promise<U>; <U>(success?: (value: any) => U, error?: (error: any) => U, progress?: (progress: any) => void): Promise<U>; }'.

0 commit comments

Comments
 (0)