Merge pull request #31680 from microsoft/fixGenericReturnTypeInference

Fix generic return type inference
This commit is contained in:
Anders Hejlsberg 2019-05-30 16:33:22 -07:00 committed by GitHub
commit 7dc1f40dc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 227 additions and 10 deletions

View file

@ -14933,13 +14933,6 @@ namespace ts {
return context && createInferenceContextWorker(map(context.inferences, cloneInferenceInfo), context.signature, context.flags | extraFlags, context.compareTypes);
}
function cloneInferredPartOfContext(context: InferenceContext): InferenceContext | undefined {
const inferences = filter(context.inferences, hasInferenceCandidates);
return inferences.length ?
createInferenceContextWorker(map(inferences, cloneInferenceInfo), context.signature, context.flags, context.compareTypes) :
undefined;
}
function createInferenceContextWorker(inferences: InferenceInfo[], signature: Signature | undefined, flags: InferenceFlags, compareTypes: TypeComparer): InferenceContext {
const context: InferenceContext = {
inferences,
@ -20912,7 +20905,8 @@ namespace ts {
// We clone the inference context to avoid disturbing a resolution in progress for an
// outer call expression. Effectively we just want a snapshot of whatever has been
// inferred for any outer call expression so far.
const outerMapper = getMapperFromContext(cloneInferenceContext(getInferenceContext(node), InferenceFlags.NoDefault));
const outerContext = getInferenceContext(node);
const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault));
const instantiatedType = instantiateType(contextualType, outerMapper);
// If the contextual type is a generic function type with a single call signature, we
// instantiate the type with its own type parameters and type arguments. This ensures that
@ -20929,8 +20923,13 @@ namespace ts {
// Inferences made from return types have lower priority than all other inferences.
inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType);
// Create a type mapper for instantiating generic contextual types using the inferences made
// from the return type.
context.returnMapper = getMapperFromContext(cloneInferredPartOfContext(context));
// from the return type. We need a separate inference pass here because (a) instantiation of
// the source type uses the outer context's return mapper (which excludes inferences made from
// outer arguments), and (b) we don't want any further inferences going into this context.
const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags);
const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper);
inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType);
context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(returnContext) : undefined;
}
}

View file

@ -200,4 +200,23 @@ tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts(180,26): error TS23
!!! error TS2322: Types of property 'state' are incompatible.
!!! error TS2322: Type 'State.B' is not assignable to type 'State.A'.
!!! related TS6502 tests/cases/compiler/inferFromGenericFunctionReturnTypes3.ts:179:28: The expected type comes from the return type of this signature.
// Repros from #31443
enum Enum { A, B }
class ClassWithConvert<T> {
constructor(val: T) { }
convert(converter: { to: (v: T) => T; }) { }
}
function fn<T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) { }
fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A));
type Func<T> = (x: T) => T;
declare function makeFoo<T>(x: T): Func<T>;
declare function baz<U>(x: Func<U>, y: Func<U>): void;
baz(makeFoo(Enum.A), makeFoo(Enum.A));

View file

@ -179,6 +179,25 @@ enum State { A, B }
type Foo = { state: State }
declare function bar<T>(f: () => T[]): T[];
let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); // Error
// Repros from #31443
enum Enum { A, B }
class ClassWithConvert<T> {
constructor(val: T) { }
convert(converter: { to: (v: T) => T; }) { }
}
function fn<T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) { }
fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A));
type Func<T> = (x: T) => T;
declare function makeFoo<T>(x: T): Func<T>;
declare function baz<U>(x: Func<U>, y: Func<U>): void;
baz(makeFoo(Enum.A), makeFoo(Enum.A));
//// [inferFromGenericFunctionReturnTypes3.js]
@ -278,6 +297,19 @@ var State;
State[State["B"] = 1] = "B";
})(State || (State = {}));
let x = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); // Error
// Repros from #31443
var Enum;
(function (Enum) {
Enum[Enum["A"] = 0] = "A";
Enum[Enum["B"] = 1] = "B";
})(Enum || (Enum = {}));
class ClassWithConvert {
constructor(val) { }
convert(converter) { }
}
function fn(arg, f) { }
fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A));
baz(makeFoo(Enum.A), makeFoo(Enum.A));
//// [inferFromGenericFunctionReturnTypes3.d.ts]

View file

