Skip to content

Commit 5d09688

Browse files
authored
Merge pull request microsoft#33228 from microsoft/fix32976
Less aggressive contextual signature instantiation
2 parents 5b9a56f + bbec8b3 commit 5d09688

7 files changed

+205
-9
lines changed

src/compiler/checker.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ namespace ts {
177177
const enum ContextFlags {
178178
None = 0,
179179
Signature = 1 << 0, // Obtaining contextual signature
180+
NoConstraints = 1 << 1, // Don't obtain type variable constraints
180181
}
181182

182183
const enum AccessFlags {
@@ -19236,7 +19237,7 @@ namespace ts {
1923619237
getContextualTypeForObjectLiteralMethod(node, contextFlags) :
1923719238
getContextualType(node, contextFlags);
1923819239
const instantiatedType = instantiateContextualType(contextualType, node, contextFlags);
19239-
if (instantiatedType) {
19240+
if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) {
1924019241
const apparentType = mapType(instantiatedType, getApparentType, /*noReductions*/ true);
1924119242
if (apparentType.flags & TypeFlags.Union) {
1924219243
if (isObjectLiteralExpression(node)) {
@@ -25142,8 +25143,8 @@ namespace ts {
2514225143
const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true);
2514325144
const signature = callSignature || constructSignature;
2514425145
if (signature && signature.typeParameters) {
25145-
const contextualType = getApparentTypeOfContextualType(<Expression>node);
25146-
if (contextualType && !isMixinConstructorType(contextualType)) {
25146+
const contextualType = getApparentTypeOfContextualType(<Expression>node, ContextFlags.NoConstraints);
25147+
if (contextualType) {
2514725148
const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false);
2514825149
if (contextualSignature && !contextualSignature.typeParameters) {
2514925150
if (checkMode & CheckMode.SkipGenericFunctions) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [contextualSignatureInstantiation4.ts]
2+
// Repros from #32976
3+
4+
declare class Banana<T extends string> { constructor(a: string, property: T) }
5+
6+
declare function fruitFactory1<TFruit>(Fruit: new (...args: any[]) => TFruit): TFruit
7+
const banana1 = fruitFactory1(Banana) // Banana<any>
8+
9+
declare function fruitFactory2<TFruit>(Fruit: new (a: string, ...args: any[]) => TFruit): TFruit
10+
const banana2 = fruitFactory2(Banana) // Banana<any>
11+
12+
declare function fruitFactory3<TFruit>(Fruit: new (a: string, s: "foo", ...args: any[]) => TFruit): TFruit
13+
const banana3 = fruitFactory3(Banana) // Banana<"foo">
14+
15+
declare function fruitFactory4<TFruit>(Fruit: new (a: string, ...args: "foo"[]) => TFruit): TFruit
16+
const banana4 = fruitFactory4(Banana) // Banana<"foo">
17+
18+
declare function fruitFactory5<TFruit>(Fruit: new (...args: "foo"[]) => TFruit): TFruit
19+
const banana5 = fruitFactory5(Banana) // Banana<"foo">
20+
21+
22+
//// [contextualSignatureInstantiation4.js]
23+
"use strict";
24+
// Repros from #32976
25+
var banana1 = fruitFactory1(Banana); // Banana<any>
26+
var banana2 = fruitFactory2(Banana); // Banana<any>
27+
var banana3 = fruitFactory3(Banana); // Banana<"foo">
28+
var banana4 = fruitFactory4(Banana); // Banana<"foo">
29+
var banana5 = fruitFactory5(Banana); // Banana<"foo">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
=== tests/cases/compiler/contextualSignatureInstantiation4.ts ===
2+
// Repros from #32976
3+
4+
declare class Banana<T extends string> { constructor(a: string, property: T) }
5+
>Banana : Symbol(Banana, Decl(contextualSignatureInstantiation4.ts, 0, 0))
6+
>T : Symbol(T, Decl(contextualSignatureInstantiation4.ts, 2, 21))
7+
>a : Symbol(a, Decl(contextualSignatureInstantiation4.ts, 2, 53))
8+
>property : Symbol(property, Decl(contextualSignatureInstantiation4.ts, 2, 63))
9+
>T : Symbol(T, Decl(contextualSignatureInstantiation4.ts, 2, 21))
10+
11+
declare function fruitFactory1<TFruit>(Fruit: new (...args: any[]) => TFruit): TFruit
12+
>fruitFactory1 : Symbol(fruitFactory1, Decl(contextualSignatureInstantiation4.ts, 2, 78))
13+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 4, 31))
14+
>Fruit : Symbol(Fruit, Decl(contextualSignatureInstantiation4.ts, 4, 39))
15+
>args : Symbol(args, Decl(contextualSignatureInstantiation4.ts, 4, 51))
16+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 4, 31))
17+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 4, 31))
18+
19+
const banana1 = fruitFactory1(Banana) // Banana<any>
20+
>banana1 : Symbol(banana1, Decl(contextualSignatureInstantiation4.ts, 5, 5))
21+
>fruitFactory1 : Symbol(fruitFactory1, Decl(contextualSignatureInstantiation4.ts, 2, 78))
22+
>Banana : Symbol(Banana, Decl(contextualSignatureInstantiation4.ts, 0, 0))
23+
24+
declare function fruitFactory2<TFruit>(Fruit: new (a: string, ...args: any[]) => TFruit): TFruit
25+
>fruitFactory2 : Symbol(fruitFactory2, Decl(contextualSignatureInstantiation4.ts, 5, 37))
26+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 7, 31))
27+
>Fruit : Symbol(Fruit, Decl(contextualSignatureInstantiation4.ts, 7, 39))
28+
>a : Symbol(a, Decl(contextualSignatureInstantiation4.ts, 7, 51))
29+
>args : Symbol(args, Decl(contextualSignatureInstantiation4.ts, 7, 61))
30+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 7, 31))
31+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 7, 31))
32+
33+
const banana2 = fruitFactory2(Banana) // Banana<any>
34+
>banana2 : Symbol(banana2, Decl(contextualSignatureInstantiation4.ts, 8, 5))
35+
>fruitFactory2 : Symbol(fruitFactory2, Decl(contextualSignatureInstantiation4.ts, 5, 37))
36+
>Banana : Symbol(Banana, Decl(contextualSignatureInstantiation4.ts, 0, 0))
37+
38+
declare function fruitFactory3<TFruit>(Fruit: new (a: string, s: "foo", ...args: any[]) => TFruit): TFruit
39+
>fruitFactory3 : Symbol(fruitFactory3, Decl(contextualSignatureInstantiation4.ts, 8, 37))
40+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 10, 31))
41+
>Fruit : Symbol(Fruit, Decl(contextualSignatureInstantiation4.ts, 10, 39))
42+
>a : Symbol(a, Decl(contextualSignatureInstantiation4.ts, 10, 51))
43+
>s : Symbol(s, Decl(contextualSignatureInstantiation4.ts, 10, 61))
44+
>args : Symbol(args, Decl(contextualSignatureInstantiation4.ts, 10, 71))
45+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 10, 31))
46+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 10, 31))
47+
48+
const banana3 = fruitFactory3(Banana) // Banana<"foo">
49+
>banana3 : Symbol(banana3, Decl(contextualSignatureInstantiation4.ts, 11, 5))
50+
>fruitFactory3 : Symbol(fruitFactory3, Decl(contextualSignatureInstantiation4.ts, 8, 37))
51+
>Banana : Symbol(Banana, Decl(contextualSignatureInstantiation4.ts, 0, 0))
52+
53+
declare function fruitFactory4<TFruit>(Fruit: new (a: string, ...args: "foo"[]) => TFruit): TFruit
54+
>fruitFactory4 : Symbol(fruitFactory4, Decl(contextualSignatureInstantiation4.ts, 11, 37))
55+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 13, 31))
56+
>Fruit : Symbol(Fruit, Decl(contextualSignatureInstantiation4.ts, 13, 39))
57+
>a : Symbol(a, Decl(contextualSignatureInstantiation4.ts, 13, 51))
58+
>args : Symbol(args, Decl(contextualSignatureInstantiation4.ts, 13, 61))
59+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 13, 31))
60+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 13, 31))
61+
62+
const banana4 = fruitFactory4(Banana) // Banana<"foo">
63+
>banana4 : Symbol(banana4, Decl(contextualSignatureInstantiation4.ts, 14, 5))
64+
>fruitFactory4 : Symbol(fruitFactory4, Decl(contextualSignatureInstantiation4.ts, 11, 37))
65+
>Banana : Symbol(Banana, Decl(contextualSignatureInstantiation4.ts, 0, 0))
66+
67+
declare function fruitFactory5<TFruit>(Fruit: new (...args: "foo"[]) => TFruit): TFruit
68+
>fruitFactory5 : Symbol(fruitFactory5, Decl(contextualSignatureInstantiation4.ts, 14, 37))
69+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 16, 31))
70+
>Fruit : Symbol(Fruit, Decl(contextualSignatureInstantiation4.ts, 16, 39))
71+
>args : Symbol(args, Decl(contextualSignatureInstantiation4.ts, 16, 51))
72+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 16, 31))
73+
>TFruit : Symbol(TFruit, Decl(contextualSignatureInstantiation4.ts, 16, 31))
74+
75+
const banana5 = fruitFactory5(Banana) // Banana<"foo">
76+
>banana5 : Symbol(banana5, Decl(contextualSignatureInstantiation4.ts, 17, 5))
77+
>fruitFactory5 : Symbol(fruitFactory5, Decl(contextualSignatureInstantiation4.ts, 14, 37))
78+
>Banana : Symbol(Banana, Decl(contextualSignatureInstantiation4.ts, 0, 0))
79+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
=== tests/cases/compiler/contextualSignatureInstantiation4.ts ===
2+
// Repros from #32976
3+
4+
declare class Banana<T extends string> { constructor(a: string, property: T) }
5+
>Banana : Banana<T>
6+
>a : string
7+
>property : T
8+
9+
declare function fruitFactory1<TFruit>(Fruit: new (...args: any[]) => TFruit): TFruit
10+
>fruitFactory1 : <TFruit>(Fruit: new (...args: any[]) => TFruit) => TFruit
11+
>Fruit : new (...args: any[]) => TFruit
12+
>args : any[]
13+
14+
const banana1 = fruitFactory1(Banana) // Banana<any>
15+
>banana1 : Banana<any>
16+
>fruitFactory1(Banana) : Banana<any>
17+
>fruitFactory1 : <TFruit>(Fruit: new (...args: any[]) => TFruit) => TFruit
18+
>Banana : typeof Banana
19+
20+
declare function fruitFactory2<TFruit>(Fruit: new (a: string, ...args: any[]) => TFruit): TFruit
21+
>fruitFactory2 : <TFruit>(Fruit: new (a: string, ...args: any[]) => TFruit) => TFruit
22+
>Fruit : new (a: string, ...args: any[]) => TFruit
23+
>a : string
24+
>args : any[]
25+
26+
const banana2 = fruitFactory2(Banana) // Banana<any>
27+
>banana2 : Banana<any>
28+
>fruitFactory2(Banana) : Banana<any>
29+
>fruitFactory2 : <TFruit>(Fruit: new (a: string, ...args: any[]) => TFruit) => TFruit
30+
>Banana : typeof Banana
31+
32+
declare function fruitFactory3<TFruit>(Fruit: new (a: string, s: "foo", ...args: any[]) => TFruit): TFruit
33+
>fruitFactory3 : <TFruit>(Fruit: new (a: string, s: "foo", ...args: any[]) => TFruit) => TFruit
34+
>Fruit : new (a: string, s: "foo", ...args: any[]) => TFruit
35+
>a : string
36+
>s : "foo"
37+
>args : any[]
38+
39+
const banana3 = fruitFactory3(Banana) // Banana<"foo">
40+
>banana3 : Banana<"foo">
41+
>fruitFactory3(Banana) : Banana<"foo">
42+
>fruitFactory3 : <TFruit>(Fruit: new (a: string, s: "foo", ...args: any[]) => TFruit) => TFruit
43+
>Banana : typeof Banana
44+
45+
declare function fruitFactory4<TFruit>(Fruit: new (a: string, ...args: "foo"[]) => TFruit): TFruit
46+
>fruitFactory4 : <TFruit>(Fruit: new (a: string, ...args: "foo"[]) => TFruit) => TFruit
47+
>Fruit : new (a: string, ...args: "foo"[]) => TFruit
48+
>a : string
49+
>args : "foo"[]
50+
51+
const banana4 = fruitFactory4(Banana) // Banana<"foo">
52+
>banana4 : Banana<"foo">
53+
>fruitFactory4(Banana) : Banana<"foo">
54+
>fruitFactory4 : <TFruit>(Fruit: new (a: string, ...args: "foo"[]) => TFruit) => TFruit
55+
>Banana : typeof Banana
56+
57+
declare function fruitFactory5<TFruit>(Fruit: new (...args: "foo"[]) => TFruit): TFruit
58+
>fruitFactory5 : <TFruit>(Fruit: new (...args: "foo"[]) => TFruit) => TFruit
59+
>Fruit : new (...args: "foo"[]) => TFruit
60+
>args : "foo"[]
61+
62+
const banana5 = fruitFactory5(Banana) // Banana<"foo">
63+
>banana5 : Banana<"foo">
64+
>fruitFactory5(Banana) : Banana<"foo">
65+
>fruitFactory5 : <TFruit>(Fruit: new (...args: "foo"[]) => TFruit) => TFruit
66+
>Banana : typeof Banana
67+

