Skip to content

Commit 7f5052b

Browse files
authored
Merge pull request #30114 from Microsoft/contextualGenericRestParameter
Improve contextual typing by generic rest parameters
2 parents 237c33b + 0716b87 commit 7f5052b

6 files changed

+311
-32
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10697,9 +10697,9 @@ namespace ts {
1069710697
return !!(<InferenceContext>mapper).typeParameters;
1069810698
}
1069910699

10700-
function cloneTypeMapper(mapper: TypeMapper): TypeMapper {
10700+
function cloneTypeMapper(mapper: TypeMapper, extraFlags: InferenceFlags = 0): TypeMapper {
1070110701
return mapper && isInferenceContext(mapper) ?
10702-
createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | InferenceFlags.NoDefault, mapper.compareTypes, mapper.inferences) :
10702+
createInferenceContext(mapper.typeParameters, mapper.signature, mapper.flags | extraFlags, mapper.compareTypes, mapper.inferences) :
1070310703
mapper;
1070410704
}
1070510705

@@ -20081,7 +20081,7 @@ namespace ts {
2008120081
// We clone the contextual mapper to avoid disturbing a resolution in progress for an
2008220082
// outer call expression. Effectively we just want a snapshot of whatever has been
2008320083
// inferred for any outer call expression so far.
20084-
const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node)));
20084+
const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node), InferenceFlags.NoDefault));
2008520085
// If the contextual type is a generic function type with a single call signature, we
2008620086
// instantiate the type with its own type parameters and type arguments. This ensures that
2008720087
// the type parameters are not erased to type any during type inference such that they can
@@ -21749,6 +21749,17 @@ namespace ts {
2174921749
}
2175021750
}
2175121751
}
21752+
const restType = getEffectiveRestType(context);
21753+
if (restType && restType.flags & TypeFlags.TypeParameter) {
21754+
// The contextual signature has a generic rest parameter. We first instantiate the contextual
21755+
// signature (without fixing type parameters) and assign types to contextually typed parameters.
21756+
const instantiatedContext = instantiateSignature(context, cloneTypeMapper(mapper));
21757+
assignContextualParameterTypes(signature, instantiatedContext);
21758+
// We then infer from a tuple type representing the parameters that correspond to the contextual
21759+
// rest parameter.
21760+
const restPos = getParameterCount(context) - 1;
21761+
inferTypes((<InferenceContext>mapper).inferences, getRestTypeAtPosition(signature, restPos), restType);
21762+
}
2175221763
}
2175321764

2175421765
function assignContextualParameterTypes(signature: Signature, context: Signature) {

tests/baselines/reference/restTuplesFromContextualTypes.errors.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,21 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error
6868
!!! error TS2345: Property '0' is missing in type 'any[]' but required in type '[T[0], ...T[number][]]'.
6969
}
7070

71+
declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;
72+
73+
let g0 = f5(() => "hello");
74+
let g1 = f5((x, y) => 42);
75+
let g2 = f5((x: number, y) => 42);
76+
let g3 = f5((x: number, y: number) => x + y);
77+
let g4 = f5((...args) => true);
78+
79+
declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;
80+
81+
let g5 = pipe(() => true, b => 42);
82+
let g6 = pipe(x => "hello", s => s.length);
83+
let g7 = pipe((x, y) => 42, x => "" + x);
84+
let g8 = pipe((x: number, y: string) => 42, x => "" + x);
85+
7186
// Repro from #25288
7287

7388
declare var tuple: [number, string];

tests/baselines/reference/restTuplesFromContextualTypes.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,21 @@ function f4<T extends any[]>(t: T) {
5757
f((a, b, ...x) => {});
5858
}
5959

60+
declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;
61+
62+
let g0 = f5(() => "hello");
63+
let g1 = f5((x, y) => 42);
64+
let g2 = f5((x: number, y) => 42);
65+
let g3 = f5((x: number, y: number) => x + y);
66+
let g4 = f5((...args) => true);
67+
68+
declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;
69+
70+
let g5 = pipe(() => true, b => 42);
71+
let g6 = pipe(x => "hello", s => s.length);
72+
let g7 = pipe((x, y) => 42, x => "" + x);
73+
let g8 = pipe((x: number, y: string) => 42, x => "" + x);
74+
6075
// Repro from #25288
6176

