Merge pull request #31680 from microsoft/fixGenericReturnTypeInference
Fix generic return type inference
This commit is contained in:
commit
7dc1f40dc1
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
@ -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]
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue