Skip to content

Infer to erased signatures #37261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18588,7 +18588,7 @@ namespace ts {
const len = sourceLen < targetLen ? sourceLen : targetLen;
const skipParameters = !!(getObjectFlags(source) & ObjectFlags.NonInferrableType);
for (let i = 0; i < len; i++) {
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getBaseSignature(targetSignatures[targetLen - len + i]), skipParameters);
inferFromSignature(getBaseSignature(sourceSignatures[sourceLen - len + i]), getErasedSignature(targetSignatures[targetLen - len + i]), skipParameters);
}
}

Expand Down
76 changes: 76 additions & 0 deletions tests/baselines/reference/inferenceErasedSignatures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//// [inferenceErasedSignatures.ts]
// Repro from #37163

declare class SomeBaseClass {
set<K extends keyof this>(key: K, value: this[K]): this[K];
}

abstract class SomeAbstractClass<C, M, R> extends SomeBaseClass {
foo!: (r?: R) => void;
bar!: (r?: any) => void;
abstract baz(c: C): Promise<M>;
}

class SomeClass extends SomeAbstractClass<number, string, boolean> {
async baz(context: number): Promise<string> {
return `${context}`;
}
}

type CType<T> = T extends SomeAbstractClass<infer C, any, any> ? C : never;
type MType<T> = T extends SomeAbstractClass<any, infer M, any> ? M : never;
type RType<T> = T extends SomeAbstractClass<any, any, infer R> ? R : never;

type SomeClassC = CType<SomeClass>; // number
type SomeClassM = MType<SomeClass>; // string
type SomeClassR = RType<SomeClass>; // boolean

// Repro from #37163

interface BaseType<T1, T2> {
set<K extends keyof this>(key: K, value: this[K]): this[K];
useT1(c: T1): void;
useT2(r?: T2): void;
unrelatedButSomehowRelevant(r?: any): void;
}

interface InheritedType extends BaseType<number, boolean> {
// This declaration shouldn't do anything...
useT1(_: number): void
}

// Structural expansion of InheritedType
interface StructuralVersion {
set<K extends keyof this>(key: K, value: this[K]): this[K];
useT1(c: number): void;
useT2(r?: boolean): void;
unrelatedButSomehowRelevant(r?: any): void;
}

type GetT1<T> = T extends BaseType<infer U, any> ? U : never;

type T1 = GetT1<InheritedType>; // number
type T2 = GetT1<StructuralVersion>; // number


//// [inferenceErasedSignatures.js]
"use strict";
// Repro from #37163
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
class SomeAbstractClass extends SomeBaseClass {
}
class SomeClass extends SomeAbstractClass {
baz(context) {
return __awaiter(this, void 0, void 0, function* () {
return `${context}`;
});
}
}
178 changes: 178 additions & 0 deletions tests/baselines/reference/inferenceErasedSignatures.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
=== tests/cases/compiler/inferenceErasedSignatures.ts ===
// Repro from #37163

declare class SomeBaseClass {
>SomeBaseClass : Symbol(SomeBaseClass, Decl(inferenceErasedSignatures.ts, 0, 0))

set<K extends keyof this>(key: K, value: this[K]): this[K];
>set : Symbol(SomeBaseClass.set, Decl(inferenceErasedSignatures.ts, 2, 29))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
>key : Symbol(key, Decl(inferenceErasedSignatures.ts, 3, 30))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
>value : Symbol(value, Decl(inferenceErasedSignatures.ts, 3, 37))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 3, 8))
}

abstract class SomeAbstractClass<C, M, R> extends SomeBaseClass {
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 6, 33))
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 6, 35))
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 6, 38))
>SomeBaseClass : Symbol(SomeBaseClass, Decl(inferenceErasedSignatures.ts, 0, 0))

foo!: (r?: R) => void;
>foo : Symbol(SomeAbstractClass.foo, Decl(inferenceErasedSignatures.ts, 6, 65))
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 7, 11))
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 6, 38))

bar!: (r?: any) => void;
>bar : Symbol(SomeAbstractClass.bar, Decl(inferenceErasedSignatures.ts, 7, 26))
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 8, 11))

abstract baz(c: C): Promise<M>;
>baz : Symbol(SomeAbstractClass.baz, Decl(inferenceErasedSignatures.ts, 8, 28))
>c : Symbol(c, Decl(inferenceErasedSignatures.ts, 9, 17))
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 6, 33))
>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, --, --))
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 6, 35))
}

class SomeClass extends SomeAbstractClass<number, string, boolean> {
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))

async baz(context: number): Promise<string> {
>baz : Symbol(SomeClass.baz, Decl(inferenceErasedSignatures.ts, 12, 68))
>context : Symbol(context, Decl(inferenceErasedSignatures.ts, 13, 14))
>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, --, --))

return `${context}`;
>context : Symbol(context, Decl(inferenceErasedSignatures.ts, 13, 14))
}
}

type CType<T> = T extends SomeAbstractClass<infer C, any, any> ? C : never;
>CType : Symbol(CType, Decl(inferenceErasedSignatures.ts, 16, 1))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 18, 11))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 18, 11))
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 18, 49))
>C : Symbol(C, Decl(inferenceErasedSignatures.ts, 18, 49))

