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

Allow rest elements to follow other rest elements in tuple types #55446

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16307,14 +16307,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return false;
}

function isTupleNormalizable(node: TupleTypeNode) {
let hasSeenRest = false;
for (const element of node.elements) {
const flags = getTupleElementFlags(element);
if (flags & ElementFlags.Variadic) {
return true;
}
if (flags & ElementFlags.Rest) {
if (hasSeenRest) {
return true;
}
hasSeenRest = true;
}
}
return false;
}

function getTypeFromArrayOrTupleTypeNode(node: ArrayTypeNode | TupleTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
const target = getArrayOrTupleTargetType(node);
if (target === emptyGenericType) {
links.resolvedType = emptyObjectType;
}
else if (!(node.kind === SyntaxKind.TupleType && some(node.elements, e => !!(getTupleElementFlags(e) & ElementFlags.Variadic))) && isDeferredTypeReferenceNode(node)) {
else if (!(node.kind === SyntaxKind.TupleType && isTupleNormalizable(node)) && isDeferredTypeReferenceNode(node)) {
links.resolvedType = node.kind === SyntaxKind.TupleType && node.elements.length === 0 ? target :
createDeferredTypeReference(target, node, /*mapper*/ undefined);
}
Expand Down Expand Up @@ -39410,10 +39427,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
else if (flags & ElementFlags.Rest) {
if (seenRestElement) {
grammarErrorOnNode(e, Diagnostics.A_rest_element_cannot_follow_another_rest_element);
break;
}
seenRestElement = true;
}
else if (flags & ElementFlags.Optional) {
Expand Down
4 changes: 0 additions & 4 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,6 @@
"category": "Error",
"code": 1264
},
"A rest element cannot follow another rest element.": {
"category": "Error",
"code": 1265
},
"An optional element cannot follow a rest element.": {
"category": "Error",
"code": 1266
Expand Down
11 changes: 4 additions & 7 deletions tests/baselines/reference/variadicTuples2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
variadicTuples2.ts(7,34): error TS1265: A rest element cannot follow another rest element.
variadicTuples2.ts(8,34): error TS1266: An optional element cannot follow a rest element.
variadicTuples2.ts(9,30): error TS1257: A required element cannot follow an optional element.
variadicTuples2.ts(42,1): error TS2322: Type '[string, string, number, number]' is not assignable to type '[...string[], number]'.
Expand Down Expand Up @@ -65,20 +64,18 @@ variadicTuples2.ts(134,25): error TS2345: Argument of type '["blah2", 1, 2, 3]'
Type 'number' is not assignable to type 'string'.


==== variadicTuples2.ts (29 errors) ====
==== variadicTuples2.ts (28 errors) ====
// Declarations

type V00 = [number, ...string[]];
type V01 = [...string[], number];
type V03 = [number, ...string[], number];
type V04 = [number, ...string[], ...boolean[]];

type V10 = [number, ...string[], ...boolean[]]; // Error
~~~~~~~~~~~~
!!! error TS1265: A rest element cannot follow another rest element.
type V11 = [number, ...string[], boolean?]; // Error
type V10 = [number, ...string[], boolean?]; // Error
~~~~~~~~
!!! error TS1266: An optional element cannot follow a rest element.
type V12 = [number, string?, boolean]; // Error
type V11 = [number, string?, boolean]; // Error
~~~~~~~
!!! error TS1257: A required element cannot follow an optional element.

Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/variadicTuples2.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
type V00 = [number, ...string[]];
type V01 = [...string[], number];
type V03 = [number, ...string[], number];
type V04 = [number, ...string[], ...boolean[]];

type V10 = [number, ...string[], ...boolean[]]; // Error
type V11 = [number, ...string[], boolean?]; // Error
type V12 = [number, string?, boolean]; // Error
type V10 = [number, ...string[], boolean?]; // Error
type V11 = [number, string?, boolean]; // Error

// Normalization

Expand Down Expand Up @@ -239,9 +239,9 @@ var e1 = foo('blah1', 'blah2', 1, 2, 3); // Error
type V00 = [number, ...string[]];
type V01 = [...string[], number];
type V03 = [number, ...string[], number];
type V10 = [number, ...string[], ...boolean[]];
type V11 = [number, ...string[], boolean?];
type V12 = [number, string?, boolean];
type V04 = [number, ...string[], ...boolean[]];
type V10 = [number, ...string[], boolean?];
type V11 = [number, string?, boolean];
type Tup3<T extends unknown[], U extends unknown[], V extends unknown[]> = [...T, ...U, ...V];
type V20 = Tup3<[number], string[], [number]>;
type V21 = Tup3<[number], [string?], [boolean]>;
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/variadicTuples2.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ type V01 = [...string[], number];
type V03 = [number, ...string[], number];
>V03 : Symbol(V03, Decl(variadicTuples2.ts, 3, 33))

type V10 = [number, ...string[], ...boolean[]]; // Error
>V10 : Symbol(V10, Decl(variadicTuples2.ts, 4, 41))
type V04 = [number, ...string[], ...boolean[]];
>V04 : Symbol(V04, Decl(variadicTuples2.ts, 4, 41))

type V11 = [number, ...string[], boolean?]; // Error
>V11 : Symbol(V11, Decl(variadicTuples2.ts, 6, 47))
type V10 = [number, ...string[], boolean?]; // Error
>V10 : Symbol(V10, Decl(variadicTuples2.ts, 5, 47))

type V12 = [number, string?, boolean]; // Error
>V12 : Symbol(V12, Decl(variadicTuples2.ts, 7, 43))
type V11 = [number, string?, boolean]; // Error
>V11 : Symbol(V11, Decl(variadicTuples2.ts, 7, 43))

// Normalization

Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/variadicTuples2.types
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ type V01 = [...string[], number];
type V03 = [number, ...string[], number];
>V03 : [number, ...string[], number]

type V10 = [number, ...string[], ...boolean[]]; // Error
>V10 : [number, ...string[], ...boolean[]]
type V04 = [number, ...string[], ...boolean[]];
>V04 : [number, ...(string | boolean)[]]

type V11 = [number, ...string[], boolean?]; // Error
>V11 : [number, ...string[], (boolean | undefined)?]
type V10 = [number, ...string[], boolean?]; // Error
>V10 : [number, ...string[], (boolean | undefined)?]

type V12 = [number, string?, boolean]; // Error
>V12 : [number, (string | undefined)?, boolean]
type V11 = [number, string?, boolean]; // Error
>V11 : [number, (string | undefined)?, boolean]

// Normalization

Expand Down
6 changes: 3 additions & 3 deletions tests/cases/conformance/types/tuple/variadicTuples2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
type V00 = [number, ...string[]];
type V01 = [...string[], number];
type V03 = [number, ...string[], number];
type V04 = [number, ...string[], ...boolean[]];

type V10 = [number, ...string[], ...boolean[]]; // Error
type V11 = [number, ...string[], boolean?]; // Error
type V12 = [number, string?, boolean]; // Error
type V10 = [number, ...string[], boolean?]; // Error
type V11 = [number, string?, boolean]; // Error

// Normalization

Expand Down