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

Tuples in rest parameters and spread expressions #24897

Merged
merged 40 commits into from
Jun 26, 2018
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8cd8edb
Allow generic rest parameters and infer tuples when possible
ahejlsberg Jun 7, 2018
43bfccf
Accept new baselines
ahejlsberg Jun 7, 2018
2e04322
Optional elements in tuple types + empty tuple types + other fixes.
ahejlsberg Jun 9, 2018
346276c
Accept new baselines
ahejlsberg Jun 9, 2018
c69e4e7
Expand rest parameter with tuple types when emitting signatures
ahejlsberg Jun 11, 2018
73e008d
Accept new baselines
ahejlsberg Jun 11, 2018
7aee647
Record parameter names in inferred tuple types
ahejlsberg Jun 11, 2018
9ae9371
Fix lint errors
ahejlsberg Jun 11, 2018
e239f86
Flatten spread expressions of tuple types
ahejlsberg Jun 11, 2018
0b0a91a
Accept new baselines
ahejlsberg Jun 11, 2018
5245642
Accept baseline API changes
ahejlsberg Jun 11, 2018
39099a0
Merge branch 'master' into restTuples
ahejlsberg Jun 12, 2018
dee51ed
Accept baseline changes in APIs
ahejlsberg Jun 12, 2018
f93f6ec
Better algorithm for combined co- and contra-variant inferences.
ahejlsberg Jun 12, 2018
6bdedad
Accept new baselines
ahejlsberg Jun 12, 2018
58d5583
Minor fixes
ahejlsberg Jun 13, 2018
cee75aa
Properly widen type element types in inferred rest parameter types
ahejlsberg Jun 14, 2018
0cc0fad
Add tests
ahejlsberg Jun 14, 2018
09f17bc
Accept new baselines
ahejlsberg Jun 14, 2018
f1efd1d
Parsing and rudimentary checking of tuples with rest elements
ahejlsberg Jun 15, 2018
4f99bc1
Merge branch 'master' into restTuples
ahejlsberg Jun 16, 2018
64aabf2
Accept new baselines
ahejlsberg Jun 16, 2018
82448af
Merge branch 'master' into restTuples
ahejlsberg Jun 16, 2018
3f03a37
Infer union types for rest elements in tuples
ahejlsberg Jun 16, 2018
43bac20
Array literals contextually typed by tuple types with rest elements
ahejlsberg Jun 16, 2018
ae859d6
Update destructuring to support optional and rest elements in tuples
ahejlsberg Jun 22, 2018
c231000
Update tests
ahejlsberg Jun 22, 2018
4037d07
Accept new baselines
ahejlsberg Jun 22, 2018
cffa1dd
Accept new baselines
ahejlsberg Jun 22, 2018
0a94f77
Accept new baselines
ahejlsberg Jun 22, 2018
b0d8c65
Merge branch 'master' into restTuples
ahejlsberg Jun 22, 2018
b650d7d
Fix issue
ahejlsberg Jun 22, 2018
88444fe
Accept new baselines
ahejlsberg Jun 22, 2018
28c9f59
Complete support for rest elements in tuples
ahejlsberg Jun 25, 2018
9cd8ead
Update tests
ahejlsberg Jun 25, 2018
3cc3b49
Accept new baselines
ahejlsberg Jun 25, 2018
d7443f0
Contextual typing by tuple rest elements
ahejlsberg Jun 25, 2018
d869e56
Add tests
ahejlsberg Jun 25, 2018
5ef7e9f
Accept new baselines
ahejlsberg Jun 25, 2018
656ccd8
Revert package.json change
ahejlsberg Jun 26, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@types/minimatch": "latest",
"@types/minimist": "latest",
"@types/mkdirp": "latest",
"@types/mocha": "latest",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any specific reason for this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, I don't know where that came from.

