Skip to content
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

Improve contextual typing by generic rest parameters #30114

Merged
merged 4 commits into from
Feb 28, 2019
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
17 changes: 14 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10678,9 +10678,9 @@ namespace ts {
return !!(<InferenceContext>mapper).typeParameters;
}

function cloneTypeMapper(mapper: TypeMapper): TypeMapper {
function cloneTypeMapper(mapper: TypeMapper, extraFlags: InferenceFlags = 0): TypeMapper {
return mapper && isInferenceContext(mapper) ?
createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.compareTypes, mapper.inferences) :
createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | extraFlags, mapper.compareTypes, mapper.inferences) :
mapper;
}

Expand Down Expand Up @@ -20018,7 +20018,7 @@ namespace ts {
// We clone the contextual mapper 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 instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node)));
const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node), InferenceFlags.NoDefault));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cloneTypeMapper call used to create the returnType mapper inside call resolution doesn't pass InferenceFlags.NoDefault with this change. Intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's intentional. We only want the InferenceFlags.NoDefault behavior here (because we're transposing inferences from the outer call mapper and don't want an absence of inferences in the outer mapper to turn into what appears to be a concrete inference of the default).

// 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
// the type parameters are not erased to type any during type inference such that they can
Expand Down Expand Up @@ -21686,6 +21686,17 @@ namespace ts {
}
}
}
const restType = getEffectiveRestType(context);
if (restType && restType.flags & TypeFlags.TypeParameter) {
// The contextual signature has a generic rest parameter. We first instantiate the contextual
// signature (without fixing type parameters) and assign types to contextually typed parameters.
const instantiatedContext = instantiateSignature(context, cloneTypeMapper(mapper));
assignContextualParameterTypes(signature, instantiatedContext);
// We then infer from a tuple type representing the parameters that correspond to the contextual
// rest parameter.
const restPos = getParameterCount(context) - 1;
inferTypes((<InferenceContext>mapper).inferences, getRestTypeAtPosition(signature, restPos), restType);
}
}

function assignContextualParameterTypes(signature: Signature, context: Signature) {
Expand Down
15 changes: 15 additions & 0 deletions tests/baselines/reference/restTuplesFromContextualTypes.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error
!!! error TS2345: Property '0' is missing in type 'any[]' but required in type '[T[0], ...T[number][]]'.
}

declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;

let g0 = f5(() => "hello");
let g1 = f5((x, y) => 42);
let g2 = f5((x: number, y) => 42);
let g3 = f5((x: number, y: number) => x + y);
let g4 = f5((...args) => true);

declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;

let g5 = pipe(() => true, b => 42);
let g6 = pipe(x => "hello", s => s.length);
let g7 = pipe((x, y) => 42, x => "" + x);
let g8 = pipe((x: number, y: string) => 42, x => "" + x);

// Repro from #25288

declare var tuple: [number, string];
Expand Down
41 changes: 41 additions & 0 deletions tests/baselines/reference/restTuplesFromContextualTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ function f4<T extends any[]>(t: T) {
f((a, b, ...x) => {});
}

declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;

let g0 = f5(() => "hello");
let g1 = f5((x, y) => 42);
let g2 = f5((x: number, y) => 42);
let g3 = f5((x: number, y: number) => x + y);
let g4 = f5((...args) => true);

declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;

let g5 = pipe(() => true, b => 42);
let g6 = pipe(x => "hello", s => s.length);
let g7 = pipe((x, y) => 42, x => "" + x);
let g8 = pipe((x: number, y: string) => 42, x => "" + x);

// Repro from #25288

declare var tuple: [number, string];
Expand Down Expand Up @@ -275,6 +290,21 @@ function f4(t) {
}
});
}
var g0 = f5(function () { return "hello"; });
var g1 = f5(function (x, y) { return 42; });
var g2 = f5(function (x, y) { return 42; });
var g3 = f5(function (x, y) { return x + y; });
var g4 = f5(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return true;
});
var g5 = pipe(function () { return true; }, function (b) { return 42; });
var g6 = pipe(function (x) { return "hello"; }, function (s) { return s.length; });
var g7 = pipe(function (x, y) { return 42; }, function (x) { return "" + x; });
var g8 = pipe(function (x, y) { return 42; }, function (x) { return "" + x; });
(function foo(a, b) { }.apply(void 0, tuple));
(function foo() {
var rest = [];
Expand Down Expand Up @@ -309,6 +339,17 @@ declare function f2(cb: (...args: typeof t2) => void): void;
declare const t3: [boolean, ...string[]];
declare function f3(cb: (x: number, ...args: typeof t3) => void): void;
declare function f4<T extends any[]>(t: T): void;
declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;
declare let g0: () => string;
declare let g1: (x: any, y: any) => number;
declare let g2: (x: number, y: any) => number;
declare let g3: (x: number, y: number) => number;
declare let g4: (...args: any[]) => boolean;
declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;
declare let g5: () => number;
declare let g6: (x: any) => number;
declare let g7: (x: any, y: any) => string;
declare let g8: (x: number, y: string) => string;
declare var tuple: [number, string];
declare function take(cb: (a: number, b: string) => void): void;
declare type ArgsUnion = [number, string] | [number, Error];
Expand Down
146 changes: 117 additions & 29 deletions tests/baselines/reference/restTuplesFromContextualTypes.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -238,67 +238,155 @@ function f4<T extends any[]>(t: T) {
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 55, 12))
}

declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
>T : Symbol(T, Decl(restTuplesFromContextualTypes.ts, 58, 20))
>U : Symbol(U, Decl(restTuplesFromContextualTypes.ts, 58, 36))
>f : Symbol(f, Decl(restTuplesFromContextualTypes.ts, 58, 40))
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 58, 44))
>T : Symbol(T, Decl(restTuplesFromContextualTypes.ts, 58, 20))
>U : Symbol(U, Decl(restTuplesFromContextualTypes.ts, 58, 36))
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 58, 64))
>T : Symbol(T, Decl(restTuplesFromContextualTypes.ts, 58, 20))
>U : Symbol(U, Decl(restTuplesFromContextualTypes.ts, 58, 36))

let g0 = f5(() => "hello");
>g0 : Symbol(g0, Decl(restTuplesFromContextualTypes.ts, 60, 3))
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))

let g1 = f5((x, y) => 42);
>g1 : Symbol(g1, Decl(restTuplesFromContextualTypes.ts, 61, 3))
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 61, 13))
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 61, 15))

let g2 = f5((x: number, y) => 42);
>g2 : Symbol(g2, Decl(restTuplesFromContextualTypes.ts, 62, 3))
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 62, 13))
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 62, 23))

let g3 = f5((x: number, y: number) => x + y);
>g3 : Symbol(g3, Decl(restTuplesFromContextualTypes.ts, 63, 3))
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 63, 13))
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 63, 23))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 63, 13))
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 63, 23))

let g4 = f5((...args) => true);
>g4 : Symbol(g4, Decl(restTuplesFromContextualTypes.ts, 64, 3))
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 64, 13))

declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
>A : Symbol(A, Decl(restTuplesFromContextualTypes.ts, 66, 22))
>B : Symbol(B, Decl(restTuplesFromContextualTypes.ts, 66, 38))
>C : Symbol(C, Decl(restTuplesFromContextualTypes.ts, 66, 41))
>f : Symbol(f, Decl(restTuplesFromContextualTypes.ts, 66, 45))
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 66, 49))
>A : Symbol(A, Decl(restTuplesFromContextualTypes.ts, 66, 22))
>B : Symbol(B, Decl(restTuplesFromContextualTypes.ts, 66, 38))
>g : Symbol(g, Decl(restTuplesFromContextualTypes.ts, 66, 66))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 66, 71))
>B : Symbol(B, Decl(restTuplesFromContextualTypes.ts, 66, 38))
>C : Symbol(C, Decl(restTuplesFromContextualTypes.ts, 66, 41))
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 66, 85))
>A : Symbol(A, Decl(restTuplesFromContextualTypes.ts, 66, 22))
>C : Symbol(C, Decl(restTuplesFromContextualTypes.ts, 66, 41))

let g5 = pipe(() => true, b => 42);
>g5 : Symbol(g5, Decl(restTuplesFromContextualTypes.ts, 68, 3))
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 68, 25))

let g6 = pipe(x => "hello", s => s.length);
>g6 : Symbol(g6, Decl(restTuplesFromContextualTypes.ts, 69, 3))
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 69, 14))
>s : Symbol(s, Decl(restTuplesFromContextualTypes.ts, 69, 27))
>s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
>s : Symbol(s, Decl(restTuplesFromContextualTypes.ts, 69, 27))
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))

let g7 = pipe((x, y) => 42, x => "" + x);
>g7 : Symbol(g7, Decl(restTuplesFromContextualTypes.ts, 70, 3))
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 70, 15))
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 70, 17))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 70, 27))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 70, 27))

let g8 = pipe((x: number, y: string) => 42, x => "" + x);
>g8 : Symbol(g8, Decl(restTuplesFromContextualTypes.ts, 71, 3))
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 71, 15))
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 71, 25))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 71, 43))
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 71, 43))

// Repro from #25288

declare var tuple: [number, string];
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 60, 11))
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 75, 11))

(function foo(a, b){}(...tuple));
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 61, 1))
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 61, 14))
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 61, 16))
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 60, 11))
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 76, 1))
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 76, 14))
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 76, 16))
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 75, 11))

// Repro from #25289

declare function take(cb: (a: number, b: string) => void): void;
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 61, 33))
>cb : Symbol(cb, Decl(restTuplesFromContextualTypes.ts, 65, 22))
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 65, 27))
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 65, 37))
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 76, 33))
>cb : Symbol(cb, Decl(restTuplesFromContextualTypes.ts, 80, 22))
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 80, 27))
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 80, 37))

(function foo(...rest){}(1, ''));
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 67, 1))
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 67, 14))
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 82, 1))
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 82, 14))

take(function(...rest){});
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 61, 33))
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 68, 14))
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 76, 33))
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 83, 14))

// Repro from #29833

type ArgsUnion = [number, string] | [number, Error];
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26))
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 83, 26))
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))

type TupleUnionFunc = (...params: ArgsUnion) => number;
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 73, 23))
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26))
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 87, 52))
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 88, 23))
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 83, 26))

const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
>funcUnionTupleNoRest : Symbol(funcUnionTupleNoRest, Decl(restTuplesFromContextualTypes.ts, 75, 5))
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46))
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 75, 50))
>funcUnionTupleNoRest : Symbol(funcUnionTupleNoRest, Decl(restTuplesFromContextualTypes.ts, 90, 5))
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 87, 52))
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 90, 46))
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 90, 50))

return num;
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46))
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 90, 46))

};

const funcUnionTupleRest: TupleUnionFunc = (...params) => {
>funcUnionTupleRest : Symbol(funcUnionTupleRest, Decl(restTuplesFromContextualTypes.ts, 79, 5))
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44))
>funcUnionTupleRest : Symbol(funcUnionTupleRest, Decl(restTuplesFromContextualTypes.ts, 94, 5))
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 87, 52))
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 94, 44))

const [num, strOrErr] = params;
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9))
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 80, 13))
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44))
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 95, 9))
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 95, 13))
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 94, 44))

return num;
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9))
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 95, 9))

};

Loading