tests/baselines/reference/functionConstraintSatisfaction2.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ var r7 = foo2(b);
7979
>b : new (x: string) => string
8080

8181
var r8 = foo2(<U>(x: U) => x); // no error expected
82-
>r8 : (x: string) => string
83-
>foo2(<U>(x: U) => x) : (x: string) => string
82+
>r8 : <U>(x: U) => U
83+
>foo2(<U>(x: U) => x) : <U>(x: U) => U
8484
>foo2 : <T extends (x: string) => string>(x: T) => T
8585
><U>(x: U) => x : <U>(x: U) => U
8686
>x : U

tests/baselines/reference/functionConstraintSatisfaction3.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,16 @@ var c2: { <T>(x: T): T; <T>(x: T, y: T): T };
103103
>y : T
104104

105105
var r9 = foo(function <U>(x: U) { return x; });
106-
>r9 : (x: string) => string
107-
>foo(function <U>(x: U) { return x; }) : (x: string) => string
106+
>r9 : <U>(x: U) => U
107+
>foo(function <U>(x: U) { return x; }) : <U>(x: U) => U
108108
>foo : <T extends (x: string) => string>(x: T) => T
109109
>function <U>(x: U) { return x; } : <U>(x: U) => U
110110
>x : U
111111
>x : U
112112