"@types/mocha": "^5.2.2",
"@types/node": "8.5.5",
"@types/q": "latest",
"@types/run-sequence": "latest",
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3606,6 +3606,8 @@ namespace ts {
case SyntaxKind.TypeLiteral:
case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
case SyntaxKind.OptionalType:
case SyntaxKind.RestType:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.ConditionalType:
Expand Down
814 changes: 565 additions & 249 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

24 changes: 20 additions & 4 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,6 @@
"category": "Error",
"code": 1121
},
"A tuple type element list cannot be empty.": {
"category": "Error",
"code": 1122
},
"Variable declaration list cannot be empty.": {
"category": "Error",
"code": 1123
Expand Down Expand Up @@ -847,6 +843,14 @@
"category": "Error",
"code": 1255
},
"A rest element must be last in a tuple type.": {
"category": "Error",
"code": 1256
},
"A required element cannot follow an optional element.": {
"category": "Error",
"code": 1257
},
"'with' statements are not allowed in an async function block.": {
"category": "Error",
"code": 1300
Expand Down Expand Up @@ -2032,6 +2036,18 @@
"category": "Error",
"code": 2571
},
"Rest signatures are incompatible.": {
"category": "Error",
"code": 2572
},
"Property '{0}' is incompatible with rest element type.": {
"category": "Error",
"code": 2573
},
"A rest element type must be an array type.": {
"category": "Error",
"code": 2574
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
Expand Down
12 changes: 10 additions & 2 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,8 @@ namespace ts {
return emitArrayType(<ArrayTypeNode>node);
case SyntaxKind.TupleType:
return emitTupleType(<TupleTypeNode>node);
case SyntaxKind.OptionalType:
return emitOptionalType(<OptionalTypeNode>node);
case SyntaxKind.UnionType:
return emitUnionType(<UnionTypeNode>node);
case SyntaxKind.IntersectionType:
Expand Down Expand Up @@ -695,8 +697,9 @@ namespace ts {
return emitJSDocNonNullableType(node as JSDocNonNullableType);
case SyntaxKind.JSDocOptionalType:
return emitJSDocOptionalType(node as JSDocOptionalType);
case SyntaxKind.RestType:
case SyntaxKind.JSDocVariadicType:
return emitJSDocVariadicType(node as JSDocVariadicType);
return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType);

// Binding patterns
case SyntaxKind.ObjectBindingPattern:
Expand Down Expand Up @@ -1304,7 +1307,7 @@ namespace ts {
writePunctuation("]");
}

function emitJSDocVariadicType(node: JSDocVariadicType) {
function emitRestOrJSDocVariadicType(node: RestTypeNode | JSDocVariadicType) {
write("...");
emit(node.type);
}
Expand All @@ -1315,6 +1318,11 @@ namespace ts {
writePunctuation("]");
}

function emitOptionalType(node: OptionalTypeNode) {
emit(node.type);
write("?");
}

function emitUnionType(node: UnionTypeNode) {
emitList(node, node.types, ListFormat.UnionTypeConstituents);
}
Expand Down
26 changes: 25 additions & 1 deletion src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -745,12 +745,36 @@ namespace ts {
return node;
}

export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: ReadonlyArray<TypeNode>) {
export function updateTupleTypeNode(node: TupleTypeNode, elementTypes: ReadonlyArray<TypeNode>) {
return node.elementTypes !== elementTypes
? updateNode(createTupleTypeNode(elementTypes), node)
: node;
}

export function createOptionalTypeNode(type: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.OptionalType) as OptionalTypeNode;
node.type = parenthesizeArrayTypeMember(type);
return node;
}

export function updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode {
return node.type !== type
? updateNode(createOptionalTypeNode(type), node)
: node;
}

export function createRestTypeNode(type: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.RestType) as RestTypeNode;
node.type = type;
return node;
}

export function updateRestTypeNode(node: RestTypeNode, type: TypeNode): RestTypeNode {
return node.type !== type
? updateNode(createRestTypeNode(type), node)
: node;
}

export function createUnionTypeNode(types: ReadonlyArray<TypeNode>): UnionTypeNode {
return <UnionTypeNode>createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types);
}
Expand Down
38 changes: 25 additions & 13 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,19 +445,17 @@ namespace ts {
case SyntaxKind.JsxClosingElement:
return visitNode(cbNode, (<JsxClosingElement>node).tagName);

case SyntaxKind.OptionalType:
case SyntaxKind.RestType:
case SyntaxKind.JSDocTypeExpression:
return visitNode(cbNode, (<JSDocTypeExpression>node).type);
case SyntaxKind.JSDocNonNullableType:
return visitNode(cbNode, (<JSDocNonNullableType>node).type);
case SyntaxKind.JSDocNullableType:
return visitNode(cbNode, (<JSDocNullableType>node).type);
case SyntaxKind.JSDocOptionalType:
return visitNode(cbNode, (<JSDocOptionalType>node).type);
case SyntaxKind.JSDocVariadicType:
return visitNode(cbNode, (<OptionalTypeNode | RestTypeNode | JSDocTypeExpression | JSDocTypeReferencingNode>node).type);
case SyntaxKind.JSDocFunctionType:
return visitNodes(cbNode, cbNodes, (<JSDocFunctionType>node).parameters) ||
visitNode(cbNode, (<JSDocFunctionType>node).type);
case SyntaxKind.JSDocVariadicType:
return visitNode(cbNode, (<JSDocVariadicType>node).type);
case SyntaxKind.JSDocComment:
return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags);
case SyntaxKind.JSDocParameterTag:
Expand Down Expand Up @@ -2293,7 +2291,7 @@ namespace ts {
function parseJSDocAllType(postFixEquals: boolean): JSDocAllType | JSDocOptionalType {
const result = createNode(SyntaxKind.JSDocAllType) as JSDocAllType;
if (postFixEquals) {
return createJSDocPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType;
return createPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType;
}
else {
nextToken();
Expand Down Expand Up @@ -2371,7 +2369,7 @@ namespace ts {
type = finishNode(variadic);
}
if (token() === SyntaxKind.EqualsToken) {
return createJSDocPostfixType(SyntaxKind.JSDocOptionalType, type);
return createPostfixType(SyntaxKind.JSDocOptionalType, type);
}
return type;
}
Expand Down Expand Up @@ -2779,9 +2777,23 @@ namespace ts {
return finishNode(node);
}

function parseTupleElementType() {
const pos = getNodePos();
if (parseOptional(SyntaxKind.DotDotDotToken)) {
const node = <RestTypeNode>createNode(SyntaxKind.RestType, pos);
node.type = parseType();
return finishNode(node);
}
const type = parseType();
if (!(contextFlags & NodeFlags.JSDoc) && type.kind === SyntaxKind.JSDocNullableType && type.pos === (<JSDocNullableType>type).type.pos) {
type.kind = SyntaxKind.OptionalType;
}
return type;
}

function parseTupleType(): TupleTypeNode {
const node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
return finishNode(node);
}

Expand Down Expand Up @@ -2964,14 +2976,14 @@ namespace ts {
while (!scanner.hasPrecedingLineBreak()) {
switch (token()) {
case SyntaxKind.ExclamationToken:
type = createJSDocPostfixType(SyntaxKind.JSDocNonNullableType, type);
type = createPostfixType(SyntaxKind.JSDocNonNullableType, type);
break;
case SyntaxKind.QuestionToken:
// If not in JSDoc and next token is start of a type we have a conditional type
if (!(contextFlags & NodeFlags.JSDoc) && lookAhead(nextTokenIsStartOfType)) {
return type;
}
type = createJSDocPostfixType(SyntaxKind.JSDocNullableType, type);
type = createPostfixType(SyntaxKind.JSDocNullableType, type);
break;
case SyntaxKind.OpenBracketToken:
parseExpected(SyntaxKind.OpenBracketToken);
Expand All @@ -2996,9 +3008,9 @@ namespace ts {
return type;
}

function createJSDocPostfixType(kind: SyntaxKind, type: TypeNode) {
function createPostfixType(kind: SyntaxKind, type: TypeNode) {
nextToken();
const postfix = createNode(kind, type.pos) as JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
const postfix = createNode(kind, type.pos) as OptionalTypeNode | JSDocOptionalType | JSDocNonNullableType | JSDocNullableType;
postfix.type = type;
return finishNode(postfix);
}
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ namespace ts {

case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
case SyntaxKind.OptionalType:
case SyntaxKind.RestType:
case SyntaxKind.TypeLiteral:
case SyntaxKind.TypePredicate:
case SyntaxKind.TypeParameter:
Expand Down
34 changes: 32 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ namespace ts {
TypeLiteral,
ArrayType,
TupleType,
OptionalType,
RestType,
UnionType,
IntersectionType,
ConditionalType,
Expand Down Expand Up @@ -269,6 +271,7 @@ namespace ts {
AsExpression,
NonNullExpression,
MetaProperty,
SyntheticExpression,

// Misc
TemplateSpan,
Expand Down Expand Up @@ -1101,6 +1104,16 @@ namespace ts {
elementTypes: NodeArray<TypeNode>;
}

export interface OptionalTypeNode extends TypeNode {
kind: SyntaxKind.OptionalType;
type: TypeNode;
}

export interface RestTypeNode extends TypeNode {
kind: SyntaxKind.RestType;
type: TypeNode;
}

export type UnionOrIntersectionTypeNode = UnionTypeNode | IntersectionTypeNode;

export interface UnionTypeNode extends TypeNode {
Expand Down Expand Up @@ -1288,6 +1301,12 @@ namespace ts {
expression?: Expression;
}

export interface SyntheticExpression extends Expression {
kind: SyntaxKind.SyntheticExpression;
isSpread: boolean;
type: Type;
}

// see: https://tc39.github.io/ecma262/#prod-ExponentiationExpression
export type ExponentiationOperator
= SyntaxKind.AsteriskAsteriskToken
Expand Down Expand Up @@ -3520,14 +3539,15 @@ namespace ts {
ContainsPrivate = 1 << 8, // Synthetic property with private constituent(s)
ContainsStatic = 1 << 9, // Synthetic property with static constituent(s)
Late = 1 << 10, // Late-bound symbol for a computed property with a dynamic name
ReverseMapped = 1 << 11, // property of reverse-inferred homomorphic mapped type.
ReverseMapped = 1 << 11, // Property of reverse-inferred homomorphic mapped type
OptionalParameter = 1 << 12, // Optional parameter
RestParameter = 1 << 13, // Rest parameter
Synthetic = SyntheticProperty | SyntheticMethod
}

/* @internal */
export interface TransientSymbol extends Symbol, SymbolLinks {
checkFlags: CheckFlags;
isRestParameter?: boolean;
}

/* @internal */
Expand Down Expand Up @@ -3856,6 +3876,16 @@ namespace ts {
variances?: Variance[]; // Variance of each type parameter
}

export interface TupleType extends GenericType {
minLength: number;
hasRestElement: boolean;
associatedNames?: __String[];
}

export interface TupleTypeReference extends TypeReference {
target: TupleType;
}

export interface UnionOrIntersectionType extends Type {
types: Type[]; // Constituent types
/* @internal */
Expand Down
10 changes: 9 additions & 1 deletion src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,17 @@ namespace ts {
visitNode((<ArrayTypeNode>node).elementType, visitor, isTypeNode));

case SyntaxKind.TupleType:
return updateTypleTypeNode((<TupleTypeNode>node),
return updateTupleTypeNode((<TupleTypeNode>node),
nodesVisitor((<TupleTypeNode>node).elementTypes, visitor, isTypeNode));

case SyntaxKind.OptionalType:
return updateOptionalTypeNode((<OptionalTypeNode>node),
visitNode((<OptionalTypeNode>node).type, visitor, isTypeNode));

case SyntaxKind.RestType:
return updateRestTypeNode((<RestTypeNode>node),
visitNode((<RestTypeNode>node).type, visitor, isTypeNode));

case SyntaxKind.UnionType:
return updateUnionTypeNode(<UnionTypeNode>node,
nodesVisitor((<UnionTypeNode>node).types, visitor, isTypeNode));
Expand Down
7 changes: 0 additions & 7 deletions tests/baselines/reference/TupleType3.errors.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
tests/cases/compiler/anyIndexedAccessArrayNoException.ts(1,12): error TS1122: A tuple type element list cannot be empty.
tests/cases/compiler/anyIndexedAccessArrayNoException.ts(1,12): error TS2538: Type '[]' cannot be used as an index type.


==== tests/cases/compiler/anyIndexedAccessArrayNoException.ts (2 errors) ====
==== tests/cases/compiler/anyIndexedAccessArrayNoException.ts (1 errors) ====
var x: any[[]];
~~
!!! error TS1122: A tuple type element list cannot be empty.
~~
!!! error TS2538: Type '[]' cannot be used as an index type.

Loading