diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ea91ff3fbaa54..efc5a5462f429 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18457,7 +18457,7 @@ namespace ts { } function getEndLengthOfType(type: Type) { - return isTupleType(type) ? getTypeReferenceArity(type) - findLastIndex(type.target.elementFlags, f => !!(f & ElementFlags.Variable)) - 1 : 0; + return isTupleType(type) ? getTypeReferenceArity(type) - findLastIndex(type.target.elementFlags, f => !(f & ElementFlags.Required)) - 1 : 0; } function getElementTypeOfSliceOfTupleType(type: TupleTypeReference, index: number, endSkipCount = 0, writing = false) { diff --git a/tests/baselines/reference/variadicTuples1.errors.txt b/tests/baselines/reference/variadicTuples1.errors.txt index 6ccc9daa42b4b..eac8f5ef32a5f 100644 --- a/tests/baselines/reference/variadicTuples1.errors.txt +++ b/tests/baselines/reference/variadicTuples1.errors.txt @@ -40,9 +40,11 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Typ tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'. Type '"2"' is not assignable to type 'number | "0" | "length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | "every" | "some" | "forEach" | "map" | "filter" | "reduce" | "reduceRight" | "1"'. tests/cases/conformance/types/tuple/variadicTuples1.ts(333,14): error TS7019: Rest parameter 'x' implicitly has an 'any[]' type. +tests/cases/conformance/types/tuple/variadicTuples1.ts(341,19): error TS2322: Type 'string' is not assignable to type 'number | undefined'. +tests/cases/conformance/types/tuple/variadicTuples1.ts(342,19): error TS2322: Type 'string' is not assignable to type 'number | undefined'. -==== tests/cases/conformance/types/tuple/variadicTuples1.ts (19 errors) ==== +==== tests/cases/conformance/types/tuple/variadicTuples1.ts (21 errors) ==== // Variadics in tuple types type TV0 = [string, ...T]; @@ -438,4 +440,27 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(333,14): error TS7019: Re call(...sa, (...x) => 42); ~~~~ !!! error TS7019: Rest parameter 'x' implicitly has an 'any[]' type. + + // No inference to ending optional elements (except with identical structure) + + declare function f20(args: [...T, number?]): T; + + function f21(args: [...U, number?]) { + let v1 = f20(args); // U + let v2 = f20(["foo", "bar"]); // [] + ~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. + let v3 = f20(["foo", 42]); // [] + ~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. + } + + declare function f22(args: [...T, number]): T; + declare function f22(args: [...T]): T; + + function f23(args: [...U, number]) { + let v1 = f22(args); // U + let v2 = f22(["foo", "bar"]); // [string, string] + let v3 = f22(["foo", 42]); // [string] + } \ No newline at end of file diff --git a/tests/baselines/reference/variadicTuples1.js b/tests/baselines/reference/variadicTuples1.js index c1d364682952b..f7d388ea5ae86 100644 --- a/tests/baselines/reference/variadicTuples1.js +++ b/tests/baselines/reference/variadicTuples1.js @@ -332,6 +332,25 @@ call('hello', 32, (a, b) => 42); // Requires [starting-fixed-part, ...rest-part, ending-fixed-part] tuple structure call(...sa, (...x) => 42); + +// No inference to ending optional elements (except with identical structure) + +declare function f20(args: [...T, number?]): T; + +function f21(args: [...U, number?]) { + let v1 = f20(args); // U + let v2 = f20(["foo", "bar"]); // [] + let v3 = f20(["foo", 42]); // [] +} + +declare function f22(args: [...T, number]): T; +declare function f22(args: [...T]): T; + +function f23(args: [...U, number]) { + let v1 = f22(args); // U + let v2 = f22(["foo", "bar"]); // [string, string] + let v3 = f22(["foo", 42]); // [string] +} //// [variadicTuples1.js] @@ -528,6 +547,16 @@ call.apply(void 0, __spreadArrays(sa, [function () { } return 42; }])); +function f21(args) { + var v1 = f20(args); // U + var v2 = f20(["foo", "bar"]); // [] + var v3 = f20(["foo", 42]); // [] +} +function f23(args) { + var v1 = f22(args); // U + var v2 = f22(["foo", "bar"]); // [string, string] + var v3 = f22(["foo", 42]); // [string] +} //// [variadicTuples1.d.ts] @@ -669,3 +698,8 @@ declare const c22: (...b: string[]) => number; declare function curry2(f: (...args: [...T, ...U]) => R, t: [...T], u: [...U]): R; declare function fn10(a: string, b: number, c: boolean): string[]; declare function call(...args: [...T, (...args: T) => R]): [T, R]; +declare function f20(args: [...T, number?]): T; +declare function f21(args: [...U, number?]): void; +declare function f22(args: [...T, number]): T; +declare function f22(args: [...T]): T; +declare function f23(args: [...U, number]): void; diff --git a/tests/baselines/reference/variadicTuples1.symbols b/tests/baselines/reference/variadicTuples1.symbols index fe83d5f0bd7cc..0f6c900fb6cdf 100644 --- a/tests/baselines/reference/variadicTuples1.symbols +++ b/tests/baselines/reference/variadicTuples1.symbols @@ -1141,3 +1141,66 @@ call(...sa, (...x) => 42); >sa : Symbol(sa, Decl(variadicTuples1.ts, 29, 13)) >x : Symbol(x, Decl(variadicTuples1.ts, 332, 13)) +// No inference to ending optional elements (except with identical structure) + +declare function f20(args: [...T, number?]): T; +>f20 : Symbol(f20, Decl(variadicTuples1.ts, 332, 26)) +>T : Symbol(T, Decl(variadicTuples1.ts, 336, 21)) +>args : Symbol(args, Decl(variadicTuples1.ts, 336, 47)) +>T : Symbol(T, Decl(variadicTuples1.ts, 336, 21)) +>T : Symbol(T, Decl(variadicTuples1.ts, 336, 21)) + +function f21(args: [...U, number?]) { +>f21 : Symbol(f21, Decl(variadicTuples1.ts, 336, 73)) +>U : Symbol(U, Decl(variadicTuples1.ts, 338, 13)) +>args : Symbol(args, Decl(variadicTuples1.ts, 338, 33)) +>U : Symbol(U, Decl(variadicTuples1.ts, 338, 13)) + + let v1 = f20(args); // U +>v1 : Symbol(v1, Decl(variadicTuples1.ts, 339, 7)) +>f20 : Symbol(f20, Decl(variadicTuples1.ts, 332, 26)) +>args : Symbol(args, Decl(variadicTuples1.ts, 338, 33)) + + let v2 = f20(["foo", "bar"]); // [] +>v2 : Symbol(v2, Decl(variadicTuples1.ts, 340, 7)) +>f20 : Symbol(f20, Decl(variadicTuples1.ts, 332, 26)) + + let v3 = f20(["foo", 42]); // [] +>v3 : Symbol(v3, Decl(variadicTuples1.ts, 341, 7)) +>f20 : Symbol(f20, Decl(variadicTuples1.ts, 332, 26)) +} + +declare function f22(args: [...T, number]): T; +>f22 : Symbol(f22, Decl(variadicTuples1.ts, 342, 1), Decl(variadicTuples1.ts, 344, 72)) +>T : Symbol(T, Decl(variadicTuples1.ts, 344, 21)) +>args : Symbol(args, Decl(variadicTuples1.ts, 344, 47)) +>T : Symbol(T, Decl(variadicTuples1.ts, 344, 21)) +>T : Symbol(T, Decl(variadicTuples1.ts, 344, 21)) + +declare function f22(args: [...T]): T; +>f22 : Symbol(f22, Decl(variadicTuples1.ts, 342, 1), Decl(variadicTuples1.ts, 344, 72)) +>T : Symbol(T, Decl(variadicTuples1.ts, 345, 21)) +>args : Symbol(args, Decl(variadicTuples1.ts, 345, 47)) +>T : Symbol(T, Decl(variadicTuples1.ts, 345, 21)) +>T : Symbol(T, Decl(variadicTuples1.ts, 345, 21)) + +function f23(args: [...U, number]) { +>f23 : Symbol(f23, Decl(variadicTuples1.ts, 345, 64)) +>U : Symbol(U, Decl(variadicTuples1.ts, 347, 13)) +>args : Symbol(args, Decl(variadicTuples1.ts, 347, 33)) +>U : Symbol(U, Decl(variadicTuples1.ts, 347, 13)) + + let v1 = f22(args); // U +>v1 : Symbol(v1, Decl(variadicTuples1.ts, 348, 7)) +>f22 : Symbol(f22, Decl(variadicTuples1.ts, 342, 1), Decl(variadicTuples1.ts, 344, 72)) +>args : Symbol(args, Decl(variadicTuples1.ts, 347, 33)) + + let v2 = f22(["foo", "bar"]); // [string, string] +>v2 : Symbol(v2, Decl(variadicTuples1.ts, 349, 7)) +>f22 : Symbol(f22, Decl(variadicTuples1.ts, 342, 1), Decl(variadicTuples1.ts, 344, 72)) + + let v3 = f22(["foo", 42]); // [string] +>v3 : Symbol(v3, Decl(variadicTuples1.ts, 350, 7)) +>f22 : Symbol(f22, Decl(variadicTuples1.ts, 342, 1), Decl(variadicTuples1.ts, 344, 72)) +} + diff --git a/tests/baselines/reference/variadicTuples1.types b/tests/baselines/reference/variadicTuples1.types index 9c78c1f88ac89..0c24e873ef8b5 100644 --- a/tests/baselines/reference/variadicTuples1.types +++ b/tests/baselines/reference/variadicTuples1.types @@ -1186,3 +1186,71 @@ call(...sa, (...x) => 42); >x : any[] >42 : 42 +// No inference to ending optional elements (except with identical structure) + +declare function f20(args: [...T, number?]): T; +>f20 : (args: [...T, number?]) => T +>args : [...T, (number | undefined)?] + +function f21(args: [...U, number?]) { +>f21 : (args: [...U, number?]) => void +>args : [...U, (number | undefined)?] + + let v1 = f20(args); // U +>v1 : U +>f20(args) : U +>f20 : (args: [...T, (number | undefined)?]) => T +>args : [...U, (number | undefined)?] + + let v2 = f20(["foo", "bar"]); // [] +>v2 : [] +>f20(["foo", "bar"]) : [] +>f20 : (args: [...T, (number | undefined)?]) => T +>["foo", "bar"] : [string, string] +>"foo" : "foo" +>"bar" : "bar" + + let v3 = f20(["foo", 42]); // [] +>v3 : [] +>f20(["foo", 42]) : [] +>f20 : (args: [...T, (number | undefined)?]) => T +>["foo", 42] : [string, number] +>"foo" : "foo" +>42 : 42 +} + +declare function f22(args: [...T, number]): T; +>f22 : { (args: [...T, number]): T; (args: [...T]): T; } +>args : [...T, number] + +declare function f22(args: [...T]): T; +>f22 : { (args: [...T, number]): T; (args: [...T]): T; } +>args : [...T] + +function f23(args: [...U, number]) { +>f23 : (args: [...U, number]) => void +>args : [...U, number] + + let v1 = f22(args); // U +>v1 : U +>f22(args) : U +>f22 : { (args: [...T, number]): T; (args: [...T]): T; } +>args : [...U, number] + + let v2 = f22(["foo", "bar"]); // [string, string] +>v2 : [string, string] +>f22(["foo", "bar"]) : [string, string] +>f22 : { (args: [...T, number]): T; (args: [...T]): T; } +>["foo", "bar"] : [string, string] +>"foo" : "foo" +>"bar" : "bar" + + let v3 = f22(["foo", 42]); // [string] +>v3 : [string] +>f22(["foo", 42]) : [string] +>f22 : { (args: [...T, number]): T; (args: [...T]): T; } +>["foo", 42] : [string, number] +>"foo" : "foo" +>42 : 42 +} + diff --git a/tests/cases/conformance/types/tuple/variadicTuples1.ts b/tests/cases/conformance/types/tuple/variadicTuples1.ts index 036c65469c32f..07732a0a5a726 100644 --- a/tests/cases/conformance/types/tuple/variadicTuples1.ts +++ b/tests/cases/conformance/types/tuple/variadicTuples1.ts @@ -334,3 +334,22 @@ call('hello', 32, (a, b) => 42); // Requires [starting-fixed-part, ...rest-part, ending-fixed-part] tuple structure call(...sa, (...x) => 42); + +// No inference to ending optional elements (except with identical structure) + +declare function f20(args: [...T, number?]): T; + +function f21(args: [...U, number?]) { + let v1 = f20(args); // U + let v2 = f20(["foo", "bar"]); // [] + let v3 = f20(["foo", 42]); // [] +} + +declare function f22(args: [...T, number]): T; +declare function f22(args: [...T]): T; + +function f23(args: [...U, number]) { + let v1 = f22(args); // U + let v2 = f22(["foo", "bar"]); // [string, string] + let v3 = f22(["foo", 42]); // [string] +}