From 6d4d06b4cb1a47bf8076241a42c3b757f5603ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 8 Oct 2025 12:16:51 +0200 Subject: [PATCH 1/5] Properly account for start length when inferring into two variadic tuple elements when implied arity is available --- src/compiler/checker.ts | 2 +- .../reference/variadicTuples4.symbols | 28 ++++++++++++ .../baselines/reference/variadicTuples4.types | 45 +++++++++++++++++++ .../types/tuple/variadicTuples4.ts | 13 ++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/variadicTuples4.symbols create mode 100644 tests/baselines/reference/variadicTuples4.types create mode 100644 tests/cases/conformance/types/tuple/variadicTuples4.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 48bc0da113816..54efdf0595f10 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27319,7 +27319,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const 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, endLength + sourceArity - startLength - targetInfo.impliedArity), elementTypes[startLength]); inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); } } diff --git a/tests/baselines/reference/variadicTuples4.symbols b/tests/baselines/reference/variadicTuples4.symbols new file mode 100644 index 0000000000000..6c3e593daf5d4 --- /dev/null +++ b/tests/baselines/reference/variadicTuples4.symbols @@ -0,0 +1,28 @@ +//// [tests/cases/conformance/types/tuple/variadicTuples4.ts] //// + +=== variadicTuples4.ts === +// https://github.com/microsoft/TypeScript/issues/62561 + +function f( +>f : Symbol(f, Decl(variadicTuples4.ts, 0, 0)) +>T : Symbol(T, Decl(variadicTuples4.ts, 2, 11)) +>V : Symbol(V, Decl(variadicTuples4.ts, 2, 31)) + + x: [boolean, ...V, ...T], +>x : Symbol(x, Decl(variadicTuples4.ts, 2, 53)) +>V : Symbol(V, Decl(variadicTuples4.ts, 2, 31)) +>T : Symbol(T, Decl(variadicTuples4.ts, 2, 11)) + + ...args: V +>args : Symbol(args, Decl(variadicTuples4.ts, 3, 27)) +>V : Symbol(V, Decl(variadicTuples4.ts, 2, 31)) + +) { + return x; +>x : Symbol(x, Decl(variadicTuples4.ts, 2, 53)) +} + +const a = f([true, 2, "b", true], 1, "a"); // ok +>a : Symbol(a, Decl(variadicTuples4.ts, 9, 5)) +>f : Symbol(f, Decl(variadicTuples4.ts, 0, 0)) + diff --git a/tests/baselines/reference/variadicTuples4.types b/tests/baselines/reference/variadicTuples4.types new file mode 100644 index 0000000000000..1f2cbb88ad1f4 --- /dev/null +++ b/tests/baselines/reference/variadicTuples4.types @@ -0,0 +1,45 @@ +//// [tests/cases/conformance/types/tuple/variadicTuples4.ts] //// + +=== variadicTuples4.ts === +// https://github.com/microsoft/TypeScript/issues/62561 + +function f( +>f : (x: [boolean, ...V, ...T], ...args: V) => [boolean, ...V, ...T] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ + + x: [boolean, ...V, ...T], +>x : [boolean, ...V, ...T] +> : ^^^^^^^^^^^^^^^^^^^^^ + + ...args: V +>args : V +> : ^ + +) { + return x; +>x : [boolean, ...V, ...T] +> : ^^^^^^^^^^^^^^^^^^^^^ +} + +const a = f([true, 2, "b", true], 1, "a"); // ok +>a : [boolean, number, string, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f([true, 2, "b", true], 1, "a") : [boolean, number, string, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f : (x: [boolean, ...V, ...T], ...args: V) => [boolean, ...V, ...T] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[true, 2, "b", true] : [true, number, string, true] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>2 : 2 +> : ^ +>"b" : "b" +> : ^^^ +>true : true +> : ^^^^ +>1 : 1 +> : ^ +>"a" : "a" +> : ^^^ + diff --git a/tests/cases/conformance/types/tuple/variadicTuples4.ts b/tests/cases/conformance/types/tuple/variadicTuples4.ts new file mode 100644 index 0000000000000..2cc1ee25d07c7 --- /dev/null +++ b/tests/cases/conformance/types/tuple/variadicTuples4.ts @@ -0,0 +1,13 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/62561 + +function f( + x: [boolean, ...V, ...T], + ...args: V +) { + return x; +} + +const a = f([true, 2, "b", true], 1, "a"); // ok From e7ad72384903fe833b92aeae1b99b80c9bce7397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 8 Oct 2025 12:46:05 +0200 Subject: [PATCH 2/5] fix computation --- src/compiler/checker.ts | 2 +- .../reference/variadicTuples4.symbols | 23 ++++++++++ .../baselines/reference/variadicTuples4.types | 42 +++++++++++++++++++ .../types/tuple/variadicTuples4.ts | 9 ++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 54efdf0595f10..0df5b551f7426 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27319,7 +27319,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const 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 - startLength - targetInfo.impliedArity), elementTypes[startLength]); + inferFromTypes(sliceTupleType(source, startLength, endLength + sourceArity - targetInfo.impliedArity - startLength - endLength), elementTypes[startLength]); inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); } } diff --git a/tests/baselines/reference/variadicTuples4.symbols b/tests/baselines/reference/variadicTuples4.symbols index 6c3e593daf5d4..7dc5e0078d75f 100644 --- a/tests/baselines/reference/variadicTuples4.symbols +++ b/tests/baselines/reference/variadicTuples4.symbols @@ -26,3 +26,26 @@ const a = f([true, 2, "b", true], 1, "a"); // ok >a : Symbol(a, Decl(variadicTuples4.ts, 9, 5)) >f : Symbol(f, Decl(variadicTuples4.ts, 0, 0)) +function f2( +>f2 : Symbol(f2, Decl(variadicTuples4.ts, 9, 42)) +>T : Symbol(T, Decl(variadicTuples4.ts, 11, 12)) +>V : Symbol(V, Decl(variadicTuples4.ts, 11, 32)) + + x: [boolean, ...V, ...T, string], +>x : Symbol(x, Decl(variadicTuples4.ts, 11, 54)) +>V : Symbol(V, Decl(variadicTuples4.ts, 11, 32)) +>T : Symbol(T, Decl(variadicTuples4.ts, 11, 12)) + + ...args: V +>args : Symbol(args, Decl(variadicTuples4.ts, 12, 35)) +>V : Symbol(V, Decl(variadicTuples4.ts, 11, 32)) + +) { + return x; +>x : Symbol(x, Decl(variadicTuples4.ts, 11, 54)) +} + +const a2 = f2([true, 2, "b", true, "c"], 1, "a"); // ok +>a2 : Symbol(a2, Decl(variadicTuples4.ts, 18, 5)) +>f2 : Symbol(f2, Decl(variadicTuples4.ts, 9, 42)) + diff --git a/tests/baselines/reference/variadicTuples4.types b/tests/baselines/reference/variadicTuples4.types index 1f2cbb88ad1f4..a9bb7ab246f33 100644 --- a/tests/baselines/reference/variadicTuples4.types +++ b/tests/baselines/reference/variadicTuples4.types @@ -43,3 +43,45 @@ const a = f([true, 2, "b", true], 1, "a"); // ok >"a" : "a" > : ^^^ +function f2( +>f2 : (x: [boolean, ...V, ...T, string], ...args: V) => [boolean, ...V, ...T, string] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + x: [boolean, ...V, ...T, string], +>x : [boolean, ...V, ...T, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...args: V +>args : V +> : ^ + +) { + return x; +>x : [boolean, ...V, ...T, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +const a2 = f2([true, 2, "b", true, "c"], 1, "a"); // ok +>a2 : [boolean, number, string, boolean, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f2([true, 2, "b", true, "c"], 1, "a") : [boolean, number, string, boolean, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f2 : (x: [boolean, ...V, ...T, string], ...args: V) => [boolean, ...V, ...T, string] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[true, 2, "b", true, "c"] : [true, number, string, true, string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>2 : 2 +> : ^ +>"b" : "b" +> : ^^^ +>true : true +> : ^^^^ +>"c" : "c" +> : ^^^ +>1 : 1 +> : ^ +>"a" : "a" +> : ^^^ + diff --git a/tests/cases/conformance/types/tuple/variadicTuples4.ts b/tests/cases/conformance/types/tuple/variadicTuples4.ts index 2cc1ee25d07c7..86011352e3b57 100644 --- a/tests/cases/conformance/types/tuple/variadicTuples4.ts +++ b/tests/cases/conformance/types/tuple/variadicTuples4.ts @@ -11,3 +11,12 @@ function f( } const a = f([true, 2, "b", true], 1, "a"); // ok + +function f2( + x: [boolean, ...V, ...T, string], + ...args: V +) { + return x; +} + +const a2 = f2([true, 2, "b", true, "c"], 1, "a"); // ok From a340459d72d94fb22afc566f125651a72c7e703c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 8 Oct 2025 12:46:49 +0200 Subject: [PATCH 3/5] simplify --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0df5b551f7426..4560a88a85f68 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27319,7 +27319,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const 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 - startLength - endLength), elementTypes[startLength]); + inferFromTypes(sliceTupleType(source, startLength, sourceArity - targetInfo.impliedArity - startLength), elementTypes[startLength]); inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); } } From 8bd5c858579bb78a6e8c5620ade328df9dd89c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 8 Oct 2025 12:50:47 +0200 Subject: [PATCH 4/5] more tests --- .../reference/variadicTuples4.symbols | 69 +++++++++ .../baselines/reference/variadicTuples4.types | 136 ++++++++++++++++++ .../types/tuple/variadicTuples4.ts | 27 ++++ 3 files changed, 232 insertions(+) diff --git a/tests/baselines/reference/variadicTuples4.symbols b/tests/baselines/reference/variadicTuples4.symbols index 7dc5e0078d75f..d573676fc15d6 100644 --- a/tests/baselines/reference/variadicTuples4.symbols +++ b/tests/baselines/reference/variadicTuples4.symbols @@ -49,3 +49,72 @@ const a2 = f2([true, 2, "b", true, "c"], 1, "a"); // ok >a2 : Symbol(a2, Decl(variadicTuples4.ts, 18, 5)) >f2 : Symbol(f2, Decl(variadicTuples4.ts, 9, 42)) +function f3( +>f3 : Symbol(f3, Decl(variadicTuples4.ts, 18, 49)) +>T : Symbol(T, Decl(variadicTuples4.ts, 20, 12)) +>V : Symbol(V, Decl(variadicTuples4.ts, 20, 32)) + + x: [boolean, ...V, ...T, string, number], +>x : Symbol(x, Decl(variadicTuples4.ts, 20, 54)) +>V : Symbol(V, Decl(variadicTuples4.ts, 20, 32)) +>T : Symbol(T, Decl(variadicTuples4.ts, 20, 12)) + + ...args: V +>args : Symbol(args, Decl(variadicTuples4.ts, 21, 43)) +>V : Symbol(V, Decl(variadicTuples4.ts, 20, 32)) + +) { + return x; +>x : Symbol(x, Decl(variadicTuples4.ts, 20, 54)) +} + +const a3 = f3([true, 2, "b", true, "c", 3], 1, "a"); // ok +>a3 : Symbol(a3, Decl(variadicTuples4.ts, 27, 5)) +>f3 : Symbol(f3, Decl(variadicTuples4.ts, 18, 49)) + +function f4( +>f4 : Symbol(f4, Decl(variadicTuples4.ts, 27, 52)) +>T : Symbol(T, Decl(variadicTuples4.ts, 29, 12)) +>V : Symbol(V, Decl(variadicTuples4.ts, 29, 32)) + + x: [boolean, boolean, boolean, ...V, ...T, string, number], +>x : Symbol(x, Decl(variadicTuples4.ts, 29, 54)) +>V : Symbol(V, Decl(variadicTuples4.ts, 29, 32)) +>T : Symbol(T, Decl(variadicTuples4.ts, 29, 12)) + + ...args: V +>args : Symbol(args, Decl(variadicTuples4.ts, 30, 61)) +>V : Symbol(V, Decl(variadicTuples4.ts, 29, 32)) + +) { + return x; +>x : Symbol(x, Decl(variadicTuples4.ts, 29, 54)) +} + +const a4 = f4([true, true, true, 2, "b", true, "c", 3], 1, "a"); // ok +>a4 : Symbol(a4, Decl(variadicTuples4.ts, 36, 5)) +>f4 : Symbol(f4, Decl(variadicTuples4.ts, 27, 52)) + +function f5( +>f5 : Symbol(f5, Decl(variadicTuples4.ts, 36, 64)) +>T : Symbol(T, Decl(variadicTuples4.ts, 38, 12)) +>V : Symbol(V, Decl(variadicTuples4.ts, 38, 32)) + + x: [boolean, boolean, boolean, ...V, ...T], +>x : Symbol(x, Decl(variadicTuples4.ts, 38, 54)) +>V : Symbol(V, Decl(variadicTuples4.ts, 38, 32)) +>T : Symbol(T, Decl(variadicTuples4.ts, 38, 12)) + + ...args: V +>args : Symbol(args, Decl(variadicTuples4.ts, 39, 45)) +>V : Symbol(V, Decl(variadicTuples4.ts, 38, 32)) + +) { + return x; +>x : Symbol(x, Decl(variadicTuples4.ts, 38, 54)) +} + +const a5 = f5([true, true, true, 2, "b", true], 1, "a"); // ok +>a5 : Symbol(a5, Decl(variadicTuples4.ts, 45, 5)) +>f5 : Symbol(f5, Decl(variadicTuples4.ts, 36, 64)) + diff --git a/tests/baselines/reference/variadicTuples4.types b/tests/baselines/reference/variadicTuples4.types index a9bb7ab246f33..ff46b3ee54958 100644 --- a/tests/baselines/reference/variadicTuples4.types +++ b/tests/baselines/reference/variadicTuples4.types @@ -85,3 +85,139 @@ const a2 = f2([true, 2, "b", true, "c"], 1, "a"); // ok >"a" : "a" > : ^^^ +function f3( +>f3 : (x: [boolean, ...V, ...T, string, number], ...args: V) => [boolean, ...V, ...T, string, number] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + x: [boolean, ...V, ...T, string, number], +>x : [boolean, ...V, ...T, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...args: V +>args : V +> : ^ + +) { + return x; +>x : [boolean, ...V, ...T, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +const a3 = f3([true, 2, "b", true, "c", 3], 1, "a"); // ok +>a3 : [boolean, number, string, boolean, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f3([true, 2, "b", true, "c", 3], 1, "a") : [boolean, number, string, boolean, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f3 : (x: [boolean, ...V, ...T, string, number], ...args: V) => [boolean, ...V, ...T, string, number] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[true, 2, "b", true, "c", 3] : [true, number, string, true, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>2 : 2 +> : ^ +>"b" : "b" +> : ^^^ +>true : true +> : ^^^^ +>"c" : "c" +> : ^^^ +>3 : 3 +> : ^ +>1 : 1 +> : ^ +>"a" : "a" +> : ^^^ + +function f4( +>f4 : (x: [boolean, boolean, boolean, ...V, ...T, string, number], ...args: V) => [boolean, boolean, boolean, ...V, ...T, string, number] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + x: [boolean, boolean, boolean, ...V, ...T, string, number], +>x : [boolean, boolean, boolean, ...V, ...T, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...args: V +>args : V +> : ^ + +) { + return x; +>x : [boolean, boolean, boolean, ...V, ...T, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +const a4 = f4([true, true, true, 2, "b", true, "c", 3], 1, "a"); // ok +>a4 : [boolean, boolean, boolean, number, string, boolean, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f4([true, true, true, 2, "b", true, "c", 3], 1, "a") : [boolean, boolean, boolean, number, string, boolean, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f4 : (x: [boolean, boolean, boolean, ...V, ...T, string, number], ...args: V) => [boolean, boolean, boolean, ...V, ...T, string, number] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[true, true, true, 2, "b", true, "c", 3] : [true, true, true, number, string, true, string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>true : true +> : ^^^^ +>true : true +> : ^^^^ +>2 : 2 +> : ^ +>"b" : "b" +> : ^^^ +>true : true +> : ^^^^ +>"c" : "c" +> : ^^^ +>3 : 3 +> : ^ +>1 : 1 +> : ^ +>"a" : "a" +> : ^^^ + +function f5( +>f5 : (x: [boolean, boolean, boolean, ...V, ...T], ...args: V) => [boolean, boolean, boolean, ...V, ...T] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + x: [boolean, boolean, boolean, ...V, ...T], +>x : [boolean, boolean, boolean, ...V, ...T] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + ...args: V +>args : V +> : ^ + +) { + return x; +>x : [boolean, boolean, boolean, ...V, ...T] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +const a5 = f5([true, true, true, 2, "b", true], 1, "a"); // ok +>a5 : [boolean, boolean, boolean, number, string, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f5([true, true, true, 2, "b", true], 1, "a") : [boolean, boolean, boolean, number, string, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f5 : (x: [boolean, boolean, boolean, ...V, ...T], ...args: V) => [boolean, boolean, boolean, ...V, ...T] +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>[true, true, true, 2, "b", true] : [true, true, true, number, string, true] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>true : true +> : ^^^^ +>true : true +> : ^^^^ +>true : true +> : ^^^^ +>2 : 2 +> : ^ +>"b" : "b" +> : ^^^ +>true : true +> : ^^^^ +>1 : 1 +> : ^ +>"a" : "a" +> : ^^^ + diff --git a/tests/cases/conformance/types/tuple/variadicTuples4.ts b/tests/cases/conformance/types/tuple/variadicTuples4.ts index 86011352e3b57..9df1ba810bc67 100644 --- a/tests/cases/conformance/types/tuple/variadicTuples4.ts +++ b/tests/cases/conformance/types/tuple/variadicTuples4.ts @@ -20,3 +20,30 @@ function f2( } const a2 = f2([true, 2, "b", true, "c"], 1, "a"); // ok + +function f3( + x: [boolean, ...V, ...T, string, number], + ...args: V +) { + return x; +} + +const a3 = f3([true, 2, "b", true, "c", 3], 1, "a"); // ok + +function f4( + x: [boolean, boolean, boolean, ...V, ...T, string, number], + ...args: V +) { + return x; +} + +const a4 = f4([true, true, true, 2, "b", true, "c", 3], 1, "a"); // ok + +function f5( + x: [boolean, boolean, boolean, ...V, ...T], + ...args: V +) { + return x; +} + +const a5 = f5([true, true, true, 2, "b", true], 1, "a"); // ok From 5942d7b6906419e54995b187026c6c80a0aa54b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 8 Oct 2025 12:53:42 +0200 Subject: [PATCH 5/5] make computation clearer --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4560a88a85f68..6c5a5c1c94bc4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27319,7 +27319,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetInfo = getInferenceInfoForType(elementTypes[startLength]); if (targetInfo && targetInfo.impliedArity !== undefined) { // Infer slices from source based on implied arity of T. - inferFromTypes(sliceTupleType(source, startLength, sourceArity - targetInfo.impliedArity - startLength), elementTypes[startLength]); + const otherImpliedArity = sourceArity - targetInfo.impliedArity - startLength - endLength; // implied arity of U + inferFromTypes(sliceTupleType(source, startLength, endLength + otherImpliedArity), elementTypes[startLength]); inferFromTypes(sliceTupleType(source, startLength + targetInfo.impliedArity, endLength), elementTypes[startLength + 1]); } }