type MType<T> = T extends SomeAbstractClass<any, infer M, any> ? M : never;
>MType : Symbol(MType, Decl(inferenceErasedSignatures.ts, 18, 75))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 19, 11))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 19, 11))
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 19, 54))
>M : Symbol(M, Decl(inferenceErasedSignatures.ts, 19, 54))

type RType<T> = T extends SomeAbstractClass<any, any, infer R> ? R : never;
>RType : Symbol(RType, Decl(inferenceErasedSignatures.ts, 19, 75))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 20, 11))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 20, 11))
>SomeAbstractClass : Symbol(SomeAbstractClass, Decl(inferenceErasedSignatures.ts, 4, 1))
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 20, 59))
>R : Symbol(R, Decl(inferenceErasedSignatures.ts, 20, 59))

type SomeClassC = CType<SomeClass>; // number
>SomeClassC : Symbol(SomeClassC, Decl(inferenceErasedSignatures.ts, 20, 75))
>CType : Symbol(CType, Decl(inferenceErasedSignatures.ts, 16, 1))
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))

type SomeClassM = MType<SomeClass>; // string
>SomeClassM : Symbol(SomeClassM, Decl(inferenceErasedSignatures.ts, 22, 35))
>MType : Symbol(MType, Decl(inferenceErasedSignatures.ts, 18, 75))
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))

type SomeClassR = RType<SomeClass>; // boolean
>SomeClassR : Symbol(SomeClassR, Decl(inferenceErasedSignatures.ts, 23, 35))
>RType : Symbol(RType, Decl(inferenceErasedSignatures.ts, 19, 75))
>SomeClass : Symbol(SomeClass, Decl(inferenceErasedSignatures.ts, 10, 1))

// Repro from #37163

interface BaseType<T1, T2> {
>BaseType : Symbol(BaseType, Decl(inferenceErasedSignatures.ts, 24, 35))
>T1 : Symbol(T1, Decl(inferenceErasedSignatures.ts, 28, 19))
>T2 : Symbol(T2, Decl(inferenceErasedSignatures.ts, 28, 22))

set<K extends keyof this>(key: K, value: this[K]): this[K];
>set : Symbol(BaseType.set, Decl(inferenceErasedSignatures.ts, 28, 29))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
>key : Symbol(key, Decl(inferenceErasedSignatures.ts, 29, 30))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
>value : Symbol(value, Decl(inferenceErasedSignatures.ts, 29, 37))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 29, 8))

useT1(c: T1): void;
>useT1 : Symbol(BaseType.useT1, Decl(inferenceErasedSignatures.ts, 29, 63))
>c : Symbol(c, Decl(inferenceErasedSignatures.ts, 30, 10))
>T1 : Symbol(T1, Decl(inferenceErasedSignatures.ts, 28, 19))

useT2(r?: T2): void;
>useT2 : Symbol(BaseType.useT2, Decl(inferenceErasedSignatures.ts, 30, 23))
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 31, 10))
>T2 : Symbol(T2, Decl(inferenceErasedSignatures.ts, 28, 22))

unrelatedButSomehowRelevant(r?: any): void;
>unrelatedButSomehowRelevant : Symbol(BaseType.unrelatedButSomehowRelevant, Decl(inferenceErasedSignatures.ts, 31, 24))
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 32, 32))
}

interface InheritedType extends BaseType<number, boolean> {
>InheritedType : Symbol(InheritedType, Decl(inferenceErasedSignatures.ts, 33, 1))
>BaseType : Symbol(BaseType, Decl(inferenceErasedSignatures.ts, 24, 35))

// This declaration shouldn't do anything...
useT1(_: number): void
>useT1 : Symbol(InheritedType.useT1, Decl(inferenceErasedSignatures.ts, 35, 59))
>_ : Symbol(_, Decl(inferenceErasedSignatures.ts, 37, 10))
}

// Structural expansion of InheritedType
interface StructuralVersion {
>StructuralVersion : Symbol(StructuralVersion, Decl(inferenceErasedSignatures.ts, 38, 1))

set<K extends keyof this>(key: K, value: this[K]): this[K];
>set : Symbol(StructuralVersion.set, Decl(inferenceErasedSignatures.ts, 41, 30))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
>key : Symbol(key, Decl(inferenceErasedSignatures.ts, 42, 30))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
>value : Symbol(value, Decl(inferenceErasedSignatures.ts, 42, 37))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))
>K : Symbol(K, Decl(inferenceErasedSignatures.ts, 42, 8))

useT1(c: number): void;
>useT1 : Symbol(StructuralVersion.useT1, Decl(inferenceErasedSignatures.ts, 42, 63))
>c : Symbol(c, Decl(inferenceErasedSignatures.ts, 43, 10))

useT2(r?: boolean): void;
>useT2 : Symbol(StructuralVersion.useT2, Decl(inferenceErasedSignatures.ts, 43, 27))
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 44, 10))