@ -459,3 +459,84 @@ let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]);
>State : Symbol(State, Decl(inferFromGenericFunctionReturnTypes3.ts, 174, 56))
>B : Symbol(State.B, Decl(inferFromGenericFunctionReturnTypes3.ts, 176, 15))
// Repros from #31443
enum Enum { A, B }
>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79))
>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>B : Symbol(Enum.B, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 14))
class ClassWithConvert<T> {
>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23))
constructor(val: T) { }
>val : Symbol(val, Decl(inferFromGenericFunctionReturnTypes3.ts, 186, 14))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23))
convert(converter: { to: (v: T) => T; }) { }
>convert : Symbol(ClassWithConvert.convert, Decl(inferFromGenericFunctionReturnTypes3.ts, 186, 25))
>converter : Symbol(converter, Decl(inferFromGenericFunctionReturnTypes3.ts, 187, 10))
>to : Symbol(to, Decl(inferFromGenericFunctionReturnTypes3.ts, 187, 22))
>v : Symbol(v, Decl(inferFromGenericFunctionReturnTypes3.ts, 187, 28))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 185, 23))
}
function fn<T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) { }
>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes3.ts, 188, 1))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 12))
>arg : Symbol(arg, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 15))
>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 12))
>f : Symbol(f, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 40))
>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 190, 12))
fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A));
>fn : Symbol(fn, Decl(inferFromGenericFunctionReturnTypes3.ts, 188, 1))
>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18))
>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79))
>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>ClassWithConvert : Symbol(ClassWithConvert, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 18))
>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79))
>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
type Func<T> = (x: T) => T;
>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 10))
>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 16))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 10))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 10))
declare function makeFoo<T>(x: T): Func<T>;
>makeFoo : Symbol(makeFoo, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 27))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 25))
>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 28))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 25))
>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69))
>T : Symbol(T, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 25))
declare function baz<U>(x: Func<U>, y: Func<U>): void;
>baz : Symbol(baz, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 43))
>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 21))
>x : Symbol(x, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 24))
>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69))
>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 21))
>y : Symbol(y, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 35))
>Func : Symbol(Func, Decl(inferFromGenericFunctionReturnTypes3.ts, 191, 69))
>U : Symbol(U, Decl(inferFromGenericFunctionReturnTypes3.ts, 196, 21))
baz(makeFoo(Enum.A), makeFoo(Enum.A));
>baz : Symbol(baz, Decl(inferFromGenericFunctionReturnTypes3.ts, 195, 43))
>makeFoo : Symbol(makeFoo, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 27))
>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79))
>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>makeFoo : Symbol(makeFoo, Decl(inferFromGenericFunctionReturnTypes3.ts, 193, 27))
>Enum.A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))
>Enum : Symbol(Enum, Decl(inferFromGenericFunctionReturnTypes3.ts, 179, 79))
>A : Symbol(Enum.A, Decl(inferFromGenericFunctionReturnTypes3.ts, 183, 11))

View file

@ -506,3 +506,70 @@ let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]);
>State : typeof State
>B : State.B
// Repros from #31443
enum Enum { A, B }
>Enum : Enum
>A : Enum.A
>B : Enum.B
class ClassWithConvert<T> {
>ClassWithConvert : ClassWithConvert<T>
constructor(val: T) { }
>val : T
convert(converter: { to: (v: T) => T; }) { }
>convert : (converter: { to: (v: T) => T; }) => void
>converter : { to: (v: T) => T; }
>to : (v: T) => T
>v : T
}
function fn<T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) { }
>fn : <T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) => void
>arg : ClassWithConvert<T>
>f : () => ClassWithConvert<T>
fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A));
>fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A)) : void
>fn : <T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) => void
>new ClassWithConvert(Enum.A) : ClassWithConvert<Enum>
>ClassWithConvert : typeof ClassWithConvert
>Enum.A : Enum.A
>Enum : typeof Enum
>A : Enum.A
>() => new ClassWithConvert(Enum.A) : () => ClassWithConvert<Enum>
>new ClassWithConvert(Enum.A) : ClassWithConvert<Enum>
>ClassWithConvert : typeof ClassWithConvert
>Enum.A : Enum.A
>Enum : typeof Enum
>A : Enum.A
type Func<T> = (x: T) => T;
>Func : Func<T>
>x : T
declare function makeFoo<T>(x: T): Func<T>;
>makeFoo : <T>(x: T) => Func<T>
>x : T
declare function baz<U>(x: Func<U>, y: Func<U>): void;
>baz : <U>(x: Func<U>, y: Func<U>) => void
>x : Func<U>
>y : Func<U>
baz(makeFoo(Enum.A), makeFoo(Enum.A));
>baz(makeFoo(Enum.A), makeFoo(Enum.A)) : void
>baz : <U>(x: Func<U>, y: Func<U>) => void
>makeFoo(Enum.A) : Func<Enum>
>makeFoo : <T>(x: T) => Func<T>
>Enum.A : Enum.A
>Enum : typeof Enum
>A : Enum.A
>makeFoo(Enum.A) : Func<Enum>
>makeFoo : <T>(x: T) => Func<T>
>Enum.A : Enum.A
>Enum : typeof Enum
>A : Enum.A

View file

@ -182,3 +182,22 @@ enum State { A, B }
type Foo = { state: State }
declare function bar<T>(f: () => T[]): T[];
let x: Foo[] = bar(() => !!true ? [{ state: State.A }] : [{ state: State.B }]); // Error
// Repros from #31443
enum Enum { A, B }
class ClassWithConvert<T> {
constructor(val: T) { }
convert(converter: { to: (v: T) => T; }) { }
}
function fn<T>(arg: ClassWithConvert<T>, f: () => ClassWithConvert<T>) { }
fn(new ClassWithConvert(Enum.A), () => new ClassWithConvert(Enum.A));
type Func<T> = (x: T) => T;
declare function makeFoo<T>(x: T): Func<T>;
declare function baz<U>(x: Func<U>, y: Func<U>): void;
baz(makeFoo(Enum.A), makeFoo(Enum.A));