Skip to content

Commit c4da903

Browse files
authored
Infer to erased signatures (#37261)
* Use erased signatures as inference targets * Add tests
1 parent 44ada5b commit c4da903

File tree

5 files changed

+428
-1
lines changed

5 files changed

+428
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18588,7 +18588,7 @@ namespace ts {
1858818588
const len = sourceLen < targetLen ? sourceLen : targetLen;
1858918589
const skipParameters = !!(getObjectFlags(source) & ObjectFlags.NonInferrableType);
1859018590
for (let i = 0; i < len; i++) {
18591-
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getBaseSignature(targetSignatures[targetLen - len + i]), skipParameters);
18591+
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i]), skipParameters);
1859218592
}
1859318593
}
1859418594

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//// [inferenceErasedSignatures.ts]
2+
// Repro from #37163
3+
4+
declare class SomeBaseClass {
5+
set<K extends keyof this>(key: K, value: this[K]): this[K];
6+
}
7+
8+
abstract class SomeAbstractClass<C, M, R> extends SomeBaseClass {
9+
foo!: (r?: R) => void;
10+
bar!: (r?: any) => void;
11+
abstract baz(c: C): Promise<M>;
12+
}
13+
14+
class SomeClass extends SomeAbstractClass<number, string, boolean> {
15+
async baz(context: number): Promise<string> {
16+
return `${context}`;
17+
}
18+
}
19+
20+
type CType<T> = T extends SomeAbstractClass<infer C, any, any> ? C : never;
21+
type MType<T> = T extends SomeAbstractClass<any, infer M, any> ? M : never;
22+
type RType<T> = T extends SomeAbstractClass<any, any, infer R> ? R : never;
23+
24+
type SomeClassC = CType<SomeClass>; // number
25+
type SomeClassM = MType<SomeClass>; // string
26+
type SomeClassR = RType<SomeClass>; // boolean
27+
28+
// Repro from #37163
29+
30+
interface BaseType<T1, T2> {
31+
set<K extends keyof this>(key: K, value: this[K]): this[K];
32+
useT1(c: T1): void;
33+
useT2(r?: T2): void;
34+
unrelatedButSomehowRelevant(r?: any): void;
35+
}
36+
37+
interface InheritedType extends BaseType<number, boolean> {
38+
// This declaration shouldn't do anything...
39+
useT1(_: number): void
40+
}
41+
42+
// Structural expansion of InheritedType
43+
interface StructuralVersion {
44+
set<K extends keyof this>(key: K, value: this[K]): this[K];
45+
useT1(c: number): void;
46+
useT2(r?: boolean): void;
47+
unrelatedButSomehowRelevant(r?: any): void;
48+
}
49+
50+
type GetT1<T> = T extends BaseType<infer U, any> ? U : never;
51+
52+
type T1 = GetT1<InheritedType>; // number
53+
type T2 = GetT1<StructuralVersion>; // number
54+
55+
56+
//// [inferenceErasedSignatures.js]
57+
"use strict";
58+
// Repro from #37163
59+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
60+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
61+
return new (P || (P = Promise))(function (resolve, reject) {
62+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
63+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
64+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
65+
step((generator = generator.apply(thisArg, _arguments || [])).next());
66+
});
67+
};
68+
class SomeAbstractClass extends SomeBaseClass {
69+
}
70+
class SomeClass extends SomeAbstractClass {
71+
baz(context) {
72+
return __awaiter(this, void 0, void 0, function* () {
73+
return `${context}`;
74+
});
75+
}
76+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
=== tests/cases/compiler/inferenceErasedSignatures.ts ===
2+
// Repro from #37163
3+
4+
declare class SomeBaseClass {
5+
>SomeBaseClass : Symbol(SomeBaseClass, Decl(inferenceErasedSignatures.ts, 0, 0))
6+
7+
set<K extends keyof this>(key: K, value: this[K]): this[K];
8+
>set : Symbol(SomeBaseClass.set, Decl(inferenceErasedSignatures.ts, 2, 29))
9+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
10+
>key : Symbol(key, Decl(inferenceErasedSignatures.ts, 3, 30))
11+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
12+
>value : Symbol(value, Decl(inferenceErasedSignatures.ts, 3, 37))
13+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
14+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
15+
}
16+
17+
abstract class SomeAbstractClass<C, M, R> extends SomeBaseClass {
18+
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
19+
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 6, 33))
20+
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 6, 35))
21+
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 6, 38))
22+
>SomeBaseClass : Symbol(SomeBaseClass, Decl(inferenceErasedSignatures.ts, 0, 0))
23+
24+
foo!: (r?: R) => void;
25+
>foo : Symbol(SomeAbstractClass.foo, Decl(inferenceErasedSignatures.ts, 6, 65))
26+
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 7, 11))
27+
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 6, 38))
28+
29+
bar!: (r?: any) => void;
30+
>bar : Symbol(SomeAbstractClass.bar, Decl(inferenceErasedSignatures.ts, 7, 26))
31+
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 8, 11))
32+
33+
abstract baz(c: C): Promise<M>;
34+
>baz : Symbol(SomeAbstractClass.baz, Decl(inferenceErasedSignatures.ts, 8, 28))
35+
>c : Symbol(c, Decl(inferenceErasedSignatures.ts, 9, 17))
36+
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 6, 33))
37+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
38+
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 6, 35))
39+
}
40+
41+
class SomeClass extends SomeAbstractClass<number, string, boolean> {
42+
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))
43+
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
44+
45+
async baz(context: number): Promise<string> {
46+
>baz : Symbol(SomeClass.baz, Decl(inferenceErasedSignatures.ts, 12, 68))
47+
>context : Symbol(context, Decl(inferenceErasedSignatures.ts, 13, 14))
48+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
49+
50+
return `${context}`;
51+
>context : Symbol(context, Decl(inferenceErasedSignatures.ts, 13, 14))
52+
}
53+
}
54+
55+
type CType<T> = T extends SomeAbstractClass<infer C, any, any> ? C : never;
56+
>CType : Symbol(CType, Decl(inferenceErasedSignatures.ts, 16, 1))
57+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 18, 11))
58+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 18, 11))
59+
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
60+
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 18, 49))
61+
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 18, 49))
62+
63+
type MType<T> = T extends SomeAbstractClass<any, infer M, any> ? M : never;
64+
>MType : Symbol(MType, Decl(inferenceErasedSignatures.ts, 18, 75))
65+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 19, 11))
66+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 19, 11))
67+
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
68+
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 19, 54))
69+
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 19, 54))
70+
71+
type RType<T> = T extends SomeAbstractClass<any, any, infer R> ? R : never;
72+
>RType : Symbol(RType, Decl(inferenceErasedSignatures.ts, 19, 75))
73+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 20, 11))
74+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 20, 11))
75+
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
76+
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 20, 59))
77+
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 20, 59))
78+
79+
type SomeClassC = CType<SomeClass>; // number
80+
>SomeClassC : Symbol(SomeClassC, Decl(inferenceErasedSignatures.ts, 20, 75))
81+
>CType : Symbol(CType, Decl(inferenceErasedSignatures.ts, 16, 1))
82+
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))
83+
84+
type SomeClassM = MType<SomeClass>; // string
85+
>SomeClassM : Symbol(SomeClassM, Decl(inferenceErasedSignatures.ts, 22, 35))
86+
>MType : Symbol(MType, Decl(inferenceErasedSignatures.ts, 18, 75))
87+
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))
88+
89+
type SomeClassR = RType<SomeClass>; // boolean
90+
>SomeClassR : Symbol(SomeClassR, Decl(inferenceErasedSignatures.ts, 23, 35))
91+
>RType : Symbol(RType, Decl(inferenceErasedSignatures.ts, 19, 75))
92+
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))
93+
94+
// Repro from #37163
95+
96+
interface BaseType<T1, T2> {
97+
>BaseType : Symbol(BaseType, Decl(inferenceErasedSignatures.ts, 24, 35))
98+
>T1 : Symbol(T1, Decl(inferenceErasedSignatures.ts, 28, 19))
99+
>T2 : Symbol(T2, Decl(inferenceErasedSignatures.ts, 28, 22))
100+
101+
set<K extends keyof this>(key: K, value: this[K]): this[K];
102+
>set : Symbol(BaseType.set, Decl(inferenceErasedSignatures.ts, 28, 29))
103+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
104+
>key : Symbol(key, Decl(inferenceErasedSignatures.ts, 29, 30))
105+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
106+
>value : Symbol(value, Decl(inferenceErasedSignatures.ts, 29, 37))
107+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
108+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
109+
110+
useT1(c: T1): void;
111+
>useT1 : Symbol(BaseType.useT1, Decl(inferenceErasedSignatures.ts, 29, 63))
112+
>c : Symbol(c, Decl(inferenceErasedSignatures.ts, 30, 10))
113+
>T1 : Symbol(T1, Decl(inferenceErasedSignatures.ts, 28, 19))
114+
115+
useT2(r?: T2): void;
116+
>useT2 : Symbol(BaseType.useT2, Decl(inferenceErasedSignatures.ts, 30, 23))
117+
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 31, 10))
118+
>T2 : Symbol(T2, Decl(inferenceErasedSignatures.ts, 28, 22))
119+
120+
unrelatedButSomehowRelevant(r?: any): void;
121+
>unrelatedButSomehowRelevant : Symbol(BaseType.unrelatedButSomehowRelevant, Decl(inferenceErasedSignatures.ts, 31, 24))
122+
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 32, 32))
123+
}
124+
125+
interface InheritedType extends BaseType<number, boolean> {
126+
>InheritedType : Symbol(InheritedType, Decl(inferenceErasedSignatures.ts, 33, 1))
127+
>BaseType : Symbol(BaseType, Decl(inferenceErasedSignatures.ts, 24, 35))
128+
129+
// This declaration shouldn't do anything...
130+
useT1(_: number): void
131+
>useT1 : Symbol(InheritedType.useT1, Decl(inferenceErasedSignatures.ts, 35, 59))
132+
>_ : Symbol(_, Decl(inferenceErasedSignatures.ts, 37, 10))
133+
}
134+
135+
// Structural expansion of InheritedType
136+
interface StructuralVersion {
137+
>StructuralVersion : Symbol(StructuralVersion, Decl(inferenceErasedSignatures.ts, 38, 1))
138+
139+
set<K extends keyof this>(key: K, value: this[K]): this[K];
140+
>set : Symbol(StructuralVersion.set, Decl(inferenceErasedSignatures.ts, 41, 30))
141+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
142+
>key : Symbol(key, Decl(inferenceErasedSignatures.ts, 42, 30))
143+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
144+
>value : Symbol(value, Decl(inferenceErasedSignatures.ts, 42, 37))
145+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
146+
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
147+
148+
useT1(c: number): void;
149+
>useT1 : Symbol(StructuralVersion.useT1, Decl(inferenceErasedSignatures.ts, 42, 63))
150+
>c : Symbol(c, Decl(inferenceErasedSignatures.ts, 43, 10))
151+
152+
useT2(r?: boolean): void;
153+
>useT2 : Symbol(StructuralVersion.useT2, Decl(inferenceErasedSignatures.ts, 43, 27))
154+
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 44, 10))
155+
156+
unrelatedButSomehowRelevant(r?: any): void;
157+
>unrelatedButSomehowRelevant : Symbol(StructuralVersion.unrelatedButSomehowRelevant, Decl(inferenceErasedSignatures.ts, 44, 29))
158+
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 45, 32))
159+
}
160+
161+
type GetT1<T> = T extends BaseType<infer U, any> ? U : never;
162+
>GetT1 : Symbol(GetT1, Decl(inferenceErasedSignatures.ts, 46, 1))
163+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 48, 11))
164+
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 48, 11))
165+
>BaseType : Symbol(BaseType, Decl(inferenceErasedSignatures.ts, 24, 35))
166+
>U : Symbol(U, Decl(inferenceErasedSignatures.ts, 48, 40))
167+
>U : Symbol(U, Decl(inferenceErasedSignatures.ts, 48, 40))
168+
169+
type T1 = GetT1<InheritedType>; // number
170+
>T1 : Symbol(T1, Decl(inferenceErasedSignatures.ts, 48, 61))
171+
>GetT1 : Symbol(GetT1, Decl(inferenceErasedSignatures.ts, 46, 1))
172+
>InheritedType : Symbol(InheritedType, Decl(inferenceErasedSignatures.ts, 33, 1))
173+
174+
type T2 = GetT1<StructuralVersion>; // number
175+
>T2 : Symbol(T2, Decl(inferenceErasedSignatures.ts, 50, 31))
176+
>GetT1 : Symbol(GetT1, Decl(inferenceErasedSignatures.ts, 46, 1))
177+
>StructuralVersion : Symbol(StructuralVersion, Decl(inferenceErasedSignatures.ts, 38, 1))
178+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
=== tests/cases/compiler/inferenceErasedSignatures.ts ===
2+
// Repro from #37163
3+
4+
declare class SomeBaseClass {
5+
>SomeBaseClass : SomeBaseClass
6+
7+
set<K extends keyof this>(key: K, value: this[K]): this[K];
8+
>set : <K extends keyof this>(key: K, value: this[K]) => this[K]
9+
>key : K
10+
>value : this[K]
11+
}
12+
13+
abstract class SomeAbstractClass<C, M, R> extends SomeBaseClass {
14+
>SomeAbstractClass : SomeAbstractClass<C, M, R>
15+
>SomeBaseClass : SomeBaseClass
16+
17+
foo!: (r?: R) => void;
18+
>foo : (r?: R | undefined) => void
19+
>r : R | undefined
20+
21+
bar!: (r?: any) => void;
22+
>bar : (r?: any) => void
23+
>r : any
24+
25+
abstract baz(c: C): Promise<M>;
26+
>baz : (c: C) => Promise<M>
27+
>c : C
28+
}
29+
30+
class SomeClass extends SomeAbstractClass<number, string, boolean> {
31+
>SomeClass : SomeClass
32+
>SomeAbstractClass : SomeAbstractClass<number, string, boolean>
33+
34+
async baz(context: number): Promise<string> {
35+
>baz : (context: number) => Promise<string>
36+
>context : number
37+
38+
return `${context}`;
39+
>`${context}` : string
40+
>context : number
41+
}
42+
}
43+
44+
type CType<T> = T extends SomeAbstractClass<infer C, any, any> ? C : never;
45+
>CType : CType<T>
46+
47+
type MType<T> = T extends SomeAbstractClass<any, infer M, any> ? M : never;
48+
>MType : MType<T>
49+
50+
type RType<T> = T extends SomeAbstractClass<any, any, infer R> ? R : never;
51+
>RType : RType<T>
52+
53+
type SomeClassC = CType<SomeClass>; // number
54+
>SomeClassC : number
55+
56+
type SomeClassM = MType<SomeClass>; // string
57+
>SomeClassM : string
58+
59+
type SomeClassR = RType<SomeClass>; // boolean
60+
>SomeClassR : boolean
61+
62+
// Repro from #37163
63+
64+
interface BaseType<T1, T2> {
65+
set<K extends keyof this>(key: K, value: this[K]): this[K];
66+
>set : <K extends keyof this>(key: K, value: this[K]) => this[K]
67+
>key : K
68+
>value : this[K]
69+
70+
useT1(c: T1): void;
71+
>useT1 : (c: T1) => void
72+
>c : T1
73+
74+
useT2(r?: T2): void;
75+
>useT2 : (r?: T2 | undefined) => void
76+
>r : T2 | undefined
77+
78+
unrelatedButSomehowRelevant(r?: any): void;
79+
>unrelatedButSomehowRelevant : (r?: any) => void
80+
>r : any
81+
}
82+
83+
interface InheritedType extends BaseType<number, boolean> {
84+
// This declaration shouldn't do anything...
85+
useT1(_: number): void
86+
>useT1 : (_: number) => void
87+
>_ : number
88+
}
89+
90+
// Structural expansion of InheritedType
91+
interface StructuralVersion {
92+
set<K extends keyof this>(key: K, value: this[K]): this[K];
93+
>set : <K extends keyof this>(key: K, value: this[K]) => this[K]
94+
>key : K
95+
>value : this[K]
96+
97+
useT1(c: number): void;
98+
>useT1 : (c: number) => void
99+
>c : number
100+
101+
useT2(r?: boolean): void;
102+
>useT2 : (r?: boolean | undefined) => void
103+
>r : boolean | undefined
104+
105+
unrelatedButSomehowRelevant(r?: any): void;
106+
>unrelatedButSomehowRelevant : (r?: any) => void
107+
>r : any
108+
}
109+
110+
type GetT1<T> = T extends BaseType<infer U, any> ? U : never;
111+
>GetT1 : GetT1<T>
112+
113+
type T1 = GetT1<InheritedType>; // number
114+
>T1 : number
115+
116+
type T2 = GetT1<StructuralVersion>; // number
117+
>T2 : number
118+

0 commit comments

Comments
 (0)