6277
declare var tuple: [number, string];
@@ -275,6 +290,21 @@ function f4(t) {
275290
}
276291
});
277292
}
293+
var g0 = f5(function () { return "hello"; });
294+
var g1 = f5(function (x, y) { return 42; });
295+
var g2 = f5(function (x, y) { return 42; });
296+
var g3 = f5(function (x, y) { return x + y; });
297+
var g4 = f5(function () {
298+
var args = [];
299+
for (var _i = 0; _i < arguments.length; _i++) {
300+
args[_i] = arguments[_i];
301+
}
302+
return true;
303+
});
304+
var g5 = pipe(function () { return true; }, function (b) { return 42; });
305+
var g6 = pipe(function (x) { return "hello"; }, function (s) { return s.length; });
306+
var g7 = pipe(function (x, y) { return 42; }, function (x) { return "" + x; });
307+
var g8 = pipe(function (x, y) { return 42; }, function (x) { return "" + x; });
278308
(function foo(a, b) { }.apply(void 0, tuple));
279309
(function foo() {
280310
var rest = [];
@@ -309,6 +339,17 @@ declare function f2(cb: (...args: typeof t2) => void): void;
309339
declare const t3: [boolean, ...string[]];
310340
declare function f3(cb: (x: number, ...args: typeof t3) => void): void;
311341
declare function f4<T extends any[]>(t: T): void;
342+
declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;
343+
declare let g0: () => string;
344+
declare let g1: (x: any, y: any) => number;
345+
declare let g2: (x: number, y: any) => number;
346+
declare let g3: (x: number, y: number) => number;
347+
declare let g4: (...args: any[]) => boolean;
348+
declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;
349+
declare let g5: () => number;
350+
declare let g6: (x: any) => number;
351+
declare let g7: (x: any, y: any) => string;
352+
declare let g8: (x: number, y: string) => string;
312353
declare var tuple: [number, string];
313354
declare function take(cb: (a: number, b: string) => void): void;
314355
declare type ArgsUnion = [number, string] | [number, Error];

tests/baselines/reference/restTuplesFromContextualTypes.symbols

Lines changed: 117 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -238,67 +238,155 @@ function f4<T extends any[]>(t: T) {
238238
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 55, 12))
239239
}
240240

241+
declare function f5<T extends any[], U>(f: (...args: T) => U): (...args: T) => U;
242+
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
243+
>T : Symbol(T, Decl(restTuplesFromContextualTypes.ts, 58, 20))
244+
>U : Symbol(U, Decl(restTuplesFromContextualTypes.ts, 58, 36))
245+
>f : Symbol(f, Decl(restTuplesFromContextualTypes.ts, 58, 40))
246+
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 58, 44))
247+
>T : Symbol(T, Decl(restTuplesFromContextualTypes.ts, 58, 20))
248+
>U : Symbol(U, Decl(restTuplesFromContextualTypes.ts, 58, 36))
249+
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 58, 64))
250+
>T : Symbol(T, Decl(restTuplesFromContextualTypes.ts, 58, 20))
251+
>U : Symbol(U, Decl(restTuplesFromContextualTypes.ts, 58, 36))
252+
253+
let g0 = f5(() => "hello");
254+
>g0 : Symbol(g0, Decl(restTuplesFromContextualTypes.ts, 60, 3))
255+
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
256+
257+
let g1 = f5((x, y) => 42);
258+
>g1 : Symbol(g1, Decl(restTuplesFromContextualTypes.ts, 61, 3))
259+
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
260+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 61, 13))
261+
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 61, 15))
262+
263+
let g2 = f5((x: number, y) => 42);
264+
>g2 : Symbol(g2, Decl(restTuplesFromContextualTypes.ts, 62, 3))
265+
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
266+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 62, 13))
267+
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 62, 23))
268+
269+
let g3 = f5((x: number, y: number) => x + y);
270+
>g3 : Symbol(g3, Decl(restTuplesFromContextualTypes.ts, 63, 3))
271+
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
272+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 63, 13))
273+
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 63, 23))
274+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 63, 13))
275+
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 63, 23))
276+
277+
let g4 = f5((...args) => true);
278+
>g4 : Symbol(g4, Decl(restTuplesFromContextualTypes.ts, 64, 3))
279+
>f5 : Symbol(f5, Decl(restTuplesFromContextualTypes.ts, 56, 1))
280+
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 64, 13))
281+
282+
declare function pipe<A extends any[], B, C>(f: (...args: A) => B, g: (x: B) => C): (...args: A) => C;
283+
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
284+
>A : Symbol(A, Decl(restTuplesFromContextualTypes.ts, 66, 22))
285+
>B : Symbol(B, Decl(restTuplesFromContextualTypes.ts, 66, 38))
286+
>C : Symbol(C, Decl(restTuplesFromContextualTypes.ts, 66, 41))
287+
>f : Symbol(f, Decl(restTuplesFromContextualTypes.ts, 66, 45))
288+
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 66, 49))
289+
>A : Symbol(A, Decl(restTuplesFromContextualTypes.ts, 66, 22))
290+
>B : Symbol(B, Decl(restTuplesFromContextualTypes.ts, 66, 38))
291+
>g : Symbol(g, Decl(restTuplesFromContextualTypes.ts, 66, 66))
292+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 66, 71))
293+
>B : Symbol(B, Decl(restTuplesFromContextualTypes.ts, 66, 38))
294+
>C : Symbol(C, Decl(restTuplesFromContextualTypes.ts, 66, 41))
295+
>args : Symbol(args, Decl(restTuplesFromContextualTypes.ts, 66, 85))
296+
>A : Symbol(A, Decl(restTuplesFromContextualTypes.ts, 66, 22))
297+
>C : Symbol(C, Decl(restTuplesFromContextualTypes.ts, 66, 41))
298+
299+
let g5 = pipe(() => true, b => 42);
300+
>g5 : Symbol(g5, Decl(restTuplesFromContextualTypes.ts, 68, 3))
301+
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
302+
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 68, 25))
303+
304+
let g6 = pipe(x => "hello", s => s.length);
305+
>g6 : Symbol(g6, Decl(restTuplesFromContextualTypes.ts, 69, 3))
306+
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
307+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 69, 14))
308+
>s : Symbol(s, Decl(restTuplesFromContextualTypes.ts, 69, 27))
309+
>s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
310+
>s : Symbol(s, Decl(restTuplesFromContextualTypes.ts, 69, 27))
311+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
312+
313+
let g7 = pipe((x, y) => 42, x => "" + x);
314+
>g7 : Symbol(g7, Decl(restTuplesFromContextualTypes.ts, 70, 3))
315+
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
316+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 70, 15))
317+
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 70, 17))
318+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 70, 27))
319+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 70, 27))
320+
321+
let g8 = pipe((x: number, y: string) => 42, x => "" + x);
322+
>g8 : Symbol(g8, Decl(restTuplesFromContextualTypes.ts, 71, 3))
323+
>pipe : Symbol(pipe, Decl(restTuplesFromContextualTypes.ts, 64, 31))
324+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 71, 15))
325+
>y : Symbol(y, Decl(restTuplesFromContextualTypes.ts, 71, 25))
326+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 71, 43))
327+
>x : Symbol(x, Decl(restTuplesFromContextualTypes.ts, 71, 43))
328+
241329
// Repro from #25288
242330

