Skip to content

Commit 70975cd

Browse files
authored
Merge pull request microsoft#24897 from Microsoft/restTuples
Tuples in rest parameters and spread expressions
2 parents bc3268b + 656ccd8 commit 70975cd

File tree

124 files changed

+6268
-1121
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+6268
-1121
lines changed

src/compiler/binder.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3606,6 +3606,8 @@ namespace ts {
36063606
case SyntaxKind.TypeLiteral:
36073607
case SyntaxKind.ArrayType:
36083608
case SyntaxKind.TupleType:
3609+
case SyntaxKind.OptionalType:
3610+
case SyntaxKind.RestType:
36093611
case SyntaxKind.UnionType:
36103612
case SyntaxKind.IntersectionType:
36113613
case SyntaxKind.ConditionalType:

src/compiler/checker.ts

Lines changed: 565 additions & 249 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,6 @@
367367
"category": "Error",
368368
"code": 1121
369369
},
370-
"A tuple type element list cannot be empty.": {
371-
"category": "Error",
372-
"code": 1122
373-
},
374370
"Variable declaration list cannot be empty.": {
375371
"category": "Error",
376372
"code": 1123
@@ -847,6 +843,14 @@
847843
"category": "Error",
848844
"code": 1255
849845
},
846+
"A rest element must be last in a tuple type.": {
847+
"category": "Error",
848+
"code": 1256
849+
},
850+
"A required element cannot follow an optional element.": {
851+
"category": "Error",
852+
"code": 1257
853+
},
850854
"'with' statements are not allowed in an async function block.": {
851855
"category": "Error",
852856
"code": 1300
@@ -2032,6 +2036,18 @@
20322036
"category": "Error",
20332037
"code": 2571
20342038
},
2039+
"Rest signatures are incompatible.": {
2040+
"category": "Error",
2041+
"code": 2572
2042+
},
2043+
"Property '{0}' is incompatible with rest element type.": {
2044+
"category": "Error",
2045+
"code": 2573
2046+
},
2047+
"A rest element type must be an array type.": {
2048+
"category": "Error",
2049+
"code": 2574
2050+
},
20352051
"JSX element attributes type '{0}' may not be a union type.": {
20362052
"category": "Error",
20372053
"code": 2600

src/compiler/emitter.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ namespace ts {
659659
return emitArrayType(<ArrayTypeNode>node);
660660
case SyntaxKind.TupleType:
661661
return emitTupleType(<TupleTypeNode>node);
662+
case SyntaxKind.OptionalType:
663+
return emitOptionalType(<OptionalTypeNode>node);
662664
case SyntaxKind.UnionType:
663665
return emitUnionType(<UnionTypeNode>node);
664666
case SyntaxKind.IntersectionType:
@@ -695,8 +697,9 @@ namespace ts {
695697
return emitJSDocNonNullableType(node as JSDocNonNullableType);
696698
case SyntaxKind.JSDocOptionalType:
697699
return emitJSDocOptionalType(node as JSDocOptionalType);
700+
case SyntaxKind.RestType:
698701
case SyntaxKind.JSDocVariadicType:
699-
return emitJSDocVariadicType(node as JSDocVariadicType);
702+
return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType);
700703

701704
// Binding patterns
702705
case SyntaxKind.ObjectBindingPattern:
@@ -1304,7 +1307,7 @@ namespace ts {
13041307
writePunctuation("]");
13051308
}
13061309

1307-
function emitJSDocVariadicType(node: JSDocVariadicType) {
1310+
function emitRestOrJSDocVariadicType(node: RestTypeNode | JSDocVariadicType) {
13081311
write("...");
13091312
emit(node.type);
13101313
}
@@ -1315,6 +1318,11 @@ namespace ts {
13151318
writePunctuation("]");
13161319
}
13171320

1321+
function emitOptionalType(node: OptionalTypeNode) {
1322+
emit(node.type);
1323+
write("?");
1324+
}
1325+
13181326
function emitUnionType(node: UnionTypeNode) {
13191327
emitList(node, node.types, ListFormat.UnionTypeConstituents);
13201328
}

src/compiler/factory.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,12 +745,36 @@ namespace ts {
745745
return node;
746746
}
747747

748-
export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: ReadonlyArray<TypeNode>) {
748+
export function updateTupleTypeNode(node: TupleTypeNode, elementTypes: ReadonlyArray<TypeNode>) {
749749
return node.elementTypes !== elementTypes
750750
? updateNode(createTupleTypeNode(elementTypes), node)
751751
: node;
752752
}
753753

754+
export function createOptionalTypeNode(type: TypeNode) {
755+
const node = createSynthesizedNode(SyntaxKind.OptionalType) as OptionalTypeNode;
756+
node.type = parenthesizeArrayTypeMember(type);
757+
return node;
758+
}
759+
760+
export function updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode {
761+
return node.type !== type
762+
? updateNode(createOptionalTypeNode(type), node)
763+
: node;
764+
}
765+
766+
export function createRestTypeNode(type: TypeNode) {
767+
const node = createSynthesizedNode(SyntaxKind.RestType) as RestTypeNode;
768+
node.type = type;
769+
return node;
770+
}
771+
772+
export function updateRestTypeNode(node: RestTypeNode, type: TypeNode): RestTypeNode {
773+
return node.type !== type
774+
? updateNode(createRestTypeNode(type), node)
775+
: node;
776+
}
777+
754778
export function createUnionTypeNode(types: ReadonlyArray<TypeNode>): UnionTypeNode {
755779
return <UnionTypeNode>createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types);
756780
}

src/compiler/parser.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -445,19 +445,17 @@ namespace ts {
445445
case SyntaxKind.JsxClosingElement:
446446
return visitNode(cbNode, (<JsxClosingElement>node).tagName);
447447

448+
case SyntaxKind.OptionalType:
449+
case SyntaxKind.RestType:
448450
case SyntaxKind.JSDocTypeExpression:
449-
return visitNode(cbNode, (<JSDocTypeExpression>node).type);
450451
case SyntaxKind.JSDocNonNullableType:
451-
return visitNode(cbNode, (<JSDocNonNullableType>node).type);
452452
case SyntaxKind.JSDocNullableType:
453-
return visitNode(cbNode, (<JSDocNullableType>node).type);
454453
case SyntaxKind.JSDocOptionalType:
455-
return visitNode(cbNode, (<JSDocOptionalType>node).type);
454+
case SyntaxKind.JSDocVariadicType:
455+
return visitNode(cbNode, (<OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocTypeReferencingNode>node).type);
456456
case SyntaxKind.JSDocFunctionType:
457457
return visitNodes(cbNode, cbNodes, (<JSDocFunctionType>node).parameters) ||
458458
visitNode(cbNode, (<JSDocFunctionType>node).type);
459-
case SyntaxKind.JSDocVariadicType:
460-
return visitNode(cbNode, (<JSDocVariadicType>node).type);
461459
case SyntaxKind.JSDocComment:
462460
return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags);
463461
case SyntaxKind.JSDocParameterTag:
@@ -2289,7 +2287,7 @@ namespace ts {
22892287
function parseJSDocAllType(postFixEquals: boolean): JSDocAllType | JSDocOptionalType {
22902288
const result = createNode(SyntaxKind.JSDocAllType) as JSDocAllType;
22912289
if (postFixEquals) {
2292-
return createJSDocPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType;
2290+
return createPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType;
22932291
}
22942292
else {
22952293
nextToken();
@@ -2367,7 +2365,7 @@ namespace ts {
23672365
type = finishNode(variadic);
23682366
}
23692367
if (token() === SyntaxKind.EqualsToken) {
2370-
return createJSDocPostfixType(SyntaxKind.JSDocOptionalType, type);
2368+
return createPostfixType(SyntaxKind.JSDocOptionalType, type);
23712369
}
23722370
return type;
23732371
}
@@ -2775,9 +2773,23 @@ namespace ts {
27752773
return finishNode(node);
27762774
}
27772775

2776+
function parseTupleElementType() {
2777+
const pos = getNodePos();
2778+
if (parseOptional(SyntaxKind.DotDotDotToken)) {
2779+
const node = <RestTypeNode>createNode(SyntaxKind.RestType, pos);
2780+
node.type = parseType();
2781+
return finishNode(node);
2782+
}
2783+
const type = parseType();
2784+
if (!(contextFlags & NodeFlags.JSDoc) && type.kind === SyntaxKind.JSDocNullableType && type.pos === (<JSDocNullableType>type).type.pos) {
2785+
type.kind = SyntaxKind.OptionalType;
2786+
}
2787+
return type;
2788+
}
2789+
27782790
function parseTupleType(): TupleTypeNode {
27792791
const node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
2780-
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
2792+
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
27812793
return finishNode(node);
27822794
}
27832795

@@ -2960,14 +2972,14 @@ namespace ts {
29602972
while (!scanner.hasPrecedingLineBreak()) {
29612973
switch (token()) {
29622974
case SyntaxKind.ExclamationToken:
2963-
type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type);
2975+
type = createPostfixType(SyntaxKind.JSDocNonNullableType, type);
29642976
break;
29652977
case SyntaxKind.QuestionToken:
29662978
// If not in JSDoc and next token is start of a type we have a conditional type
29672979
if (!(contextFlags & NodeFlags.JSDoc) && lookAhead(nextTokenIsStartOfType)) {
29682980
return type;
29692981
}
2970-
type = createJSDocPostfixType(SyntaxKind.JSDocNullableType, type);
2982+
type = createPostfixType(SyntaxKind.JSDocNullableType, type);
29712983
break;
29722984
case SyntaxKind.OpenBracketToken:
29732985
parseExpected(SyntaxKind.OpenBracketToken);
@@ -2992,9 +3004,9 @@ namespace ts {
29923004
return type;
29933005
}
29943006

2995-
function createJSDocPostfixType(kind: SyntaxKind, type: TypeNode) {
3007+
function createPostfixType(kind: SyntaxKind, type: TypeNode) {
29963008
nextToken();
2997-
const postfix = createNode(kind, type.pos) as JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
3009+
const postfix = createNode(kind, type.pos) as OptionalTypeNode | JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
29983010
postfix.type = type;
29993011
return finishNode(postfix);
30003012
}

src/compiler/transformers/ts.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ namespace ts {
380380

381381
case SyntaxKind.ArrayType:
382382
case SyntaxKind.TupleType:
383+
case SyntaxKind.OptionalType:
384+
case SyntaxKind.RestType:
383385
case SyntaxKind.TypeLiteral:
384386
case SyntaxKind.TypePredicate:
385387
case SyntaxKind.TypeParameter:

src/compiler/types.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ namespace ts {
225225
TypeLiteral,
226226
ArrayType,
227227
TupleType,
228+
OptionalType,
229+
RestType,
228230
UnionType,
229231
IntersectionType,
230232
ConditionalType,
@@ -269,6 +271,7 @@ namespace ts {
269271
AsExpression,
270272
NonNullExpression,
271273
MetaProperty,
274+
SyntheticExpression,
272275

273276
// Misc
274277
TemplateSpan,
@@ -1101,6 +1104,16 @@ namespace ts {
11011104
elementTypes: NodeArray<TypeNode>;
11021105
}
11031106

1107+
export interface OptionalTypeNode extends TypeNode {
1108+
kind: SyntaxKind.OptionalType;
1109+
type: TypeNode;
1110+
}
1111+
1112+
export interface RestTypeNode extends TypeNode {
1113+
kind: SyntaxKind.RestType;
1114+
type: TypeNode;
1115+
}
1116+
11041117
export type UnionOrIntersectionTypeNode = UnionTypeNode | IntersectionTypeNode;
11051118

11061119
export interface UnionTypeNode extends TypeNode {
@@ -1288,6 +1301,12 @@ namespace ts {
12881301
expression?: Expression;
12891302
}
12901303

1304+
export interface SyntheticExpression extends Expression {
1305+
kind: SyntaxKind.SyntheticExpression;
1306+
isSpread: boolean;
1307+
type: Type;
1308+
}
1309+
12911310
// see: https://tc39.github.io/ecma262/#prod-ExponentiationExpression
12921311
export type ExponentiationOperator
12931312
= SyntaxKind.AsteriskAsteriskToken
@@ -3521,14 +3540,15 @@ namespace ts {
35213540
ContainsPrivate = 1 << 8, // Synthetic property with private constituent(s)
35223541
ContainsStatic = 1 << 9, // Synthetic property with static constituent(s)
35233542
Late = 1 << 10, // Late-bound symbol for a computed property with a dynamic name
3524-
ReverseMapped = 1 << 11, // property of reverse-inferred homomorphic mapped type.
3543+
ReverseMapped = 1 << 11, // Property of reverse-inferred homomorphic mapped type
3544+
OptionalParameter = 1 << 12, // Optional parameter
3545+
RestParameter = 1 << 13, // Rest parameter
35253546
Synthetic = SyntheticProperty | SyntheticMethod
35263547
}
35273548

35283549
/* @internal */
35293550
export interface TransientSymbol extends Symbol, SymbolLinks {
35303551
checkFlags: CheckFlags;
3531-
isRestParameter?: boolean;
35323552
}
35333553

35343554
/* @internal */
@@ -3857,6 +3877,16 @@ namespace ts {
38573877
variances?: Variance[]; // Variance of each type parameter
38583878
}
38593879

3880+
export interface TupleType extends GenericType {
3881+
minLength: number;
3882+
hasRestElement: boolean;
3883+
associatedNames?: __String[];
3884+
}
3885+
3886+
export interface TupleTypeReference extends TypeReference {
3887+
target: TupleType;
3888+
}
3889+
38603890
export interface UnionOrIntersectionType extends Type {
38613891
types: Type[]; // Constituent types
38623892
/* @internal */

src/compiler/visitor.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,17 @@ namespace ts {
372372
visitNode((<ArrayTypeNode>node).elementType, visitor, isTypeNode));
373373

374374
case SyntaxKind.TupleType:
375-
return updateTypleTypeNode((<TupleTypeNode>node),
375+
return updateTupleTypeNode((<TupleTypeNode>node),
376376
nodesVisitor((<TupleTypeNode>node).elementTypes, visitor, isTypeNode));
377377

378+
case SyntaxKind.OptionalType:
379+
return updateOptionalTypeNode((<OptionalTypeNode>node),
380+
visitNode((<OptionalTypeNode>node).type, visitor, isTypeNode));
381+
382+
case SyntaxKind.RestType:
383+
return updateRestTypeNode((<RestTypeNode>node),
384+
visitNode((<RestTypeNode>node).type, visitor, isTypeNode));
385+
378386
case SyntaxKind.UnionType:
379387
return updateUnionTypeNode(<UnionTypeNode>node,
380388
nodesVisitor((<UnionTypeNode>node).types, visitor, isTypeNode));

tests/baselines/reference/TupleType3.errors.txt

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
tests/cases/compiler/anyIndexedAccessArrayNoException.ts(1,12): error TS1122: A tuple type element list cannot be empty.
21
tests/cases/compiler/anyIndexedAccessArrayNoException.ts(1,12): error TS2538: Type '[]' cannot be used as an index type.
32

43

5-
==== tests/cases/compiler/anyIndexedAccessArrayNoException.ts (2 errors) ====
4+
==== tests/cases/compiler/anyIndexedAccessArrayNoException.ts (1 errors) ====
65
var x: any[[]];
76
~~
8-
!!! error TS1122: A tuple type element list cannot be empty.
9-
~~
107
!!! error TS2538: Type '[]' cannot be used as an index type.
118

0 commit comments

Comments
 (0)