diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 48bc0da113816..b8f7251bb067b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27316,12 +27316,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (middleLength === 2) { if (elementFlags[startLength] & elementFlags[startLength + 1] & ElementFlags.Variadic) { // Middle of target is [...T, ...U] and source is tuple type - const targetInfo = getInferenceInfoForType(elementTypes[startLength]); + let targetInfo = getInferenceInfoForType(elementTypes[startLength]); if (targetInfo && targetInfo.impliedArity !== undefined) { // Infer slices from source based on implied arity of T. inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity), elementTypes[startLength]); inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); } + else if ((targetInfo = getInferenceInfoForType(elementTypes[startLength + 1]))?.impliedArity !== undefined) { + // Infer slices from source based on implied arity of U. + inferFromTypes(sliceTupleType(source, startLength, endLength + targetInfo!.impliedArity), elementTypes[startLength]); + inferFromTypes(sliceTupleType(source, startLength + sourceArity - endLength - targetInfo!.impliedArity, endLength), elementTypes[startLength + 1]); + } } else if (elementFlags[startLength] & ElementFlags.Variadic && elementFlags[startLength + 1] & ElementFlags.Rest) { // Middle of target is [...T, ...rest] and source is tuple type diff --git a/tests/baselines/reference/variadicTuples4.symbols b/tests/baselines/reference/variadicTuples4.symbols new file mode 100644 index 0000000000000..1f4cbd8ff833f --- /dev/null +++ b/tests/baselines/reference/variadicTuples4.symbols @@ -0,0 +1,140 @@ +//// [tests/cases/conformance/types/tuple/variadicTuples4.ts] //// + +=== variadicTuples4.ts === +// https://github.com/microsoft/TypeScript/issues/56970 + +function partialCall1( +>partialCall1 : Symbol(partialCall1, Decl(variadicTuples4.ts, 0, 0)) +>T : Symbol(T, Decl(variadicTuples4.ts, 2, 22)) +>U : Symbol(U, Decl(variadicTuples4.ts, 2, 47)) +>R : Symbol(R, Decl(variadicTuples4.ts, 2, 73)) + + f: (...args: [...U, ...T]) => R, +>f : Symbol(f, Decl(variadicTuples4.ts, 2, 77)) +>args : Symbol(args, Decl(variadicTuples4.ts, 3, 6)) +>U : Symbol(U, Decl(variadicTuples4.ts, 2, 47)) +>T : Symbol(T, Decl(variadicTuples4.ts, 2, 22)) +>R : Symbol(R, Decl(variadicTuples4.ts, 2, 73)) + + ...tailArgs: T +>tailArgs : Symbol(tailArgs, Decl(variadicTuples4.ts, 3, 34)) +>T : Symbol(T, Decl(variadicTuples4.ts, 2, 22)) + +) { + return (...headArgs: U) => f(...headArgs, ...tailArgs); +>headArgs : Symbol(headArgs, Decl(variadicTuples4.ts, 6, 10)) +>U : Symbol(U, Decl(variadicTuples4.ts, 2, 47)) +>f : Symbol(f, Decl(variadicTuples4.ts, 2, 77)) +>headArgs : Symbol(headArgs, Decl(variadicTuples4.ts, 6, 10)) +>tailArgs : Symbol(tailArgs, Decl(variadicTuples4.ts, 3, 34)) +} + +function source1(a: number, b: number, c: number): number { +>source1 : Symbol(source1, Decl(variadicTuples4.ts, 7, 1)) +>a : Symbol(a, Decl(variadicTuples4.ts, 9, 17)) +>b : Symbol(b, Decl(variadicTuples4.ts, 9, 27)) +>c : Symbol(c, Decl(variadicTuples4.ts, 9, 38)) + + return a + b + c; +>a : Symbol(a, Decl(variadicTuples4.ts, 9, 17)) +>b : Symbol(b, Decl(variadicTuples4.ts, 9, 27)) +>c : Symbol(c, Decl(variadicTuples4.ts, 9, 38)) +} + +const result1 = partialCall1(source1, 1); +>result1 : Symbol(result1, Decl(variadicTuples4.ts, 13, 5)) +>partialCall1 : Symbol(partialCall1, Decl(variadicTuples4.ts, 0, 0)) +>source1 : Symbol(source1, Decl(variadicTuples4.ts, 7, 1)) + +function partialCall2( +>partialCall2 : Symbol(partialCall2, Decl(variadicTuples4.ts, 13, 41)) +>T : Symbol(T, Decl(variadicTuples4.ts, 15, 22)) +>U : Symbol(U, Decl(variadicTuples4.ts, 15, 47)) +>R : Symbol(R, Decl(variadicTuples4.ts, 15, 73)) + + f: (...args: [number, ...U, ...T]) => R, +>f : Symbol(f, Decl(variadicTuples4.ts, 15, 77)) +>args : Symbol(args, Decl(variadicTuples4.ts, 16, 6)) +>U : Symbol(U, Decl(variadicTuples4.ts, 15, 47)) +>T : Symbol(T, Decl(variadicTuples4.ts, 15, 22)) +>R : Symbol(R, Decl(variadicTuples4.ts, 15, 73)) + + ...tailArgs: T +>tailArgs : Symbol(tailArgs, Decl(variadicTuples4.ts, 16, 42)) +>T : Symbol(T, Decl(variadicTuples4.ts, 15, 22)) + +) { + return (...headArgs: U) => f(0, ...headArgs, ...tailArgs); +>headArgs : Symbol(headArgs, Decl(variadicTuples4.ts, 19, 10)) +>U : Symbol(U, Decl(variadicTuples4.ts, 15, 47)) +>f : Symbol(f, Decl(variadicTuples4.ts, 15, 77)) +>headArgs : Symbol(headArgs, Decl(variadicTuples4.ts, 19, 10)) +>tailArgs : Symbol(tailArgs, Decl(variadicTuples4.ts, 16, 42)) +} + +function source2(a: number, b: number, c: number, d: number): number { +>source2 : Symbol(source2, Decl(variadicTuples4.ts, 20, 1)) +>a : Symbol(a, Decl(variadicTuples4.ts, 22, 17)) +>b : Symbol(b, Decl(variadicTuples4.ts, 22, 27)) +>c : Symbol(c, Decl(variadicTuples4.ts, 22, 38)) +>d : Symbol(d, Decl(variadicTuples4.ts, 22, 49)) + + return a + b + c + d; +>a : Symbol(a, Decl(variadicTuples4.ts, 22, 17)) +>b : Symbol(b, Decl(variadicTuples4.ts, 22, 27)) +>c : Symbol(c, Decl(variadicTuples4.ts, 22, 38)) +>d : Symbol(d, Decl(variadicTuples4.ts, 22, 49)) +} + +const result2 = partialCall2(source2, 1); +>result2 : Symbol(result2, Decl(variadicTuples4.ts, 26, 5)) +>partialCall2 : Symbol(partialCall2, Decl(variadicTuples4.ts, 13, 41)) +>source2 : Symbol(source2, Decl(variadicTuples4.ts, 20, 1)) + +function partialCall3( +>partialCall3 : Symbol(partialCall3, Decl(variadicTuples4.ts, 26, 41)) +>T : Symbol(T, Decl(variadicTuples4.ts, 28, 22)) +>U : Symbol(U, Decl(variadicTuples4.ts, 28, 47)) +>R : Symbol(R, Decl(variadicTuples4.ts, 28, 73)) + + f: (...args: [...U, ...T, number]) => R, +>f : Symbol(f, Decl(variadicTuples4.ts, 28, 77)) +>args : Symbol(args, Decl(variadicTuples4.ts, 29, 6)) +>U : Symbol(U, Decl(variadicTuples4.ts, 28, 47)) +>T : Symbol(T, Decl(variadicTuples4.ts, 28, 22)) +>R : Symbol(R, Decl(variadicTuples4.ts, 28, 73)) + + ...tailArgs: T +>tailArgs : Symbol(tailArgs, Decl(variadicTuples4.ts, 29, 42)) +>T : Symbol(T, Decl(variadicTuples4.ts, 28, 22)) + +) { + return (...headArgs: U) => f(...headArgs, ...tailArgs, 100); +>headArgs : Symbol(headArgs, Decl(variadicTuples4.ts, 32, 10)) +>U : Symbol(U, Decl(variadicTuples4.ts, 28, 47)) +>f : Symbol(f, Decl(variadicTuples4.ts, 28, 77)) +>headArgs : Symbol(headArgs, Decl(variadicTuples4.ts, 32, 10)) +>tailArgs : Symbol(tailArgs, Decl(variadicTuples4.ts, 29, 42)) +} + +function source3(a: number, b: number, c: number, d: number): number { +>source3 : Symbol(source3, Decl(variadicTuples4.ts, 33, 1)) +>a : Symbol(a, Decl(variadicTuples4.ts, 35, 17)) +>b : Symbol(b, Decl(variadicTuples4.ts, 35, 27)) +>c : Symbol(c, Decl(variadicTuples4.ts, 35, 38)) +>d : Symbol(d, Decl(variadicTuples4.ts, 35, 49)) + + return a + b + c + d; +>a : Symbol(a, Decl(variadicTuples4.ts, 35, 17)) +>b : Symbol(b, Decl(variadicTuples4.ts, 35, 27)) +>c : Symbol(c, Decl(variadicTuples4.ts, 35, 38)) +>d : Symbol(d, Decl(variadicTuples4.ts, 35, 49)) +} + +const result3 = partialCall3(source3, 1); +>result3 : Symbol(result3, Decl(variadicTuples4.ts, 39, 5)) +>partialCall3 : Symbol(partialCall3, Decl(variadicTuples4.ts, 26, 41)) +>source3 : Symbol(source3, Decl(variadicTuples4.ts, 33, 1)) + +export {} + diff --git a/tests/baselines/reference/variadicTuples4.types b/tests/baselines/reference/variadicTuples4.types new file mode 100644 index 0000000000000..181f1d90f82af --- /dev/null +++ b/tests/baselines/reference/variadicTuples4.types @@ -0,0 +1,224 @@ +//// [tests/cases/conformance/types/tuple/variadicTuples4.ts] //// + +=== variadicTuples4.ts === +// https://github.com/microsoft/TypeScript/issues/56970 + +function partialCall1( +>partialCall1 : (f: (...args: [...U, ...T]) => R, ...tailArgs: T) => (...headArgs: U) => R +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^ + + f: (...args: [...U, ...T]) => R, +>f : (...args: [...U, ...T]) => R +> : ^^^^ ^^ ^^^^^ +>args : [...U, ...T] +> : ^^^^^^^^^^^^ + + ...tailArgs: T +>tailArgs : T +> : ^ + +) { + return (...headArgs: U) => f(...headArgs, ...tailArgs); +>(...headArgs: U) => f(...headArgs, ...tailArgs) : (...headArgs: U) => R +> : ^^^^ ^^ ^^^^^^ +>headArgs : U +> : ^ +>f(...headArgs, ...tailArgs) : R +> : ^ +>f : (...args: [...U, ...T]) => R +> : ^^^^ ^^ ^^^^^ +>...headArgs : any +>headArgs : U +> : ^ +>...tailArgs : any +>tailArgs : T +> : ^ +} + +function source1(a: number, b: number, c: number): number { +>source1 : (a: number, b: number, c: number) => number +> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ +>c : number +> : ^^^^^^ + + return a + b + c; +>a + b + c : number +> : ^^^^^^ +>a + b : number +> : ^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ +>c : number +> : ^^^^^^ +} + +const result1 = partialCall1(source1, 1); +>result1 : (a: number, b: number) => number +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>partialCall1(source1, 1) : (a: number, b: number) => number +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>partialCall1 : (f: (...args: [...U, ...T]) => R, ...tailArgs: T) => (...headArgs: U) => R +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^ +>source1 : (a: number, b: number, c: number) => number +> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>1 : 1 +> : ^ + +function partialCall2( +>partialCall2 : (f: (...args: [number, ...U, ...T]) => R, ...tailArgs: T) => (...headArgs: U) => R +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^ + + f: (...args: [number, ...U, ...T]) => R, +>f : (...args: [number, ...U, ...T]) => R +> : ^^^^ ^^ ^^^^^ +>args : [number, ...U, ...T] +> : ^^^^^^^^^^^^^^^^^^^^ + + ...tailArgs: T +>tailArgs : T +> : ^ + +) { + return (...headArgs: U) => f(0, ...headArgs, ...tailArgs); +>(...headArgs: U) => f(0, ...headArgs, ...tailArgs) : (...headArgs: U) => R +> : ^^^^ ^^ ^^^^^^ +>headArgs : U +> : ^ +>f(0, ...headArgs, ...tailArgs) : R +> : ^ +>f : (...args: [number, ...U, ...T]) => R +> : ^^^^ ^^ ^^^^^ +>0 : 0 +> : ^ +>...headArgs : any +>headArgs : U +> : ^ +>...tailArgs : any +>tailArgs : T +> : ^ +} + +function source2(a: number, b: number, c: number, d: number): number { +>source2 : (a: number, b: number, c: number, d: number) => number +> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ +>c : number +> : ^^^^^^ +>d : number +> : ^^^^^^ + + return a + b + c + d; +>a + b + c + d : number +> : ^^^^^^ +>a + b + c : number +> : ^^^^^^ +>a + b : number +> : ^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ +>c : number +> : ^^^^^^ +>d : number +> : ^^^^^^ +} + +const result2 = partialCall2(source2, 1); +>result2 : (b: number, c: number) => number +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>partialCall2(source2, 1) : (b: number, c: number) => number +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>partialCall2 : (f: (...args: [number, ...U, ...T]) => R, ...tailArgs: T) => (...headArgs: U) => R +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^ +>source2 : (a: number, b: number, c: number, d: number) => number +> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>1 : 1 +> : ^ + +function partialCall3( +>partialCall3 : (f: (...args: [...U, ...T, number]) => R, ...tailArgs: T) => (...headArgs: U) => R +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^ + + f: (...args: [...U, ...T, number]) => R, +>f : (...args: [...U, ...T, number]) => R +> : ^^^^ ^^ ^^^^^ +>args : [...U, ...T, number] +> : ^^^^^^^^^^^^^^^^^^^^ + + ...tailArgs: T +>tailArgs : T +> : ^ + +) { + return (...headArgs: U) => f(...headArgs, ...tailArgs, 100); +>(...headArgs: U) => f(...headArgs, ...tailArgs, 100) : (...headArgs: U) => R +> : ^^^^ ^^ ^^^^^^ +>headArgs : U +> : ^ +>f(...headArgs, ...tailArgs, 100) : R +> : ^ +>f : (...args: [...U, ...T, number]) => R +> : ^^^^ ^^ ^^^^^ +>...headArgs : any +>headArgs : U +> : ^ +>...tailArgs : any +>tailArgs : T +> : ^ +>100 : 100 +> : ^^^ +} + +function source3(a: number, b: number, c: number, d: number): number { +>source3 : (a: number, b: number, c: number, d: number) => number +> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ +>c : number +> : ^^^^^^ +>d : number +> : ^^^^^^ + + return a + b + c + d; +>a + b + c + d : number +> : ^^^^^^ +>a + b + c : number +> : ^^^^^^ +>a + b : number +> : ^^^^^^ +>a : number +> : ^^^^^^ +>b : number +> : ^^^^^^ +>c : number +> : ^^^^^^ +>d : number +> : ^^^^^^ +} + +const result3 = partialCall3(source3, 1); +>result3 : (a: number, b: number) => number +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>partialCall3(source3, 1) : (a: number, b: number) => number +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>partialCall3 : (f: (...args: [...U, ...T, number]) => R, ...tailArgs: T) => (...headArgs: U) => R +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^ +>source3 : (a: number, b: number, c: number, d: number) => number +> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ +>1 : 1 +> : ^ + +export {} + diff --git a/tests/cases/conformance/types/tuple/variadicTuples4.ts b/tests/cases/conformance/types/tuple/variadicTuples4.ts new file mode 100644 index 0000000000000..3b530e85f195f --- /dev/null +++ b/tests/cases/conformance/types/tuple/variadicTuples4.ts @@ -0,0 +1,45 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/56970 + +function partialCall1( + f: (...args: [...U, ...T]) => R, + ...tailArgs: T +) { + return (...headArgs: U) => f(...headArgs, ...tailArgs); +} + +function source1(a: number, b: number, c: number): number { + return a + b + c; +} + +const result1 = partialCall1(source1, 1); + +function partialCall2( + f: (...args: [number, ...U, ...T]) => R, + ...tailArgs: T +) { + return (...headArgs: U) => f(0, ...headArgs, ...tailArgs); +} + +function source2(a: number, b: number, c: number, d: number): number { + return a + b + c + d; +} + +const result2 = partialCall2(source2, 1); + +function partialCall3( + f: (...args: [...U, ...T, number]) => R, + ...tailArgs: T +) { + return (...headArgs: U) => f(...headArgs, ...tailArgs, 100); +} + +function source3(a: number, b: number, c: number, d: number): number { + return a + b + c + d; +} + +const result3 = partialCall3(source3, 1); + +export {}