End-to-end support for destructuring in variable declarations

This commit is contained in:
Anders Hejlsberg 2014-11-10 13:05:47 -08:00
parent 3d3212b8aa
commit af00c718cc
5 changed files with 245 additions and 141 deletions

View File

@ -340,17 +340,14 @@ module ts {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.VariableDeclaration:
case SyntaxKind.PatternDeclaration:
if ((<Declaration>node).name) {
if (node.flags & NodeFlags.BlockScoped) {
bindBlockScopedVariableDeclaration(<Declaration>node);
}
else {
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes, /*isBlockScopeContainer*/ false);
}
if (isBindingPattern((<Declaration>node).name)) {
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
}
else if (node.flags & NodeFlags.BlockScoped) {
bindBlockScopedVariableDeclaration(<Declaration>node);
}
else {
bindChildren(node, 0, /*isBlockScopeContainer*/ false);
bindDeclaration(<Declaration>node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes, /*isBlockScopeContainer*/ false);
}
break;
case SyntaxKind.Property:

View File

@ -1628,11 +1628,48 @@ module ts {
return classType.typeParameters ? createTypeReference(<GenericType>classType, map(classType.typeParameters, _ => anyType)) : classType;
}
function getTypeOfVariableOrPropertyDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
function getTypeOfPropertyOfType(type: Type, name: string): Type {
var prop = getPropertyOfType(type, name);
return prop ? getTypeOfSymbol(prop) : undefined;
}
function getTypeForBindingElement(declaration: BindingElement): Type {
var pattern = <BindingPattern>declaration.parent;
var parentType = getTypeForVariableDeclaration(<VariableDeclaration>pattern.parent);
if (parentType === unknownType) {
return unknownType;
}
if (!parentType || parentType === anyType) {
if (declaration.initializer) {
return checkExpressionCached(declaration.initializer);
}
return parentType;
}
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
var name = (declaration.propertyName || <Identifier>declaration.name).text;
var type = getTypeOfPropertyOfType(parentType, name) ||
isNumericName(name) && getIndexTypeOfType(parentType, IndexKind.Number) ||
getIndexTypeOfType(parentType, IndexKind.String);
}
else {
var index = indexOf(pattern.elements, declaration);
var type = getTypeOfPropertyOfType(parentType, "" + index) || getIndexTypeOfType(parentType, IndexKind.Number);
}
if (!type) {
// Error: Type {0} has no property {1}
return unknownType;
}
return type;
}
function getTypeForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
// A variable declared in a for..in statement is always of type any
if (declaration.parent.kind === SyntaxKind.ForInStatement) {
return anyType;
}
if (isBindingPattern(declaration.parent)) {
return getTypeForBindingElement(<BindingElement>declaration);
}
// Use type from type annotation if one is present
if (declaration.type) {
return getTypeFromTypeNode(declaration.type);
@ -1654,7 +1691,26 @@ module ts {
}
// Use the type of the initializer expression if one is present
if (declaration.initializer) {
var type = checkAndMarkExpression(declaration.initializer);
return checkExpressionCached(declaration.initializer);
}
// No type specified and nothing can be inferred
return undefined;
}
function getWidenedTypeForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
var type = getTypeForVariableDeclaration(declaration);
if (type) {
return getWidenedType(type);
}
if (declaration.flags & NodeFlags.Rest) {
return createArrayType(anyType);
}
return anyType;
}
function getTypeOfVariableOrPropertyDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
var type = getTypeForVariableDeclaration(declaration);
if (type) {
if (declaration.kind !== SyntaxKind.PropertyAssignment) {
reportErrorsFromWidening(declaration, type);
type = getWidenedType(type);
@ -1670,6 +1726,48 @@ module ts {
return type;
}
//function getTypeOfVariableOrPropertyDeclaration(declaration: VariableDeclaration | PropertyDeclaration): Type {
// // A variable declared in a for..in statement is always of type any
// if (declaration.parent.kind === SyntaxKind.ForInStatement) {
// return anyType;
// }
// // Use type from type annotation if one is present
// if (declaration.type) {
// return getTypeFromTypeNode(declaration.type);
// }
// if (declaration.kind === SyntaxKind.Parameter) {
// var func = <FunctionLikeDeclaration>declaration.parent;
// // For a parameter of a set accessor, use the type of the get accessor if one is present
// if (func.kind === SyntaxKind.SetAccessor) {
// var getter = <AccessorDeclaration>getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
// if (getter) {
// return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
// }
// }
// // Use contextual parameter type if one is available
// var type = getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
// if (type) {
// return type;
// }
// }
// // Use the type of the initializer expression if one is present
// if (declaration.initializer) {
// var type = checkAndMarkExpression(declaration.initializer);
// if (declaration.kind !== SyntaxKind.PropertyAssignment) {
// reportErrorsFromWidening(declaration, type);
// type = getWidenedType(type);
// }
// return type;
// }
// // Rest parameters default to type any[], other parameters default to type any
// var type = declaration.flags & NodeFlags.Rest ? createArrayType(anyType) : anyType;
// // Report implicit any errors unless this is a private property within an ambient declaration
// if (compilerOptions.noImplicitAny && !isPrivateWithinAmbient(declaration) && !(declaration.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(declaration.parent))) {
// reportImplicitAnyError(declaration, type);
// }
// return type;
//}
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
var links = getSymbolLinks(symbol);
if (!links.type) {
@ -4245,6 +4343,10 @@ module ts {
return type;
}
function hasInitializer(node: VariableDeclaration): boolean {
return !!(node.initializer || isBindingPattern(node.parent) && hasInitializer(<VariableDeclaration>node.parent.parent));
}
// Check if a given variable is assigned within a given syntax node
function isVariableAssignedWithin(symbol: Symbol, node: Node): boolean {
var links = getNodeLinks(node);
@ -4273,7 +4375,7 @@ module ts {
}
function isAssignedInVariableDeclaration(node: VariableDeclaration) {
if (getSymbolOfNode(node) === symbol && node.initializer) {
if (!isBindingPattern(node.name) && getSymbolOfNode(node) === symbol && hasInitializer(node)) {
return true;
}
return forEachChild(node, isAssignedIn);
@ -4284,7 +4386,6 @@ module ts {
case SyntaxKind.BinaryExpression:
return isAssignedInBinaryExpression(<BinaryExpression>node);
case SyntaxKind.VariableDeclaration:
case SyntaxKind.PatternDeclaration:
return isAssignedInVariableDeclaration(<VariableDeclaration>node);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
@ -5743,7 +5844,7 @@ module ts {
function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type {
var contextualSignature = getContextualSignature(func);
if (func.body.kind !== SyntaxKind.FunctionBlock) {
var type = checkAndMarkExpression(func.body, contextualMapper);
var type = checkExpressionCached(func.body, contextualMapper);
}
else {
// Aggregate the types of expressions within all the return statements.
@ -5772,7 +5873,7 @@ module ts {
forEachReturnStatement(body, returnStatement => {
var expr = returnStatement.expression;
if (expr) {
var type = checkAndMarkExpression(expr, contextualMapper);
var type = checkExpressionCached(expr, contextualMapper);
if (!contains(aggregatedTypes, type)) {
aggregatedTypes.push(type);
}
@ -6225,10 +6326,12 @@ module ts {
return result;
}
function checkAndMarkExpression(node: Expression, contextualMapper?: TypeMapper): Type {
var result = checkExpression(node, contextualMapper);
getNodeLinks(node).flags |= NodeCheckFlags.TypeChecked;
return result;
function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type {
var links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = checkExpression(node, contextualMapper);
}
return links.resolvedType;
}
// Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When
@ -7221,53 +7324,40 @@ module ts {
}
}
function isBindingPattern(name: DeclarationName) {
return name.kind === SyntaxKind.ArrayBindingPattern || name.kind === SyntaxKind.ObjectBindingPattern;
}
// TODO(andersh): Support destructuring
function checkVariableDeclaration(node: VariableDeclaration | PropertyDeclaration) {
if (isBindingPattern(node.name)) {
forEach((<BindingPattern>node.name).elements, e => {
if (e.kind === SyntaxKind.VariableDeclaration) {
checkVariableDeclaration(e);
}
});
if (node.initializer) {
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableDeclaration(node), node, /*headMessage*/ undefined);
}
return;
}
checkSourceElement(node.type);
checkExportsOnMergedDeclarations(node);
if (fullTypeCheck) {
var symbol = getSymbolOfNode(node);
var typeOfValueDeclaration = getTypeOfVariableOrParameterOrProperty(symbol);
var type: Type;
var useTypeFromValueDeclaration = node === symbol.valueDeclaration;
if (useTypeFromValueDeclaration) {
type = typeOfValueDeclaration;
}
else {
type = getTypeOfVariableOrPropertyDeclaration(node);
}
var symbol = getSymbolOfNode(node);
var type = getTypeOfVariableOrParameterOrProperty(symbol);
if (node === symbol.valueDeclaration) {
if (node.initializer) {
if (!(getNodeLinks(node.initializer).flags & NodeCheckFlags.TypeChecked)) {
// Use default messages
checkTypeAssignableTo(checkAndMarkExpression(node.initializer), type, node, /*headMessage*/ undefined);
}
//TODO(jfreeman): Check that it is not a computed property
checkCollisionWithConstDeclarations(<VariableDeclaration>node);
}
checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
if (!useTypeFromValueDeclaration) {
// TypeScript 1.0 spec (April 2014): 5.1
// Multiple declarations for the same variable name in the same declaration space are permitted,
// provided that each declaration associates the same type with the variable.
if (typeOfValueDeclaration !== unknownType && type !== unknownType && !isTypeIdenticalTo(typeOfValueDeclaration, type)) {
error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(typeOfValueDeclaration), typeToString(type));
}
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
}
}
else {
var declarationType = getWidenedTypeForVariableDeclaration(node);
if (type !== unknownType && declarationType !== unknownType && !isTypeIdenticalTo(type, declarationType)) {
error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(type), typeToString(declarationType));
}
if (node.initializer) {
checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, node, /*headMessage*/ undefined);
}
}
checkExportsOnMergedDeclarations(node);
checkCollisionWithConstDeclarations(<VariableDeclaration>node);
checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithRequireExportsInGeneratedCode(node, node.name);
}
function checkVariableStatement(node: VariableStatement) {
@ -7345,34 +7435,28 @@ module ts {
// TODO: Check that target label is valid
}
function isGetAccessorWithAnnotatatedSetAccessor(node: FunctionLikeDeclaration) {
return !!(node.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(<AccessorDeclaration>getDeclarationOfKind(node.symbol, SyntaxKind.SetAccessor)));
}
function checkReturnStatement(node: ReturnStatement) {
if (node.expression && !(getNodeLinks(node.expression).flags & NodeCheckFlags.TypeChecked)) {
if (node.expression) {
var func = getContainingFunction(node);
if (func) {
var returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func));
var exprType = checkExpressionCached(node.expression);
if (func.kind === SyntaxKind.SetAccessor) {
if (node.expression) {
error(node.expression, Diagnostics.Setters_cannot_return_a_value);
}
error(node.expression, Diagnostics.Setters_cannot_return_a_value);
}
else {
var returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func));
// do assignability check only if we short circuited in determining return type
// - function has explicit type annotation
// - function is getter with no type annotation and setter parameter type is used
// - function is a constructor (will be special cased below)
var checkAssignability =
func.type ||
(func.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(<AccessorDeclaration>getDeclarationOfKind(func.symbol, SyntaxKind.SetAccessor)));
if (checkAssignability) {
checkTypeAssignableTo(checkExpression(node.expression), returnType, node.expression, /*headMessage*/ undefined);
}
else if (func.kind == SyntaxKind.Constructor) {
// constructor doesn't have explicit return type annotation and yet its return type is known - declaring type
// handle constructors and issue specialized error message for them.
if (!isTypeAssignableTo(checkExpression(node.expression), returnType)) {
if (func.kind === SyntaxKind.Constructor) {
if (!isTypeAssignableTo(exprType, returnType)) {
error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class);
}
}
else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func)) {
checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined);
}
}
}
}
@ -8201,7 +8285,6 @@ module ts {
case SyntaxKind.Property:
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
case SyntaxKind.PatternDeclaration:
case SyntaxKind.ArrayLiteral:
case SyntaxKind.ObjectLiteral:
case SyntaxKind.PropertyAssignment:

View File

@ -990,6 +990,18 @@ module ts {
}
}
function emitObjectBindingPattern(node: BindingPattern) {
write("{ ");
emitCommaList(node.elements, /*includeTrailingComma*/ true);
write(" }");
}
function emitArrayBindingPattern(node: BindingPattern) {
write("[");
emitCommaList(node.elements, /*includeTrailingComma*/ true);
write("]");
}
function emitArrayLiteral(node: ArrayLiteral) {
if (node.flags & NodeFlags.MultiLine) {
write("[");
@ -1437,7 +1449,16 @@ module ts {
function emitVariableDeclaration(node: VariableDeclaration) {
emitLeadingComments(node);
emitModuleMemberName(node);
if (node.propertyName) {
emit(node.propertyName);
write(": ");
}
if (node.name.kind === SyntaxKind.Identifier) {
emitModuleMemberName(node);
}
else {
emit(node.name);
}
emitOptional(" = ", node.initializer);
emitTrailingComments(node);
}
@ -2207,11 +2228,9 @@ module ts {
if (!node) {
return;
}
if (node.flags & NodeFlags.Ambient) {
return emitPinnedOrTripleSlashComments(node);
}
switch (node.kind) {
case SyntaxKind.Identifier:
return emitIdentifier(<Identifier>node);
@ -2244,6 +2263,10 @@ module ts {
return emitTemplateSpan(<TemplateSpan>node);
case SyntaxKind.QualifiedName:
return emitPropertyAccess(<QualifiedName>node);
case SyntaxKind.ObjectBindingPattern:
return emitObjectBindingPattern(<BindingPattern>node);
case SyntaxKind.ArrayBindingPattern:
return emitArrayBindingPattern(<BindingPattern>node);
case SyntaxKind.ArrayLiteral:
return emitArrayLiteral(<ArrayLiteral>node);
case SyntaxKind.ObjectLiteral:

View File

@ -236,11 +236,7 @@ module ts {
return child((<ParenTypeNode>node).type);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return children((<BindingPattern>node).declarations);
case SyntaxKind.PatternDeclaration:
return child((<PatternDeclaration>node).propertyName) ||
child((<PatternDeclaration>node).name) ||
child((<PatternDeclaration>node).initializer);
return children((<BindingPattern>node).elements);
case SyntaxKind.ArrayLiteral:
return children((<ArrayLiteral>node).elements);
case SyntaxKind.ObjectLiteral:
@ -334,7 +330,8 @@ module ts {
return child((<CatchBlock>node).variable) ||
children((<CatchBlock>node).statements);
case SyntaxKind.VariableDeclaration:
return child((<VariableDeclaration>node).name) ||
return child((<VariableDeclaration>node).propertyName) ||
child((<VariableDeclaration>node).name) ||
child((<VariableDeclaration>node).type) ||
child((<VariableDeclaration>node).initializer);
case SyntaxKind.ClassDeclaration:
@ -421,11 +418,11 @@ module ts {
return false;
}
export function getContainingFunction(node: Node): SignatureDeclaration {
export function getContainingFunction(node: Node): FunctionLikeDeclaration {
while (true) {
node = node.parent;
if (!node || isAnyFunction(node)) {
return <SignatureDeclaration>node;
return <FunctionLikeDeclaration>node;
}
}
}
@ -518,7 +515,6 @@ module ts {
case SyntaxKind.Property:
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.PatternDeclaration:
return (<VariableDeclaration>parent).initializer === node;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
@ -565,6 +561,10 @@ module ts {
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
}
export function isBindingPattern(node: Node) {
return node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern;
}
export function isInAmbientContext(node: Node): boolean {
while (node) {
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
@ -573,7 +573,6 @@ module ts {
return false;
}
export function isDeclaration(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.TypeParameter:
@ -676,26 +675,26 @@ module ts {
}
enum ParsingContext {
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
BlockStatements, // Statements in block
SwitchClauses, // Clauses in switch statement
SwitchClauseStatements, // Statements in switch clause
TypeMembers, // Members in interface or type literal
ClassMembers, // Members in class declaration
EnumMembers, // Members in enum declaration
BaseTypeReferences, // Type references in extends or implements clause
VariableDeclarations, // Variable declarations in variable statement
ObjectBindingDeclarations, // Binding elements in object binding list
ArrayBindingDeclarations, // Binding elements in array binding list
ArgumentExpressions, // Expressions in argument list
ObjectLiteralMembers, // Members in object literal
ArrayLiteralMembers, // Members in array literal
Parameters, // Parameters in parameter list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list
Count // Number of parsing contexts
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
BlockStatements, // Statements in block
SwitchClauses, // Clauses in switch statement
SwitchClauseStatements, // Statements in switch clause
TypeMembers, // Members in interface or type literal
ClassMembers, // Members in class declaration
EnumMembers, // Members in enum declaration
BaseTypeReferences, // Type references in extends or implements clause
VariableDeclarations, // Variable declarations in variable statement
ObjectBindingElements, // Binding elements in object binding list
ArrayBindingElements, // Binding elements in array binding list
ArgumentExpressions, // Expressions in argument list
ObjectLiteralMembers, // Members in object literal
ArrayLiteralMembers, // Members in array literal
Parameters, // Parameters in parameter list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list
Count // Number of parsing contexts
}
const enum Tristate {
@ -716,8 +715,8 @@ module ts {
case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected;
case ParsingContext.BaseTypeReferences: return Diagnostics.Type_reference_expected;
case ParsingContext.VariableDeclarations: return Diagnostics.Variable_declaration_expected;
case ParsingContext.ObjectBindingDeclarations: return Diagnostics.Property_destructuring_pattern_expected;
case ParsingContext.ArrayBindingDeclarations: return Diagnostics.Array_element_destructuring_pattern_expected;
case ParsingContext.ObjectBindingElements: return Diagnostics.Property_destructuring_pattern_expected;
case ParsingContext.ArrayBindingElements: return Diagnostics.Array_element_destructuring_pattern_expected;
case ParsingContext.ArgumentExpressions: return Diagnostics.Argument_expression_expected;
case ParsingContext.ObjectLiteralMembers: return Diagnostics.Property_assignment_expected;
case ParsingContext.ArrayLiteralMembers: return Diagnostics.Expression_or_comma_expected;
@ -1191,9 +1190,10 @@ module ts {
case ParsingContext.BaseTypeReferences:
return isIdentifier() && ((token !== SyntaxKind.ExtendsKeyword && token !== SyntaxKind.ImplementsKeyword) || !lookAhead(() => (nextToken(), isIdentifier())));
case ParsingContext.VariableDeclarations:
case ParsingContext.ObjectBindingDeclarations:
case ParsingContext.ArrayBindingDeclarations:
case ParsingContext.ObjectBindingElements:
return isIdentifierOrPattern();
case ParsingContext.ArrayBindingElements:
return token === SyntaxKind.CommaToken || isIdentifierOrPattern();
case ParsingContext.TypeParameters:
return isIdentifier();
case ParsingContext.ArgumentExpressions:
@ -1225,7 +1225,7 @@ module ts {
case ParsingContext.ClassMembers:
case ParsingContext.EnumMembers:
case ParsingContext.ObjectLiteralMembers:
case ParsingContext.ObjectBindingDeclarations:
case ParsingContext.ObjectBindingElements:
return token === SyntaxKind.CloseBraceToken;
case ParsingContext.SwitchClauseStatements:
return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword;
@ -1241,7 +1241,7 @@ module ts {
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken;
case ParsingContext.ArrayLiteralMembers:
case ParsingContext.TupleElementTypes:
case ParsingContext.ArrayBindingDeclarations:
case ParsingContext.ArrayBindingElements:
return token === SyntaxKind.CloseBracketToken;
case ParsingContext.Parameters:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
@ -3389,10 +3389,13 @@ module ts {
// DECLARATIONS
function parseBindingDeclaration(flags: NodeFlags, context: ParsingContext): PatternDeclaration {
var node = <PatternDeclaration>createNode(SyntaxKind.PatternDeclaration);
function parseBindingElement(kind: SyntaxKind, flags: NodeFlags, context: ParsingContext): BindingElement {
if (context === ParsingContext.ArrayBindingElements && token === SyntaxKind.CommaToken) {
return <BindingElement>createNode(SyntaxKind.OmittedExpression);
}
var node = <BindingElement>createNode(kind);
node.flags = flags;
if (context === ParsingContext.ObjectBindingDeclarations) {
if (context === ParsingContext.ObjectBindingElements) {
var id = parseIdentifier();
if (parseOptional(SyntaxKind.ColonToken)) {
node.propertyName = id;
@ -3405,18 +3408,19 @@ module ts {
else {
node.name = parseIdentifierOrPattern(flags);
}
node.initializer = parseInitializer(/*inParameter*/ false);
return finishNode(node);
}
function parseBindingList(flags: NodeFlags, context: ParsingContext): NodeArray<PatternDeclaration> {
return parseDelimitedList(context, () => parseBindingDeclaration(flags, context), /*allowTrailingComma*/ true);
function parseBindingList(flags: NodeFlags, context: ParsingContext): NodeArray<BindingElement> {
return parseDelimitedList(context, () => parseBindingElement(SyntaxKind.VariableDeclaration, flags, context), /*allowTrailingComma*/ true);
}
function parseObjectBindingPattern(flags: NodeFlags): BindingPattern {
var node = <BindingPattern>createNode(SyntaxKind.ObjectBindingPattern);
node.flags = flags;
parseExpected(SyntaxKind.OpenBraceToken);
node.declarations = parseBindingList(flags, ParsingContext.ObjectBindingDeclarations);
node.elements = parseBindingList(flags, ParsingContext.ObjectBindingElements);
parseExpected(SyntaxKind.CloseBraceToken);
return finishNode(node);
}
@ -3425,7 +3429,7 @@ module ts {
var node = <BindingPattern>createNode(SyntaxKind.ArrayBindingPattern);
node.flags = flags;
parseExpected(SyntaxKind.OpenBracketToken);
node.declarations = parseBindingList(flags, ParsingContext.ArrayBindingDeclarations);
node.elements = parseBindingList(flags, ParsingContext.ArrayBindingElements);
parseExpected(SyntaxKind.CloseBracketToken);
return finishNode(node);
}
@ -3441,7 +3445,13 @@ module ts {
if (token === SyntaxKind.OpenBraceToken) {
return parseObjectBindingPattern(flags);
}
return parseIdentifier();
var id = parseIdentifier();
if (isInStrictMode && isEvalOrArgumentsIdentifier(id)) {
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
reportInvalidUseInStrictMode(id);
}
return id;
}
function parseVariableDeclaration(flags: NodeFlags, noIn?: boolean): VariableDeclaration {
@ -3462,11 +3472,6 @@ module ts {
if (!inAmbientContext && !node.initializer && flags & NodeFlags.Const) {
grammarErrorOnNode(node, Diagnostics.const_declarations_must_be_initialized);
}
if (isInStrictMode && isEvalOrArgumentsIdentifier(node.name)) {
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
reportInvalidUseInStrictMode(<Identifier>node.name);
}
return finishNode(node);
}

View File

@ -164,7 +164,6 @@ module ts {
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
PatternDeclaration,
// Expression
ArrayLiteral,
ObjectLiteral,
@ -323,20 +322,17 @@ module ts {
export interface SignatureDeclaration extends Declaration, ParsedSignature { }
export interface VariableDeclaration extends Declaration {
name: Identifier | BindingPattern;
type?: TypeNode;
initializer?: Expression;
propertyName?: Identifier; // Binding property name (in object binding pattern)
name: Identifier | BindingPattern; // Declared variable name
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
export interface BindingPattern extends Node {
declarations: PatternDeclaration[];
elements: NodeArray<BindingElement>;
}
export interface PatternDeclaration extends Declaration {
propertyName?: Identifier; // Binding property name
name: Identifier | BindingPattern; // Declared variable name (pattern = undefined)
initializer?: Expression; // Optional initializer
}
export interface BindingElement extends VariableDeclaration { }
export interface PropertyDeclaration extends Declaration {
type?: TypeNode;
@ -866,7 +862,7 @@ module ts {
Prototype = 0x20000000, // Prototype property (no source representation)
UnionProperty = 0x40000000, // Property in union type
Enum = RegularEnum | ConstEnum,
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,