Merge pull request #1463 from Microsoft/spreadAndRest

ECMAScript 6 spread and rest support
This commit is contained in:
Anders Hejlsberg
2014-12-17 13:01:03 -08:00
25 changed files with 739 additions and 195 deletions

View File

@@ -1674,19 +1674,26 @@ module ts {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
return unknownType;
}
return type;
}
// For an array binding element the specified or inferred type of the parent must be assignable to any[]
if (!isTypeAssignableTo(parentType, anyArrayType)) {
error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType));
return unknownType;
}
// Use specific property type when parent is a tuple or numeric index type when parent is an array
var propName = "" + indexOf(pattern.elements, declaration);
var type = isTupleLikeType(parentType) ? getTypeOfPropertyOfType(parentType, propName) : getIndexTypeOfType(parentType, IndexKind.Number);
if (!type) {
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
return unknownType;
else {
// For an array binding element the specified or inferred type of the parent must be assignable to any[]
if (!isTypeAssignableTo(parentType, anyArrayType)) {
error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType));
return unknownType;
}
if (!declaration.dotDotDotToken) {
// Use specific property type when parent is a tuple or numeric index type when parent is an array
var propName = "" + indexOf(pattern.elements, declaration);
var type = isTupleLikeType(parentType) ? getTypeOfPropertyOfType(parentType, propName) : getIndexTypeOfType(parentType, IndexKind.Number);
if (!type) {
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
return unknownType;
}
}
else {
// Rest element has an array type with the same element type as the parent type
var type = createArrayType(getIndexTypeOfType(parentType, IndexKind.Number));
}
}
return type;
}
@@ -1744,17 +1751,8 @@ module ts {
return anyType;
}
// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
// and without regard to its context (i.e. without regard any type annotation or initializer associated with the
// declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
// and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
// used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
// parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
// the parameter.
function getTypeFromBindingPattern(pattern: BindingPattern): Type {
if (pattern.kind === SyntaxKind.ArrayBindingPattern) {
return createTupleType(map(pattern.elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e)));
}
// Return the type implied by an object binding pattern
function getTypeFromObjectBindingPattern(pattern: BindingPattern): Type {
var members: SymbolTable = {};
forEach(pattern.elements, e => {
var flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
@@ -1766,6 +1764,32 @@ module ts {
return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
}
// Return the type implied by an array binding pattern
function getTypeFromArrayBindingPattern(pattern: BindingPattern): Type {
var hasSpreadElement: boolean = false;
var elementTypes: Type[] = [];
forEach(pattern.elements, e => {
elementTypes.push(e.kind === SyntaxKind.OmittedExpression || e.dotDotDotToken ? anyType : getTypeFromBindingElement(e));
if (e.dotDotDotToken) {
hasSpreadElement = true;
}
});
return !elementTypes.length ? anyArrayType : hasSpreadElement ? createArrayType(getUnionType(elementTypes)) : createTupleType(elementTypes);
}
// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
// and without regard to its context (i.e. without regard any type annotation or initializer associated with the
// declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
// and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
// used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
// parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
// the parameter.
function getTypeFromBindingPattern(pattern: BindingPattern): Type {
return pattern.kind === SyntaxKind.ObjectBindingPattern
? getTypeFromObjectBindingPattern(pattern)
: getTypeFromArrayBindingPattern(pattern);
}
// Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
// specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it
// is a bit more involved. For example:
@@ -4510,6 +4534,7 @@ module ts {
case SyntaxKind.VoidExpression:
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.Block:
case SyntaxKind.VariableStatement:
case SyntaxKind.ExpressionStatement:
@@ -5306,15 +5331,37 @@ module ts {
return false;
}
function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type {
var type = checkExpressionCached(node.expression, contextualMapper);
if (!isTypeAssignableTo(type, anyArrayType)) {
error(node.expression, Diagnostics.Type_0_is_not_an_array_type, typeToString(type));
return unknownType;
}
return type;
}
function checkArrayLiteral(node: ArrayLiteralExpression, contextualMapper?: TypeMapper): Type {
var elements = node.elements;
if (!elements.length) {
return createArrayType(undefinedType);
}
var elementTypes = map(elements, e => checkExpression(e, contextualMapper));
var contextualType = getContextualType(node);
if ((contextualType && contextualTypeIsTupleLikeType(contextualType)) || isAssignmentTarget(node)) {
return createTupleType(elementTypes);
var hasSpreadElement: boolean = false;
var elementTypes: Type[] = [];
forEach(elements, e => {
var type = checkExpression(e, contextualMapper);
if (e.kind === SyntaxKind.SpreadElementExpression) {
elementTypes.push(getIndexTypeOfType(type, IndexKind.Number) || anyType);
hasSpreadElement = true;
}
else {
elementTypes.push(type);
}
});
if (!hasSpreadElement) {
var contextualType = getContextualType(node);
if (contextualType && contextualTypeIsTupleLikeType(contextualType) || isAssignmentTarget(node)) {
return createTupleType(elementTypes);
}
}
return createArrayType(getUnionType(elementTypes));
}
@@ -6715,15 +6762,25 @@ module ts {
for (var i = 0; i < elements.length; i++) {
var e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
var propName = "" + i;
var type = sourceType.flags & TypeFlags.Any ? sourceType :
isTupleLikeType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) :
getIndexTypeOfType(sourceType, IndexKind.Number);
if (type) {
checkDestructuringAssignment(e, type, contextualMapper);
if (e.kind !== SyntaxKind.SpreadElementExpression) {
var propName = "" + i;
var type = sourceType.flags & TypeFlags.Any ? sourceType :
isTupleLikeType(sourceType) ? getTypeOfPropertyOfType(sourceType, propName) :
getIndexTypeOfType(sourceType, IndexKind.Number);
if (type) {
checkDestructuringAssignment(e, type, contextualMapper);
}
else {
error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName);
}
}
else {
error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName);
if (i === elements.length - 1) {
checkReferenceAssignment((<SpreadElementExpression>e).expression, sourceType, contextualMapper);
}
else {
error(e, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
}
}
}
}
@@ -6741,6 +6798,10 @@ module ts {
if (target.kind === SyntaxKind.ArrayLiteralExpression) {
return checkArrayLiteralAssignment(<ArrayLiteralExpression>target, sourceType, contextualMapper);
}
return checkReferenceAssignment(target, sourceType, contextualMapper);
}
function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type {
var targetType = checkExpression(target, contextualMapper);
if (checkReferenceExpression(target, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant)) {
checkTypeAssignableTo(sourceType, targetType, target, /*headMessage*/ undefined);
@@ -7081,6 +7142,8 @@ module ts {
return checkBinaryExpression(<BinaryExpression>node, contextualMapper);
case SyntaxKind.ConditionalExpression:
return checkConditionalExpression(<ConditionalExpression>node, contextualMapper);
case SyntaxKind.SpreadElementExpression:
return checkSpreadElementExpression(<SpreadElementExpression>node, contextualMapper);
case SyntaxKind.OmittedExpression:
return undefinedType;
case SyntaxKind.YieldExpression:
@@ -7987,15 +8050,6 @@ module ts {
// Check variable, parameter, or property declaration
function checkVariableLikeDeclaration(node: VariableLikeDeclaration) {
// Grammar checking
// TODO (yuisu) : Revisit this check once move all grammar checking
if (node.kind === SyntaxKind.BindingElement) {
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
}
else if (node.kind === SyntaxKind.VariableDeclaration) {
checkGrammarVariableDeclaration(<VariableDeclaration>node);
}
checkSourceElement(node.type);
// For a computed property, just check the initializer and exit
if (hasComputedNameButNotSymbol(node)) {
@@ -8051,6 +8105,16 @@ module ts {
}
}
function checkVariableDeclaration(node: VariableDeclaration) {
checkGrammarVariableDeclaration(node);
return checkVariableLikeDeclaration(node);
}
function checkBindingElement(node: BindingElement) {
checkGrammarBindingElement(<BindingElement>node);
return checkVariableLikeDeclaration(node);
}
function checkVariableStatement(node: VariableStatement) {
// Grammar checking
checkGrammarModifiers(node) || checkGrammarVariableDeclarations(node, node.declarations) || checkGrammarForDisallowedLetOrConstStatement(node);
@@ -8094,7 +8158,7 @@ module ts {
// Grammar checking
checkGrammarForStatementInAmbientContext(node) || checkGrammarVariableDeclarations(node, node.declarations);
if (node.declarations) forEach(<VariableLikeDeclaration[]>node.declarations, checkVariableLikeDeclaration);
if (node.declarations) forEach(node.declarations, checkVariableDeclaration);
if (node.initializer) checkExpression(node.initializer);
if (node.condition) checkExpression(node.condition);
if (node.iterator) checkExpression(node.iterator);
@@ -8120,7 +8184,7 @@ module ts {
if (node.declarations) {
if (node.declarations.length >= 1) {
var decl = node.declarations[0];
checkVariableLikeDeclaration(decl);
checkVariableDeclaration(decl);
if (decl.type) {
error(decl, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation);
}
@@ -9092,8 +9156,9 @@ module ts {
case SyntaxKind.TryStatement:
return checkTryStatement(<TryStatement>node);
case SyntaxKind.VariableDeclaration:
return checkVariableDeclaration(<VariableDeclaration>node);
case SyntaxKind.BindingElement:
return checkVariableLikeDeclaration(<VariableLikeDeclaration>node);
return checkBindingElement(<BindingElement>node);
case SyntaxKind.ClassDeclaration:
return checkClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.InterfaceDeclaration:
@@ -9172,6 +9237,7 @@ module ts {
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
case SyntaxKind.VariableStatement:
@@ -10535,6 +10601,22 @@ module ts {
}
}
function checkGrammarBindingElement(node: BindingElement) {
if (node.dotDotDotToken) {
var elements = (<BindingPattern>node.parent).elements;
if (node !== elements[elements.length - 1]) {
return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
}
if (node.initializer) {
// Error on equals token which immediate precedes the initializer
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
}
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
return checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
}
function checkGrammarVariableDeclaration(node: VariableDeclaration) {
if (isInAmbientContext(node)) {
if (isBindingPattern(node.name)) {
@@ -10557,7 +10639,7 @@ module ts {
}
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
return checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
return checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
}
function checkGrammarVariableDeclarations(container: Node, declarations: NodeArray<VariableDeclaration>): boolean {

View File

@@ -144,6 +144,7 @@ module ts {
Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts.", isEarly: true },
An_implementation_cannot_be_declared_in_ambient_contexts: { code: 1184, category: DiagnosticCategory.Error, key: "An implementation cannot be declared in ambient contexts.", isEarly: true },
Merge_conflict_marker_encountered: { code: 1184, category: DiagnosticCategory.Error, key: "Merge conflict marker encountered." },
A_rest_element_cannot_have_an_initializer: { code: 1185, category: DiagnosticCategory.Error, key: "A rest element cannot have an initializer." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
@@ -294,6 +295,7 @@ module ts {
Type_0_has_no_property_1_and_no_string_index_signature: { code: 2459, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}' and no string index signature." },
Type_0_has_no_property_1: { code: 2460, category: DiagnosticCategory.Error, key: "Type '{0}' has no property '{1}'." },
Type_0_is_not_an_array_type: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." },
A_rest_element_must_be_last_in_an_array_destructuring_pattern: { code: 2462, category: DiagnosticCategory.Error, key: "A rest element must be last in an array destructuring pattern" },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },

View File

@@ -665,6 +665,10 @@
"category": "Error",
"code": 1184
},
"A rest element cannot have an initializer.": {
"category": "Error",
"code": 1185
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -1270,6 +1274,10 @@
"category": "Error",
"code": 2461
},
"A rest element must be last in an array destructuring pattern": {
"category": "Error",
"code": 2462
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View File

@@ -1949,35 +1949,58 @@ module ts {
}
}
function emitParenthesized(node: Node, parenthesized: boolean) {
if (parenthesized) {
write("(");
}
emit(node);
if (parenthesized) {
write(")");
}
}
function emitTrailingCommaIfPresent(nodeList: NodeArray<Node>): void {
if (nodeList.hasTrailingComma) {
write(",");
}
}
function emitCommaList(nodes: Node[], count?: number) {
if (!(count >= 0)) {
count = nodes.length;
function emitList(nodes: Node[], start: number, count: number, multiLine: boolean, trailingComma: boolean) {
if (multiLine) {
increaseIndent();
}
if (nodes) {
for (var i = 0; i < count; i++) {
for (var i = 0; i < count; i++) {
if (multiLine) {
if (i) {
write(",");
}
writeLine();
}
else {
if (i) {
write(", ");
}
emit(nodes[i]);
}
emit(nodes[start + i]);
}
if (trailingComma) {
write(",");
}
if (multiLine) {
decreaseIndent();
writeLine();
}
}
function emitCommaList(nodes: Node[]) {
if (nodes) {
emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false);
}
}
function emitMultiLineList(nodes: Node[]) {
if (nodes) {
for (var i = 0; i < nodes.length; i++) {
if (i) {
write(",");
}
writeLine();
emit(nodes[i]);
}
emitList(nodes, 0, nodes.length, /*multiline*/ true, /*trailingComma*/ false);
}
}
@@ -2055,17 +2078,8 @@ module ts {
// "abc" + (1 << 2) + ""
var needsParens = templateSpan.expression.kind !== SyntaxKind.ParenthesizedExpression
&& comparePrecedenceToBinaryPlus(templateSpan.expression) !== Comparison.GreaterThan;
write(" + ");
if (needsParens) {
write("(");
}
emit(templateSpan.expression);
if (needsParens) {
write(")");
}
emitParenthesized(templateSpan.expression, needsParens);
// Only emit if the literal is non-empty.
// The binary '+' operator is left-associative, so the first string concatenation
// with the head will force the result up to this point to be a string.
@@ -2235,59 +2249,118 @@ module ts {
function emitObjectBindingPattern(node: BindingPattern) {
write("{ ");
emitCommaList(node.elements);
emitTrailingCommaIfPresent(node.elements);
var elements = node.elements;
emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma);
write(" }");
}
function emitArrayBindingPattern(node: BindingPattern) {
write("[");
emitCommaList(node.elements);
emitTrailingCommaIfPresent(node.elements);
var elements = node.elements;
emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma);
write("]");
}
function emitArrayLiteral(node: ArrayLiteralExpression) {
if (node.flags & NodeFlags.MultiLine) {
write("[");
increaseIndent();
emitMultiLineList(node.elements);
emitTrailingCommaIfPresent(node.elements);
decreaseIndent();
writeLine();
write("]");
function emitBindingElement(node: BindingElement) {
if (node.propertyName) {
emit(node.propertyName);
write(": ");
}
if (node.dotDotDotToken) {
write("...");
}
if (isBindingPattern(node.name)) {
emit(node.name);
}
else {
emitModuleMemberName(node);
}
emitOptional(" = ", node.initializer);
}
function emitSpreadElementExpression(node: SpreadElementExpression) {
write("...");
emit((<SpreadElementExpression>node).expression);
}
function needsParenthesisForPropertyAccess(node: Expression) {
switch (node.kind) {
case SyntaxKind.Identifier:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.ParenthesizedExpression:
// This list is not exhaustive and only includes those cases that are relevant
// to the check in emitArrayLiteral. More cases can be added as needed.
return false;
}
return true;
}
function emitArrayLiteral(node: ArrayLiteralExpression) {
var elements = node.elements;
var length = elements.length;
if (length === 0) {
write("[]");
return;
}
if (compilerOptions.target >= ScriptTarget.ES6) {
write("[");
emitCommaList(node.elements);
emitTrailingCommaIfPresent(node.elements);
emitList(elements, 0, elements.length, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0,
/*trailingComma*/ elements.hasTrailingComma);
write("]");
return;
}
var pos = 0;
var group = 0;
while (pos < length) {
// Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
if (group === 1) {
write(".concat(");
}
else if (group > 1) {
write(", ");
}
var e = elements[pos];
if (e.kind === SyntaxKind.SpreadElementExpression) {
e = (<SpreadElementExpression>e).expression;
emitParenthesized(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccess(e));
pos++;
}
else {
var i = pos;
while (i < length && elements[i].kind !== SyntaxKind.SpreadElementExpression) {
i++;
}
write("[");
emitList(elements, pos, i - pos, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
/*trailingComma*/ elements.hasTrailingComma);
write("]");
pos = i;
}
group++;
}
if (group > 1) {
write(")");
}
}
function emitObjectLiteral(node: ObjectLiteralExpression) {
if (!node.properties.length) {
write("{}");
}
else if (node.flags & NodeFlags.MultiLine) {
write("{");
increaseIndent();
emitMultiLineList(node.properties);
if (compilerOptions.target >= ScriptTarget.ES5) {
emitTrailingCommaIfPresent(node.properties);
write("{");
var properties = node.properties;
if (properties.length) {
var multiLine = (node.flags & NodeFlags.MultiLine) !== 0;
if (!multiLine) {
write(" ");
}
decreaseIndent();
writeLine();
write("}");
}
else {
write("{ ");
emitCommaList(node.properties);
if (compilerOptions.target >= ScriptTarget.ES5) {
emitTrailingCommaIfPresent(node.properties);
emitList(properties, 0, properties.length, /*multiLine*/ multiLine,
/*trailingComma*/ properties.hasTrailingComma && compilerOptions.target >= ScriptTarget.ES5);
if (!multiLine) {
write(" ");
}
write(" }");
}
write("}");
}
function emitComputedPropertyName(node: ComputedPropertyName) {
@@ -2502,7 +2575,8 @@ module ts {
function emitBinaryExpression(node: BinaryExpression) {
if (node.operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
if (compilerOptions.target < ScriptTarget.ES6 && node.operator === SyntaxKind.EqualsToken &&
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
emitDestructuring(node);
}
else {
@@ -2554,11 +2628,8 @@ module ts {
}
function emitExpressionStatement(node: ExpressionStatement) {
var isArrowExpression = node.expression.kind === SyntaxKind.ArrowFunction;
emitLeadingComments(node);
if (isArrowExpression) write("(");
emit(node.expression);
if (isArrowExpression) write(")");
emitParenthesized(node.expression, /*parenthesized*/ node.expression.kind === SyntaxKind.ArrowFunction);
write(";");
emitTrailingComments(node);
}
@@ -2899,7 +2970,16 @@ module ts {
for (var i = 0; i < elements.length; i++) {
var e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
emitDestructuringAssignment(e, createElementAccess(value, createNumericLiteral(i)));
if (e.kind !== SyntaxKind.SpreadElementExpression) {
emitDestructuringAssignment(e, createElementAccess(value, createNumericLiteral(i)));
}
else {
if (i === elements.length - 1) {
value = ensureIdentifier(value);
emitAssignment(<Identifier>(<SpreadElementExpression>e).expression, value);
write(".slice(" + i + ")");
}
}
}
}
}
@@ -2965,8 +3045,17 @@ module ts {
emitBindingElement(element, createPropertyAccess(value, propName));
}
else if (element.kind !== SyntaxKind.OmittedExpression) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, createNumericLiteral(i)));
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, createNumericLiteral(i)));
}
else {
if (i === elements.length - 1) {
value = ensureIdentifier(value);
emitAssignment(<Identifier>element.name, value);
write(".slice(" + i + ")");
}
}
}
}
}
@@ -2979,7 +3068,13 @@ module ts {
function emitVariableDeclaration(node: VariableDeclaration) {
emitLeadingComments(node);
if (isBindingPattern(node.name)) {
emitDestructuring(node);
if (compilerOptions.target < ScriptTarget.ES6) {
emitDestructuring(node);
}
else {
emit(node.name);
emitOptional(" = ", node.initializer);
}
}
else {
emitModuleMemberName(node);
@@ -3008,57 +3103,61 @@ module ts {
function emitParameter(node: ParameterDeclaration) {
emitLeadingComments(node);
if (isBindingPattern(node.name)) {
var name = createTempVariable(node);
if (!tempParameters) {
tempParameters = [];
if (compilerOptions.target < ScriptTarget.ES6) {
if (isBindingPattern(node.name)) {
var name = createTempVariable(node);
if (!tempParameters) {
tempParameters = [];
}
tempParameters.push(name);
emit(name);
}
else {
emit(node.name);
}
tempParameters.push(name);
emit(name);
}
else {
if (node.dotDotDotToken) {
write("...");
}
emit(node.name);
emitOptional(" = ", node.initializer);
}
// TODO(andersh): Enable ES6 code generation below
//if (node.propertyName) {
// emit(node.propertyName);
// write(": ");
//}
//emit(node.name);
//emitOptional(" = ", node.initializer);
emitTrailingComments(node);
}
function emitDefaultValueAssignments(node: FunctionLikeDeclaration) {
var tempIndex = 0;
forEach(node.parameters, p => {
if (isBindingPattern(p.name)) {
writeLine();
write("var ");
emitDestructuring(p, tempParameters[tempIndex]);
write(";");
tempIndex++;
}
else if (p.initializer) {
writeLine();
emitStart(p);
write("if (");
emitNode(p.name);
write(" === void 0)");
emitEnd(p);
write(" { ");
emitStart(p);
emitNode(p.name);
write(" = ");
emitNode(p.initializer);
emitEnd(p);
write("; }");
}
});
if (compilerOptions.target < ScriptTarget.ES6) {
var tempIndex = 0;
forEach(node.parameters, p => {
if (isBindingPattern(p.name)) {
writeLine();
write("var ");
emitDestructuring(p, tempParameters[tempIndex]);
write(";");
tempIndex++;
}
else if (p.initializer) {
writeLine();
emitStart(p);
write("if (");
emitNode(p.name);
write(" === void 0)");
emitEnd(p);
write(" { ");
emitStart(p);
emitNode(p.name);
write(" = ");
emitNode(p.initializer);
emitEnd(p);
write("; }");
}
});
}
}
function emitRestParameter(node: FunctionLikeDeclaration) {
if (hasRestParameters(node)) {
if (compilerOptions.target < ScriptTarget.ES6 && hasRestParameters(node)) {
var restIndex = node.parameters.length - 1;
var restParam = node.parameters[restIndex];
var tempName = createTempVariable(node, /*forLoopVariable*/ true).text;
@@ -3136,7 +3235,9 @@ module ts {
increaseIndent();
write("(");
if (node) {
emitCommaList(node.parameters, node.parameters.length - (hasRestParameters(node) ? 1 : 0));
var parameters = node.parameters;
var omitCount = compilerOptions.target < ScriptTarget.ES6 && hasRestParameters(node) ? 1 : 0;
emitList(parameters, 0, parameters.length - omitCount, /*multiLine*/ false, /*trailingComma*/ false);
}
write(")");
decreaseIndent();
@@ -3723,17 +3824,18 @@ module ts {
increaseIndent();
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);
var exportName = resolver.getExportAssignmentName(node);
if (exportName) {
writeLine();
var exportAssignement = getFirstExportAssignment(node);
emitStart(exportAssignement);
var exportAssignment = getFirstExportAssignment(node);
emitStart(exportAssignment);
write("return ");
emitStart(exportAssignement.exportName);
emitStart(exportAssignment.exportName);
write(exportName);
emitEnd(exportAssignement.exportName);
emitEnd(exportAssignment.exportName);
write(";");
emitEnd(exportAssignement);
emitEnd(exportAssignment);
}
decreaseIndent();
writeLine();
@@ -3743,17 +3845,18 @@ module ts {
function emitCommonJSModule(node: SourceFile, startIndex: number) {
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);
var exportName = resolver.getExportAssignmentName(node);
if (exportName) {
writeLine();
var exportAssignement = getFirstExportAssignment(node);
emitStart(exportAssignement);
var exportAssignment = getFirstExportAssignment(node);
emitStart(exportAssignment);
write("module.exports = ");
emitStart(exportAssignement.exportName);
emitStart(exportAssignment.exportName);
write(exportName);
emitEnd(exportAssignement.exportName);
emitEnd(exportAssignment.exportName);
write(";");
emitEnd(exportAssignement);
emitEnd(exportAssignment);
}
}
@@ -3809,6 +3912,7 @@ module ts {
else {
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);
}
emitLeadingComments(node.endOfFileToken);
@@ -3861,6 +3965,8 @@ module ts {
return emitObjectBindingPattern(<BindingPattern>node);
case SyntaxKind.ArrayBindingPattern:
return emitArrayBindingPattern(<BindingPattern>node);
case SyntaxKind.BindingElement:
return emitBindingElement(<BindingElement>node);
case SyntaxKind.ArrayLiteralExpression:
return emitArrayLiteral(<ArrayLiteralExpression>node);
case SyntaxKind.ObjectLiteralExpression:
@@ -3903,6 +4009,8 @@ module ts {
return emitBinaryExpression(<BinaryExpression>node);
case SyntaxKind.ConditionalExpression:
return emitConditionalExpression(<ConditionalExpression>node);
case SyntaxKind.SpreadElementExpression:
return emitSpreadElementExpression(<SpreadElementExpression>node);
case SyntaxKind.OmittedExpression:
return;
case SyntaxKind.Block:

View File

@@ -151,6 +151,8 @@ module ts {
return child((<ConditionalExpression>node).condition) ||
child((<ConditionalExpression>node).whenTrue) ||
child((<ConditionalExpression>node).whenFalse);
case SyntaxKind.SpreadElementExpression:
return child((<SpreadElementExpression>node).expression);
case SyntaxKind.Block:
case SyntaxKind.TryBlock:
case SyntaxKind.FinallyBlock:
@@ -1005,13 +1007,13 @@ module ts {
case ParsingContext.VariableDeclarations:
return isIdentifierOrPattern();
case ParsingContext.ArrayBindingElements:
return token === SyntaxKind.CommaToken || isIdentifierOrPattern();
return token === SyntaxKind.CommaToken || token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern();
case ParsingContext.TypeParameters:
return isIdentifier();
case ParsingContext.ArgumentExpressions:
return token === SyntaxKind.CommaToken || isStartOfExpression();
case ParsingContext.ArrayLiteralMembers:
return token === SyntaxKind.CommaToken || isStartOfExpression();
return token === SyntaxKind.CommaToken || token === SyntaxKind.DotDotDotToken || isStartOfExpression();
case ParsingContext.Parameters:
return isStartOfParameter();
case ParsingContext.TypeArguments:
@@ -2777,8 +2779,15 @@ module ts {
: parseAssignmentExpressionOrHigher();
}
function parseSpreadElement(): Expression {
var node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
parseExpected(SyntaxKind.DotDotDotToken);
node.expression = parseAssignmentExpressionOrHigher();
return finishNode(node);
}
function parseArrayLiteralElement(): Expression {
return parseAssignmentExpressionOrOmittedExpression();
return token === SyntaxKind.DotDotDotToken ? parseSpreadElement() : parseAssignmentExpressionOrOmittedExpression();
}
function parseArgumentExpression(): Expression {
@@ -3281,8 +3290,8 @@ module ts {
if (token === SyntaxKind.CommaToken) {
return <BindingElement>createNode(SyntaxKind.OmittedExpression);
}
var node = <BindingElement>createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
node.name = parseIdentifierOrPattern();
node.initializer = parseInitializer(/*inParameter*/ false);
return finishNode(node);
@@ -3290,7 +3299,6 @@ module ts {
function parseObjectBindingElement(): BindingElement {
var node = <BindingElement>createNode(SyntaxKind.BindingElement);
// TODO(andersh): Handle computed properties
var id = parsePropertyName();
if (id.kind === SyntaxKind.Identifier && token !== SyntaxKind.ColonToken) {
@@ -3301,7 +3309,6 @@ module ts {
node.propertyName = <Identifier>id;
node.name = parseIdentifierOrPattern();
}
node.initializer = parseInitializer(/*inParameter*/ false);
return finishNode(node);
}

View File

@@ -196,6 +196,7 @@ module ts {
ConditionalExpression,
TemplateExpression,
YieldExpression,
SpreadElementExpression,
OmittedExpression,
// Misc
TemplateSpan,
@@ -659,7 +660,11 @@ module ts {
export interface ArrayLiteralExpression extends PrimaryExpression {
elements: NodeArray<Expression>;
}
export interface SpreadElementExpression extends Expression {
expression: Expression;
}
// An ObjectLiteralExpression is the declaration node for an anonymous symbol.
export interface ObjectLiteralExpression extends PrimaryExpression, Declaration {
properties: NodeArray<ObjectLiteralElement>;

View File

@@ -415,6 +415,7 @@ module ts {
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.TemplateExpression:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.OmittedExpression:

View File

@@ -133,7 +133,7 @@ module FourSlash {
testOptMetadataNames.outDir, testOptMetadataNames.sourceMap, testOptMetadataNames.sourceRoot]
function convertGlobalOptionsToCompilerOptions(globalOptions: { [idx: string]: string }): ts.CompilerOptions {
var settings: ts.CompilerOptions = {};
var settings: ts.CompilerOptions = { target: ts.ScriptTarget.ES5 };
// Convert all property in globalOptions into ts.CompilationSettings
for (var prop in globalOptions) {
if (globalOptions.hasOwnProperty(prop)) {
@@ -2590,4 +2590,4 @@ module FourSlash {
fileName: fileName
};
}
}
}

View File

@@ -0,0 +1,46 @@
//// [arrayLiteralSpread.ts]
function f0() {
var a = [1, 2, 3];
var a1 = [...a];
var a2 = [1, ...a];
var a3 = [1, 2, ...a];
var a4 = [...a, 1];
var a5 = [...a, 1, 2];
var a6 = [1, 2, ...a, 1, 2];
var a7 = [1, ...a, 2, ...a];
var a8 = [...a, ...a, ...a];
}
function f1() {
var a = [1, 2, 3];
var b = ["hello", ...a, true];
var b: (string | number | boolean)[];
}
function f2() {
var a = [...[...[...[...[...[]]]]]];
var b = [...[...[...[...[...[5]]]]]];
}
//// [arrayLiteralSpread.js]
function f0() {
var a = [1, 2, 3];
var a1 = a;
var a2 = [1].concat(a);
var a3 = [1, 2].concat(a);
var a4 = a.concat([1]);
var a5 = a.concat([1, 2]);
var a6 = [1, 2].concat(a, [1, 2]);
var a7 = [1].concat(a, [2], a);
var a8 = a.concat(a, a);
}
function f1() {
var a = [1, 2, 3];
var b = ["hello"].concat(a, [true]);
var b;
}
function f2() {
var a = [];
var b = [5];
}

View File

@@ -0,0 +1,90 @@
=== tests/cases/conformance/es6/spread/arrayLiteralSpread.ts ===
function f0() {
>f0 : () => void
var a = [1, 2, 3];
>a : number[]
>[1, 2, 3] : number[]
var a1 = [...a];
>a1 : number[]
>[...a] : number[]
>a : number[]
var a2 = [1, ...a];
>a2 : number[]
>[1, ...a] : number[]
>a : number[]
var a3 = [1, 2, ...a];
>a3 : number[]
>[1, 2, ...a] : number[]
>a : number[]
var a4 = [...a, 1];
>a4 : number[]
>[...a, 1] : number[]
>a : number[]
var a5 = [...a, 1, 2];
>a5 : number[]
>[...a, 1, 2] : number[]
>a : number[]
var a6 = [1, 2, ...a, 1, 2];
>a6 : number[]
>[1, 2, ...a, 1, 2] : number[]
>a : number[]
var a7 = [1, ...a, 2, ...a];
>a7 : number[]
>[1, ...a, 2, ...a] : number[]
>a : number[]
>a : number[]
var a8 = [...a, ...a, ...a];
>a8 : number[]
>[...a, ...a, ...a] : number[]
>a : number[]
>a : number[]
>a : number[]
}
function f1() {
>f1 : () => void
var a = [1, 2, 3];
>a : number[]
>[1, 2, 3] : number[]
var b = ["hello", ...a, true];
>b : (string | number | boolean)[]
>["hello", ...a, true] : (string | number | boolean)[]
>a : number[]
var b: (string | number | boolean)[];
>b : (string | number | boolean)[]
}
function f2() {
>f2 : () => void
var a = [...[...[...[...[...[]]]]]];
>a : any[]
>[...[...[...[...[...[]]]]]] : undefined[]
>[...[...[...[...[]]]]] : undefined[]
>[...[...[...[]]]] : undefined[]
>[...[...[]]] : undefined[]
>[...[]] : undefined[]
>[] : undefined[]
var b = [...[...[...[...[...[5]]]]]];
>b : number[]
>[...[...[...[...[...[5]]]]]] : number[]
>[...[...[...[...[5]]]]] : number[]
>[...[...[...[5]]]] : number[]
>[...[...[5]]] : number[]
>[...[5]] : number[]
>[5] : number[]
}

View File

@@ -176,7 +176,7 @@ tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,9):
f17({ c: true });
f17(f15());
function g4() {
function f18() {
var a: number;
var b: string;
var aa: number[];
@@ -191,7 +191,7 @@ tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,9):
[a = 1, b = "abc"] = [2, "def"];
}
function g5() {
function f19() {
var a, b;
[a, b] = [1, 2];
[a, b] = [b, a];
@@ -199,4 +199,34 @@ tests/cases/conformance/es6/destructuring/declarationsAndAssignments.ts(138,9):
[[a, b] = [1, 2]] = [[2, 3]];
var x = ([a, b] = [1, 2]);
}
function f20() {
var a: number[];
var x: number;
var y: number;
var z: number;
var [...a] = [1, 2, 3];
var [x, ...a] = [1, 2, 3];
var [x, y, ...a] = [1, 2, 3];
var [x, y, z, ...a] = [1, 2, 3];
[...a] = [1, 2, 3];
[x, ...a] = [1, 2, 3];
[x, y, ...a] = [1, 2, 3];
[x, y, z, ...a] = [1, 2, 3];
}
function f21() {
var a: (number | string | boolean)[];
var x: number | string | boolean;
var y: number | string | boolean;
var z: number | string | boolean;
var [...a] = [1, "hello", true];
var [x, ...a] = [1, "hello", true];
var [x, y, ...a] = [1, "hello", true];
var [x, y, z, ...a] = [1, "hello", true];
[...a] = [1, "hello", true];
[x, ...a] = [1, "hello", true];
[x, y, ...a] = [1, "hello", true];
[x, y, z, ...a] = [1, "hello", true];
}

View File

@@ -129,7 +129,7 @@ f17({ a: "hello" });
f17({ c: true });
f17(f15());
function g4() {
function f18() {
var a: number;
var b: string;
var aa: number[];
@@ -140,7 +140,7 @@ function g4() {
[a = 1, b = "abc"] = [2, "def"];
}
function g5() {
function f19() {
var a, b;
[a, b] = [1, 2];
[a, b] = [b, a];
@@ -148,6 +148,36 @@ function g5() {
[[a, b] = [1, 2]] = [[2, 3]];
var x = ([a, b] = [1, 2]);
}
function f20() {
var a: number[];
var x: number;
var y: number;
var z: number;
var [...a] = [1, 2, 3];
var [x, ...a] = [1, 2, 3];
var [x, y, ...a] = [1, 2, 3];
var [x, y, z, ...a] = [1, 2, 3];
[...a] = [1, 2, 3];
[x, ...a] = [1, 2, 3];
[x, y, ...a] = [1, 2, 3];
[x, y, z, ...a] = [1, 2, 3];
}
function f21() {
var a: (number | string | boolean)[];
var x: number | string | boolean;
var y: number | string | boolean;
var z: number | string | boolean;
var [...a] = [1, "hello", true];
var [x, ...a] = [1, "hello", true];
var [x, y, ...a] = [1, "hello", true];
var [x, y, z, ...a] = [1, "hello", true];
[...a] = [1, "hello", true];
[x, ...a] = [1, "hello", true];
[x, y, ...a] = [1, "hello", true];
[x, y, z, ...a] = [1, "hello", true];
}
//// [declarationsAndAssignments.js]
@@ -266,7 +296,7 @@ f17({});
f17({ a: "hello" });
f17({ c: true });
f17(f15());
function g4() {
function f18() {
var a;
var b;
var aa;
@@ -277,7 +307,7 @@ function g4() {
_e = [2, "def"], _f = _e[0], a = _f === void 0 ? 1 : _f, _g = _e[1], b = _g === void 0 ? "abc" : _g;
var _a, _b, _c, _d, _e, _f, _g;
}
function g5() {
function f19() {
var a, b;
_a = [1, 2], a = _a[0], b = _a[1];
_b = [b, a], a = _b[0], b = _b[1];
@@ -286,3 +316,33 @@ function g5() {
var x = (_f = [1, 2], a = _f[0], b = _f[1], _f);
var _a, _b, _c, _d, _e, _f;
}
function f20() {
var a;
var x;
var y;
var z;
var _a = [1, 2, 3], a = _a.slice(0);
var _b = [1, 2, 3], x = _b[0], a = _b.slice(1);
var _c = [1, 2, 3], x = _c[0], y = _c[1], a = _c.slice(2);
var _d = [1, 2, 3], x = _d[0], y = _d[1], z = _d[2], a = _d.slice(3);
_e = [1, 2, 3], a = _e.slice(0);
_f = [1, 2, 3], x = _f[0], a = _f.slice(1);
_g = [1, 2, 3], x = _g[0], y = _g[1], a = _g.slice(2);
_h = [1, 2, 3], x = _h[0], y = _h[1], z = _h[2], a = _h.slice(3);
var _e, _f, _g, _h;
}
function f21() {
var a;
var x;
var y;
var z;
var _a = [1, "hello", true], a = _a.slice(0);
var _b = [1, "hello", true], x = _b[0], a = _b.slice(1);
var _c = [1, "hello", true], x = _c[0], y = _c[1], a = _c.slice(2);
var _d = [1, "hello", true], x = _d[0], y = _d[1], z = _d[2], a = _d.slice(3);
_e = [1, "hello", true], a = _e.slice(0);
_f = [1, "hello", true], x = _f[0], a = _f.slice(1);
_g = [1, "hello", true], x = _g[0], y = _g[1], a = _g.slice(2);
_h = [1, "hello", true], x = _h[0], y = _h[1], z = _h[2], a = _h.slice(3);
var _e, _f, _g, _h;
}

View File

@@ -0,0 +1,12 @@
tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts(1,9): error TS2462: A rest element must be last in an array destructuring pattern
tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts(2,2): error TS2462: A rest element must be last in an array destructuring pattern
==== tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts (2 errors) ====
var [...a, x] = [1, 2, 3]; // Error, rest must be last element
~
!!! error TS2462: A rest element must be last in an array destructuring pattern
[...a, x] = [1, 2, 3]; // Error, rest must be last element
~~~~
!!! error TS2462: A rest element must be last in an array destructuring pattern

View File

@@ -0,0 +1,9 @@
//// [restElementMustBeLast.ts]
var [...a, x] = [1, 2, 3]; // Error, rest must be last element
[...a, x] = [1, 2, 3]; // Error, rest must be last element
//// [restElementMustBeLast.js]
var _a = [1, 2, 3], x = _a[1]; // Error, rest must be last element
_b = [1, 2, 3], x = _b[1]; // Error, rest must be last element
var _b;

View File

@@ -0,0 +1,9 @@
tests/cases/conformance/es6/destructuring/restElementWithInitializer1.ts(2,11): error TS1185: A rest element cannot have an initializer.
==== tests/cases/conformance/es6/destructuring/restElementWithInitializer1.ts (1 errors) ====
var a: number[];
var [...x = a] = a; // Error, rest element cannot have initializer
~
!!! error TS1185: A rest element cannot have an initializer.

View File

@@ -0,0 +1,8 @@
//// [restElementWithInitializer1.ts]
var a: number[];
var [...x = a] = a; // Error, rest element cannot have initializer
//// [restElementWithInitializer1.js]
var a;
var x = a.slice(0); // Error, rest element cannot have initializer

View File

@@ -0,0 +1,10 @@
tests/cases/conformance/es6/destructuring/restElementWithInitializer2.ts(3,5): error TS2364: Invalid left-hand side of assignment expression.
==== tests/cases/conformance/es6/destructuring/restElementWithInitializer2.ts (1 errors) ====
var a: number[];
var x: number[];
[...x = a] = a; // Error, rest element cannot have initializer
~~~~~
!!! error TS2364: Invalid left-hand side of assignment expression.

View File

@@ -0,0 +1,10 @@
//// [restElementWithInitializer2.ts]
var a: number[];
var x: number[];
[...x = a] = a; // Error, rest element cannot have initializer
//// [restElementWithInitializer2.js]
var a;
var x;
x = a = a.slice(0); // Error, rest element cannot have initializer

View File

@@ -23,11 +23,7 @@ var z = foo `${1}${2}${3}`; // any (with error)
//// [taggedTemplateStringsWithOverloadResolution1_ES6.js]
function foo() {
var stuff = [];
for (var _i = 0; _i < arguments.length; _i++) {
stuff[_i - 0] = arguments[_i];
}
function foo(...stuff) {
return undefined;
}
var a = foo([]); // number

View File

@@ -18,20 +18,12 @@ var c = foo2 `${1}`; // number
var d = foo2([], 1); // number
//// [taggedTemplateStringsWithOverloadResolution2_ES6.js]
function foo1() {
var stuff = [];
for (var _i = 0; _i < arguments.length; _i++) {
stuff[_i - 0] = arguments[_i];
}
function foo1(...stuff) {
return undefined;
}
var a = foo1 `${1}`; // string
var b = foo1([], 1); // number
function foo2() {
var stuff = [];
for (var _i = 0; _i < arguments.length; _i++) {
stuff[_i - 0] = arguments[_i];
}
function foo2(...stuff) {
return undefined;
}
var c = foo2 `${1}`; // number

View File

@@ -128,7 +128,7 @@ f17({ a: "hello" });
f17({ c: true });
f17(f15());
function g4() {
function f18() {
var a: number;
var b: string;
var aa: number[];
@@ -139,7 +139,7 @@ function g4() {
[a = 1, b = "abc"] = [2, "def"];
}
function g5() {
function f19() {
var a, b;
[a, b] = [1, 2];
[a, b] = [b, a];
@@ -147,3 +147,33 @@ function g5() {
[[a, b] = [1, 2]] = [[2, 3]];
var x = ([a, b] = [1, 2]);
}
function f20() {
var a: number[];
var x: number;
var y: number;
var z: number;
var [...a] = [1, 2, 3];
var [x, ...a] = [1, 2, 3];
var [x, y, ...a] = [1, 2, 3];
var [x, y, z, ...a] = [1, 2, 3];
[...a] = [1, 2, 3];
[x, ...a] = [1, 2, 3];
[x, y, ...a] = [1, 2, 3];
[x, y, z, ...a] = [1, 2, 3];
}
function f21() {
var a: (number | string | boolean)[];
var x: number | string | boolean;
var y: number | string | boolean;
var z: number | string | boolean;
var [...a] = [1, "hello", true];
var [x, ...a] = [1, "hello", true];
var [x, y, ...a] = [1, "hello", true];
var [x, y, z, ...a] = [1, "hello", true];
[...a] = [1, "hello", true];
[x, ...a] = [1, "hello", true];
[x, y, ...a] = [1, "hello", true];
[x, y, z, ...a] = [1, "hello", true];
}

View File

@@ -0,0 +1,2 @@
var [...a, x] = [1, 2, 3]; // Error, rest must be last element
[...a, x] = [1, 2, 3]; // Error, rest must be last element

View File

@@ -0,0 +1,2 @@
var a: number[];
var [...x = a] = a; // Error, rest element cannot have initializer

View File

@@ -0,0 +1,3 @@
var a: number[];
var x: number[];
[...x = a] = a; // Error, rest element cannot have initializer

View File

@@ -0,0 +1,22 @@
function f0() {
var a = [1, 2, 3];
var a1 = [...a];
var a2 = [1, ...a];
var a3 = [1, 2, ...a];
var a4 = [...a, 1];
var a5 = [...a, 1, 2];
var a6 = [1, 2, ...a, 1, 2];
var a7 = [1, ...a, 2, ...a];
var a8 = [...a, ...a, ...a];
}
function f1() {
var a = [1, 2, 3];
var b = ["hello", ...a, true];
var b: (string | number | boolean)[];
}
function f2() {
var a = [...[...[...[...[...[]]]]]];
var b = [...[...[...[...[...[5]]]]]];
}