113113
var r10 = foo(<U extends string>(x: U) => x);
114-
>r10 : (x: string) => string
115-
>foo(<U extends string>(x: U) => x) : (x: string) => string
114+
>r10 : <U extends string>(x: U) => U
115+
>foo(<U extends string>(x: U) => x) : <U extends string>(x: U) => U
116116
>foo : <T extends (x: string) => string>(x: T) => T
117117
><U extends string>(x: U) => x : <U extends string>(x: U) => U
118118
>x : U
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @strict: true
2+
3+
// Repros from #32976
4+
5+
declare class Banana<T extends string> { constructor(a: string, property: T) }
6+
7+
declare function fruitFactory1<TFruit>(Fruit: new (...args: any[]) => TFruit): TFruit
8+
const banana1 = fruitFactory1(Banana) // Banana<any>
9+
10+
declare function fruitFactory2<TFruit>(Fruit: new (a: string, ...args: any[]) => TFruit): TFruit
11+
const banana2 = fruitFactory2(Banana) // Banana<any>
12+
13+
declare function fruitFactory3<TFruit>(Fruit: new (a: string, s: "foo", ...args: any[]) => TFruit): TFruit
14+
const banana3 = fruitFactory3(Banana) // Banana<"foo">
15+
16+
declare function fruitFactory4<TFruit>(Fruit: new (a: string, ...args: "foo"[]) => TFruit): TFruit
17+
const banana4 = fruitFactory4(Banana) // Banana<"foo">
18+
19+
declare function fruitFactory5<TFruit>(Fruit: new (...args: "foo"[]) => TFruit): TFruit
20+
const banana5 = fruitFactory5(Banana) // Banana<"foo">

0 commit comments

Comments
 (0)