243331
declare var tuple: [number, string];
244-
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 60, 11))
332+
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 75, 11))
245333

246334
(function foo(a, b){}(...tuple));
247-
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 61, 1))
248-
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 61, 14))
249-
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 61, 16))
250-
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 60, 11))
335+
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 76, 1))
336+
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 76, 14))
337+
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 76, 16))
338+
>tuple : Symbol(tuple, Decl(restTuplesFromContextualTypes.ts, 75, 11))
251339

252340
// Repro from #25289
253341

254342
declare function take(cb: (a: number, b: string) => void): void;
255-
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 61, 33))
256-
>cb : Symbol(cb, Decl(restTuplesFromContextualTypes.ts, 65, 22))
257-
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 65, 27))
258-
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 65, 37))
343+
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 76, 33))
344+
>cb : Symbol(cb, Decl(restTuplesFromContextualTypes.ts, 80, 22))
345+
>a : Symbol(a, Decl(restTuplesFromContextualTypes.ts, 80, 27))
346+
>b : Symbol(b, Decl(restTuplesFromContextualTypes.ts, 80, 37))
259347

260348
(function foo(...rest){}(1, ''));
261-
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 67, 1))
262-
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 67, 14))
349+
>foo : Symbol(foo, Decl(restTuplesFromContextualTypes.ts, 82, 1))
350+
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 82, 14))
263351

264352
take(function(...rest){});
265-
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 61, 33))
266-
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 68, 14))
353+
>take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 76, 33))
354+
>rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 83, 14))
267355

268356
// Repro from #29833
269357

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

274362
type TupleUnionFunc = (...params: ArgsUnion) => number;
275-
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
276-
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 73, 23))
277-
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26))
363+
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 87, 52))
364+
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 88, 23))
365+
>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 83, 26))
278366

279367
const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => {
280-
>funcUnionTupleNoRest : Symbol(funcUnionTupleNoRest, Decl(restTuplesFromContextualTypes.ts, 75, 5))
281-
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
282-
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46))
283-
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 75, 50))
368+
>funcUnionTupleNoRest : Symbol(funcUnionTupleNoRest, Decl(restTuplesFromContextualTypes.ts, 90, 5))
369+
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 87, 52))
370+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 90, 46))
371+
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 90, 50))
284372

285373
return num;
286-
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46))
374+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 90, 46))
287375

288376
};
289377

290378
const funcUnionTupleRest: TupleUnionFunc = (...params) => {
291-
>funcUnionTupleRest : Symbol(funcUnionTupleRest, Decl(restTuplesFromContextualTypes.ts, 79, 5))
292-
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52))
293-
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44))
379+
>funcUnionTupleRest : Symbol(funcUnionTupleRest, Decl(restTuplesFromContextualTypes.ts, 94, 5))
380+
>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 87, 52))
381+
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 94, 44))
294382

295383
const [num, strOrErr] = params;
296-
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9))
297-
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 80, 13))
298-
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44))
384+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 95, 9))
385+
>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 95, 13))
386+
>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 94, 44))
299387

300388
return num;
301-
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9))
389+
>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 95, 9))
302390

303391
};
304392

0 commit comments

Comments
 (0)