unrelatedButSomehowRelevant(r?: any): void;
>unrelatedButSomehowRelevant : Symbol(StructuralVersion.unrelatedButSomehowRelevant, Decl(inferenceErasedSignatures.ts, 44, 29))
>r : Symbol(r, Decl(inferenceErasedSignatures.ts, 45, 32))
}

type GetT1<T> = T extends BaseType<infer U, any> ? U : never;
>GetT1 : Symbol(GetT1, Decl(inferenceErasedSignatures.ts, 46, 1))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 48, 11))
>T : Symbol(T, Decl(inferenceErasedSignatures.ts, 48, 11))
>BaseType : Symbol(BaseType, Decl(inferenceErasedSignatures.ts, 24, 35))
>U : Symbol(U, Decl(inferenceErasedSignatures.ts, 48, 40))
>U : Symbol(U, Decl(inferenceErasedSignatures.ts, 48, 40))

type T1 = GetT1<InheritedType>; // number
>T1 : Symbol(T1, Decl(inferenceErasedSignatures.ts, 48, 61))
>GetT1 : Symbol(GetT1, Decl(inferenceErasedSignatures.ts, 46, 1))
>InheritedType : Symbol(InheritedType, Decl(inferenceErasedSignatures.ts, 33, 1))

type T2 = GetT1<StructuralVersion>; // number
>T2 : Symbol(T2, Decl(inferenceErasedSignatures.ts, 50, 31))
>GetT1 : Symbol(GetT1, Decl(inferenceErasedSignatures.ts, 46, 1))
>StructuralVersion : Symbol(StructuralVersion, Decl(inferenceErasedSignatures.ts, 38, 1))

118 changes: 118 additions & 0 deletions tests/baselines/reference/inferenceErasedSignatures.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
=== tests/cases/compiler/inferenceErasedSignatures.ts ===
// Repro from #37163

declare class SomeBaseClass {
>SomeBaseClass : SomeBaseClass

set<K extends keyof this>(key: K, value: this[K]): this[K];
>set : <K extends keyof this>(key: K, value: this[K]) => this[K]
>key : K
>value : this[K]
}

abstract class SomeAbstractClass<C, M, R> extends SomeBaseClass {
>SomeAbstractClass : SomeAbstractClass<C, M, R>
>SomeBaseClass : SomeBaseClass

foo!: (r?: R) => void;
>foo : (r?: R | undefined) => void
>r : R | undefined

bar!: (r?: any) => void;
>bar : (r?: any) => void
>r : any

abstract baz(c: C): Promise<M>;
>baz : (c: C) => Promise<M>
>c : C
}

class SomeClass extends SomeAbstractClass<number, string, boolean> {
>SomeClass : SomeClass
>SomeAbstractClass : SomeAbstractClass<number, string, boolean>

async baz(context: number): Promise<string> {
>baz : (context: number) => Promise<string>
>context : number

return `${context}`;
>`${context}` : string
>context : number
}
}

type CType<T> = T extends SomeAbstractClass<infer C, any, any> ? C : never;
>CType : CType<T>

type MType<T> = T extends SomeAbstractClass<any, infer M, any> ? M : never;
>MType : MType<T>

type RType<T> = T extends SomeAbstractClass<any, any, infer R> ? R : never;
>RType : RType<T>

type SomeClassC = CType<SomeClass>; // number
>SomeClassC : number

type SomeClassM = MType<SomeClass>; // string
>SomeClassM : string

type SomeClassR = RType<SomeClass>; // boolean
>SomeClassR : boolean

// Repro from #37163

interface BaseType<T1, T2> {
set<K extends keyof this>(key: K, value: this[K]): this[K];
>set : <K extends keyof this>(key: K, value: this[K]) => this[K]
>key : K
>value : this[K]

useT1(c: T1): void;
>useT1 : (c: T1) => void
>c : T1

useT2(r?: T2): void;
>useT2 : (r?: T2 | undefined) => void
>r : T2 | undefined

unrelatedButSomehowRelevant(r?: any): void;
>unrelatedButSomehowRelevant : (r?: any) => void
>r : any
}

interface InheritedType extends BaseType<number, boolean> {
// This declaration shouldn't do anything...
useT1(_: number): void
>useT1 : (_: number) => void
>_ : number
}

// Structural expansion of InheritedType
interface StructuralVersion {
set<K extends keyof this>(key: K, value: this[K]): this[K];
>set : <K extends keyof this>(key: K, value: this[K]) => this[K]
>key : K
>value : this[K]

useT1(c: number): void;
>useT1 : (c: number) => void
>c : number

useT2(r?: boolean): void;
>useT2 : (r?: boolean | undefined) => void
>r : boolean | undefined

unrelatedButSomehowRelevant(r?: any): void;
>unrelatedButSomehowRelevant : (r?: any) => void
>r : any
}

type GetT1<T> = T extends BaseType<infer U, any> ? U : never;
>GetT1 : GetT1<T>

type T1 = GetT1<InheritedType>; // number
>T1 : number

type T2 = GetT1<StructuralVersion>; // number
>T2 : number

Loading