From a975895e4d3e71cca167f5b4a6353831e6defe73 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 5 Oct 2015 13:46:56 -0700 Subject: [PATCH 01/15] parse/check/emit shorthand property assignment in destructuring --- src/compiler/checker.ts | 86 +++++-- src/compiler/diagnosticMessages.json | 4 + src/compiler/emitter.ts | 18 +- src/compiler/parser.ts | 24 +- src/compiler/types.ts | 4 + tests/baselines/reference/for-of48.errors.txt | 6 +- tests/baselines/reference/for-of48.js | 2 +- ...pertyAssignmentsInDestructuring.errors.txt | 164 ++++++++++++ ...thandPropertyAssignmentsInDestructuring.js | 242 ++++++++++++++++++ ...yAssignmentsInDestructuring_ES6.errors.txt | 164 ++++++++++++ ...dPropertyAssignmentsInDestructuring_ES6.js | 213 +++++++++++++++ ...thandPropertyAssignmentsInDestructuring.ts | 118 +++++++++ ...dPropertyAssignmentsInDestructuring_ES6.ts | 118 +++++++++ 13 files changed, 1125 insertions(+), 38 deletions(-) create mode 100644 tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt create mode 100644 tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js create mode 100644 tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt create mode 100644 tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.js create mode 100644 tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts create mode 100644 tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 40db300d310..ece6860e5b2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7313,15 +7313,15 @@ namespace ts { } function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type { + let inDestructuringPattern = isAssignmentTarget(node); // Grammar checking - checkGrammarObjectLiteralExpression(node); + checkGrammarObjectLiteralExpression(node, inDestructuringPattern); let propertiesTable: SymbolTable = {}; let propertiesArray: Symbol[] = []; let contextualType = getContextualType(node); let contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); - let inDestructuringPattern = isAssignmentTarget(node); let typeFlags: TypeFlags = 0; for (let memberDecl of node.properties) { @@ -7345,7 +7345,10 @@ namespace ts { if (inDestructuringPattern) { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. - if (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((memberDecl).initializer)) { + const isOptional = + (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((memberDecl).initializer)) || + (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && (memberDecl).objectAssignmentInitializer); + if (isOptional) { prop.flags |= SymbolFlags.Optional; } } @@ -9902,32 +9905,32 @@ namespace ts { return (symbol.flags & SymbolFlags.ConstEnum) !== 0; } - function checkInstanceOfExpression(node: BinaryExpression, leftType: Type, rightType: Type): Type { + function checkInstanceOfExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { // TypeScript 1.0 spec (April 2014): 4.15.4 // The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type, // and the right operand to be of type Any or a subtype of the 'Function' interface type. // The result is always of the Boolean primitive type. // NOTE: do not raise error if leftType is unknown as related error was already reported if (allConstituentTypesHaveKind(leftType, TypeFlags.Primitive)) { - error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } // NOTE: do not raise error if right is unknown as related error was already reported if (!(isTypeAny(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) { - error(node.right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); + error(right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); } return booleanType; } - function checkInExpression(node: BinaryExpression, leftType: Type, rightType: Type): Type { + function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type { // TypeScript 1.0 spec (April 2014): 4.15.5 // The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type, // and the right operand to be of type Any, an object type, or a type parameter type. // The result is always of the Boolean primitive type. if (!isTypeAnyOrAllConstituentTypesHaveKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) { - error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); + error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_type_any_string_number_or_symbol); } if (!isTypeAnyOrAllConstituentTypesHaveKind(rightType, TypeFlags.ObjectType | TypeFlags.TypeParameter)) { - error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); + error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } return booleanType; } @@ -9944,7 +9947,12 @@ namespace ts { isNumericLiteralName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || getIndexTypeOfType(sourceType, IndexKind.String); if (type) { - checkDestructuringAssignment((p).initializer || name, type); + if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { + checkDestructuringAssignment(p, type); + } + else { + checkDestructuringAssignment((p).initializer || name, type); + } } else { error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(sourceType), declarationNameToString(name)); @@ -10004,7 +10012,19 @@ namespace ts { return sourceType; } - function checkDestructuringAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type { + function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, contextualMapper?: TypeMapper): Type { + let target: Expression; + if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) { + const prop = exprOrAssignment; + if (prop.objectAssignmentInitializer) { + checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, contextualMapper); + } + target = (exprOrAssignment).name; + } + else { + target = exprOrAssignment; + } + if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) { checkBinaryExpression(target, contextualMapper); target = (target).left; @@ -10027,12 +10047,16 @@ namespace ts { } function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) { - let operator = node.operatorToken.kind; - if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { - return checkDestructuringAssignment(node.left, checkExpression(node.right, contextualMapper), contextualMapper); + return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, contextualMapper, node); + } + + function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, contextualMapper?: TypeMapper, errorNode?: Node) { + let operator = operatorToken.kind; + if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) { + return checkDestructuringAssignment(left, checkExpression(right, contextualMapper), contextualMapper); } - let leftType = checkExpression(node.left, contextualMapper); - let rightType = checkExpression(node.right, contextualMapper); + let leftType = checkExpression(left, contextualMapper); + let rightType = checkExpression(right, contextualMapper); switch (operator) { case SyntaxKind.AsteriskToken: case SyntaxKind.AsteriskEqualsToken: @@ -10068,13 +10092,13 @@ namespace ts { // try and return them a helpful suggestion if ((leftType.flags & TypeFlags.Boolean) && (rightType.flags & TypeFlags.Boolean) && - (suggestedOperator = getSuggestedBooleanOperator(node.operatorToken.kind)) !== undefined) { - error(node, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(node.operatorToken.kind), tokenToString(suggestedOperator)); + (suggestedOperator = getSuggestedBooleanOperator(operatorToken.kind)) !== undefined) { + error(errorNode || operatorToken, Diagnostics.The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead, tokenToString(operatorToken.kind), tokenToString(suggestedOperator)); } else { // otherwise just check each operand separately and report errors as normal - let leftOk = checkArithmeticOperandType(node.left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); - let rightOk = checkArithmeticOperandType(node.right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); + let leftOk = checkArithmeticOperandType(left, leftType, Diagnostics.The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); + let rightOk = checkArithmeticOperandType(right, rightType, Diagnostics.The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type); if (leftOk && rightOk) { checkAssignmentOperator(numberType); } @@ -10140,9 +10164,9 @@ namespace ts { } return booleanType; case SyntaxKind.InstanceOfKeyword: - return checkInstanceOfExpression(node, leftType, rightType); + return checkInstanceOfExpression(left, right, leftType, rightType); case SyntaxKind.InKeyword: - return checkInExpression(node, leftType, rightType); + return checkInExpression(left, right, leftType, rightType); case SyntaxKind.AmpersandAmpersandToken: return rightType; case SyntaxKind.BarBarToken: @@ -10157,8 +10181,8 @@ namespace ts { // Return true if there was no error, false if there was an error. function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { let offendingSymbolOperand = - someConstituentTypeHasKind(leftType, TypeFlags.ESSymbol) ? node.left : - someConstituentTypeHasKind(rightType, TypeFlags.ESSymbol) ? node.right : + someConstituentTypeHasKind(leftType, TypeFlags.ESSymbol) ? left : + someConstituentTypeHasKind(rightType, TypeFlags.ESSymbol) ? right : undefined; if (offendingSymbolOperand) { error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); @@ -10192,17 +10216,17 @@ namespace ts { // requires VarExpr to be classified as a reference // A compound assignment furthermore requires VarExpr to be classified as a reference (section 4.1) // and the type of the non - compound operation to be assignable to the type of VarExpr. - let ok = checkReferenceExpression(node.left, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant); + let ok = checkReferenceExpression(left, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant); // Use default messages if (ok) { // to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported - checkTypeAssignableTo(valueType, leftType, node.left, /*headMessage*/ undefined); + checkTypeAssignableTo(valueType, leftType, left, /*headMessage*/ undefined); } } } function reportOperatorError() { - error(node, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, tokenToString(node.operatorToken.kind), typeToString(leftType), typeToString(rightType)); + error(errorNode || operatorToken, Diagnostics.Operator_0_cannot_be_applied_to_types_1_and_2, tokenToString(operatorToken.kind), typeToString(leftType), typeToString(rightType)); } } @@ -15434,7 +15458,7 @@ namespace ts { } } - function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression) { + function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) { let seen: Map = {}; let Property = 1; let GetAccessor = 2; @@ -15450,6 +15474,12 @@ namespace ts { continue; } + if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && (prop).objectAssignmentInitializer) { + // having objectAssignmentInitializer is only valid in ObjectAssignmentPattern + // outside of destructuring it is a syntax error + return grammarErrorOnNode((prop).equalsToken, Diagnostics.can_only_be_used_in_object_literal_properties_inside_destructuring_assignment); + } + // ECMA-262 11.1.5 Object Initialiser // If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true // a.This production is contained in strict code and IsDataDescriptor(previous) is true and diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f6656edb250..a41d5d99005 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -800,6 +800,10 @@ "category": "Error", "code": 1311 }, + "'=' can only be used in object literal properties inside destructuring assignment.": { + "category": "Error", + "code": 1312 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2300 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 71187b20960..2b422d6bfbf 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2311,6 +2311,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(": "); emit(node.name); } + + if (languageVersion >= ScriptTarget.ES6 && node.objectAssignmentInitializer) { + write(" = "); + emit(node.objectAssignmentInitializer); + } } function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { @@ -3574,7 +3579,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi for (let p of properties) { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { let propName = (p).name; - emitDestructuringAssignment((p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName)); + let target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? p : (p).initializer || propName; + emitDestructuringAssignment(target, createPropertyAccessForDestructuringProperty(value, propName)); } } } @@ -3599,8 +3605,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } } - function emitDestructuringAssignment(target: Expression, value: Expression) { - if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) { + function emitDestructuringAssignment(target: Expression | ShorthandPropertyAssignment, value: Expression) { + if (target.kind === SyntaxKind.ShorthandPropertyAssignment) { + if ((target).objectAssignmentInitializer) { + value = createDefaultValueCheck(value, (target).objectAssignmentInitializer); + } + target = (target).name; + } + else if (target.kind === SyntaxKind.BinaryExpression && (target).operatorToken.kind === SyntaxKind.EqualsToken) { value = createDefaultValueCheck(value, (target).right); target = (target).left; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index dcdaec98318..09fa2ba3b82 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -57,11 +57,17 @@ namespace ts { return visitNode(cbNode, (node).name) || visitNode(cbNode, (node).constraint) || visitNode(cbNode, (node).expression); + case SyntaxKind.ShorthandPropertyAssignment: + return visitNodes(cbNodes, node.decorators) || + visitNodes(cbNodes, node.modifiers) || + visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).equalsToken) || + visitNode(cbNode, (node).objectAssignmentInitializer); case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.PropertyAssignment: - case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.VariableDeclaration: case SyntaxKind.BindingElement: return visitNodes(cbNodes, node.decorators) || @@ -3758,11 +3764,23 @@ namespace ts { return parseMethodDeclaration(fullStart, decorators, modifiers, asteriskToken, propertyName, questionToken); } - // Parse to check if it is short-hand property assignment or normal property assignment - if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) { + // check if it is short-hand property assignment or normal property assignment + // NOTE: if token is EqualsToken it is interpreted as CoverInitializedName production + // CoverInitializedName[Yield] : + // IdentifierReference[?Yield] Initializer[In, ?Yield] + // this is necessary because ObjectLiteral productions are also used to cover grammar for ObjectAssignmentPattern + const isShorthandPropertyAssignment = + tokenIsIdentifier && (token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken || token === SyntaxKind.EqualsToken); + + if (isShorthandPropertyAssignment) { let shorthandDeclaration = createNode(SyntaxKind.ShorthandPropertyAssignment, fullStart); shorthandDeclaration.name = propertyName; shorthandDeclaration.questionToken = questionToken; + const equalsToken = parseOptionalToken(SyntaxKind.EqualsToken); + if (equalsToken) { + shorthandDeclaration.equalsToken = equalsToken; + shorthandDeclaration.objectAssignmentInitializer = allowInAnd(parseAssignmentExpressionOrHigher); + } return finishNode(shorthandDeclaration); } else { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 17156aee0f1..c1199870c51 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -562,6 +562,10 @@ namespace ts { export interface ShorthandPropertyAssignment extends ObjectLiteralElement { name: Identifier; questionToken?: Node; + // used when ObjectLiteralExpression is used in ObjectAssignmentPattern + // it is grammar error to appear in actual object initializer + equalsToken?: Node; + objectAssignmentInitializer?: Expression; } // SyntaxKind.VariableDeclaration diff --git a/tests/baselines/reference/for-of48.errors.txt b/tests/baselines/reference/for-of48.errors.txt index f6826e14c61..8a8fd668714 100644 --- a/tests/baselines/reference/for-of48.errors.txt +++ b/tests/baselines/reference/for-of48.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/es6/for-ofStatements/for-of48.ts(4,12): error TS1005: ':' expected. +tests/cases/conformance/es6/for-ofStatements/for-of48.ts(4,10): error TS2322: Type 'boolean' is not assignable to type 'number'. ==== tests/cases/conformance/es6/for-ofStatements/for-of48.ts (1 errors) ==== @@ -6,8 +6,8 @@ tests/cases/conformance/es6/for-ofStatements/for-of48.ts(4,12): error TS1005: ': var array = [{ x: "", y: true }] enum E { x } for ({x, y = E.x} of array) { - ~ -!!! error TS1005: ':' expected. + ~ +!!! error TS2322: Type 'boolean' is not assignable to type 'number'. x; y; } \ No newline at end of file diff --git a/tests/baselines/reference/for-of48.js b/tests/baselines/reference/for-of48.js index 2a5e4e32b94..65e23076fd9 100644 --- a/tests/baselines/reference/for-of48.js +++ b/tests/baselines/reference/for-of48.js @@ -14,7 +14,7 @@ var E; (function (E) { E[E["x"] = 0] = "x"; })(E || (E = {})); -for ({ x, y: = E.x } of array) { +for ({ x, y = E.x } of array) { x; y; } diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt new file mode 100644 index 00000000000..844078cd8f1 --- /dev/null +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt @@ -0,0 +1,164 @@ +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(16,9): error TS2459: Type '{}' has no property 's1' and no string index signature. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(22,9): error TS2459: Type '{}' has no property 's1' and no string index signature. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(40,9): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(46,12): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(72,5): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(77,8): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(82,5): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(82,13): error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. + Types of property 'x' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(87,8): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(87,19): error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. + Types of property 'x' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(113,12): error TS2304: Cannot find name 's'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(113,14): error TS1312: '=' can only be used in object literal properties inside destructuring assignment. + + +==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts (12 errors) ==== + + + (function() { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } + }); + (function() { + var s0; + for ({ s0:s0 = 5 } of [{ s0: 1 }]) { + } + }); + + (function() { + var s1; + for ({ s1 = 5 } of [{}]) { + ~~ +!!! error TS2459: Type '{}' has no property 's1' and no string index signature. + } + }); + + (function() { + var s1; + for ({ s1:s1 = 5 } of [{}]) { + ~~ +!!! error TS2459: Type '{}' has no property 's1' and no string index signature. + } + }); + + (function() { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } + }); + + (function() { + var s2; + for ({ s2:s2 = 5 } of [{ s2: "" }]) { + } + }); + + (function() { + var s3: string; + for ({ s3 = 5 } of [{ s3: "" }]) { + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + }); + + (function() { + var s3: string; + for ({ s3:s3 = 5 } of [{ s3: "" }]) { + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + }); + + (function() { + let y; + ({ y = 5 } = { y: 1 }) + }); + + (function() { + let y; + ({ y:y = 5 } = { y: 1 }) + }); + + (function() { + let y0: number; + ({ y0 = 5 } = { y0: 1 }) + }); + + (function() { + let y0: number; + ({ y0:y0 = 5 } = { y0: 1 }) + }); + + (function() { + let y1: string; + ({ y1 = 5 } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y1: string; + ({ y1:y1 = 5 } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y2: string, y3: { x: string }; + ({ y2 = 5, y3 = { x: 1 } } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~ +!!! error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. +!!! error TS2322: Types of property 'x' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y2: string, y3: { x: string }; + ({ y2:y2 = 5, y3:y3 = { x: 1 } } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~ +!!! error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. +!!! error TS2322: Types of property 'x' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y4: number, y5: { x: number }; + ({ y4 = 5, y5 = { x: 1 } } = {}) + }); + + (function() { + let y4: number, y5: { x: number }; + ({ y4:y4 = 5, y5:y5 = { x: 1 } } = {}) + }); + + + (function() { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); + }); + + + (function() { + let z; + ({ z:z = { x: 5 } } = { z: { x: 1 } }); + }); + + (function() { + let a = { s = 5 }; + ~ +!!! error TS2304: Cannot find name 's'. + ~ +!!! error TS1312: '=' can only be used in object literal properties inside destructuring assignment. + }); + + function foo({a = 4, b = { x: 5 }}) { + } \ No newline at end of file diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js new file mode 100644 index 00000000000..981ee08e20c --- /dev/null +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.js @@ -0,0 +1,242 @@ +//// [shorthandPropertyAssignmentsInDestructuring.ts] + + +(function() { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } +}); +(function() { + var s0; + for ({ s0:s0 = 5 } of [{ s0: 1 }]) { + } +}); + +(function() { + var s1; + for ({ s1 = 5 } of [{}]) { + } +}); + +(function() { + var s1; + for ({ s1:s1 = 5 } of [{}]) { + } +}); + +(function() { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s2; + for ({ s2:s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3:s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + let y; + ({ y = 5 } = { y: 1 }) +}); + +(function() { + let y; + ({ y:y = 5 } = { y: 1 }) +}); + +(function() { + let y0: number; + ({ y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y0: number; + ({ y0:y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y1: string; + ({ y1 = 5 } = {}) +}); + +(function() { + let y1: string; + ({ y1:y1 = 5 } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2 = 5, y3 = { x: 1 } } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2:y2 = 5, y3:y3 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4 = 5, y5 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4:y4 = 5, y5:y5 = { x: 1 } } = {}) +}); + + +(function() { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); +}); + + +(function() { + let z; + ({ z:z = { x: 5 } } = { z: { x: 1 } }); +}); + +(function() { + let a = { s = 5 }; +}); + +function foo({a = 4, b = { x: 5 }}) { +} + +//// [shorthandPropertyAssignmentsInDestructuring.js] +(function () { + var s0; + for (var _i = 0, _a = [{ s0: 1 }]; _i < _a.length; _i++) { + _b = _a[_i].s0, s0 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s0; + for (var _i = 0, _a = [{ s0: 1 }]; _i < _a.length; _i++) { + _b = _a[_i].s0, s0 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s1; + for (var _i = 0, _a = [{}]; _i < _a.length; _i++) { + _b = _a[_i].s1, s1 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s1; + for (var _i = 0, _a = [{}]; _i < _a.length; _i++) { + _b = _a[_i].s1, s1 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s2; + for (var _i = 0, _a = [{ s2: "" }]; _i < _a.length; _i++) { + _b = _a[_i].s2, s2 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s2; + for (var _i = 0, _a = [{ s2: "" }]; _i < _a.length; _i++) { + _b = _a[_i].s2, s2 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s3; + for (var _i = 0, _a = [{ s3: "" }]; _i < _a.length; _i++) { + _b = _a[_i].s3, s3 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var s3; + for (var _i = 0, _a = [{ s3: "" }]; _i < _a.length; _i++) { + _b = _a[_i].s3, s3 = _b === void 0 ? 5 : _b; + } + var _b; +}); +(function () { + var y; + (_a = { y: 1 }, _b = _a.y, y = _b === void 0 ? 5 : _b, _a); + var _a, _b; +}); +(function () { + var y; + (_a = { y: 1 }, _b = _a.y, y = _b === void 0 ? 5 : _b, _a); + var _a, _b; +}); +(function () { + var y0; + (_a = { y0: 1 }, _b = _a.y0, y0 = _b === void 0 ? 5 : _b, _a); + var _a, _b; +}); +(function () { + var y0; + (_a = { y0: 1 }, _b = _a.y0, y0 = _b === void 0 ? 5 : _b, _a); + var _a, _b; +}); +(function () { + var y1; + (_a = {}, _b = _a.y1, y1 = _b === void 0 ? 5 : _b, _a); + var _a, _b; +}); +(function () { + var y1; + (_a = {}, _b = _a.y1, y1 = _b === void 0 ? 5 : _b, _a); + var _a, _b; +}); +(function () { + var y2, y3; + (_a = {}, _b = _a.y2, y2 = _b === void 0 ? 5 : _b, _c = _a.y3, y3 = _c === void 0 ? { x: 1 } : _c, _a); + var _a, _b, _c; +}); +(function () { + var y2, y3; + (_a = {}, _b = _a.y2, y2 = _b === void 0 ? 5 : _b, _c = _a.y3, y3 = _c === void 0 ? { x: 1 } : _c, _a); + var _a, _b, _c; +}); +(function () { + var y4, y5; + (_a = {}, _b = _a.y4, y4 = _b === void 0 ? 5 : _b, _c = _a.y5, y5 = _c === void 0 ? { x: 1 } : _c, _a); + var _a, _b, _c; +}); +(function () { + var y4, y5; + (_a = {}, _b = _a.y4, y4 = _b === void 0 ? 5 : _b, _c = _a.y5, y5 = _c === void 0 ? { x: 1 } : _c, _a); + var _a, _b, _c; +}); +(function () { + var z; + (_a = { z: { x: 1 } }, _b = _a.z, z = _b === void 0 ? { x: 5 } : _b, _a); + var _a, _b; +}); +(function () { + var z; + (_a = { z: { x: 1 } }, _b = _a.z, z = _b === void 0 ? { x: 5 } : _b, _a); + var _a, _b; +}); +(function () { + var a = { s: s }; +}); +function foo(_a) { + var _b = _a.a, a = _b === void 0 ? 4 : _b, _c = _a.b, b = _c === void 0 ? { x: 5 } : _c; +} diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt new file mode 100644 index 00000000000..208a8798c39 --- /dev/null +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt @@ -0,0 +1,164 @@ +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(16,9): error TS2459: Type '{}' has no property 's1' and no string index signature. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(22,9): error TS2459: Type '{}' has no property 's1' and no string index signature. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(40,9): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(46,12): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(72,5): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(77,8): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(82,5): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(82,13): error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. + Types of property 'x' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(87,8): error TS2322: Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(87,19): error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. + Types of property 'x' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(113,12): error TS2304: Cannot find name 's'. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(113,14): error TS1312: '=' can only be used in object literal properties inside destructuring assignment. + + +==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts (12 errors) ==== + + + (function() { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } + }); + (function() { + var s0; + for ({ s0:s0 = 5 } of [{ s0: 1 }]) { + } + }); + + (function() { + var s1; + for ({ s1 = 5 } of [{}]) { + ~~ +!!! error TS2459: Type '{}' has no property 's1' and no string index signature. + } + }); + + (function() { + var s1; + for ({ s1:s1 = 5 } of [{}]) { + ~~ +!!! error TS2459: Type '{}' has no property 's1' and no string index signature. + } + }); + + (function() { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } + }); + + (function() { + var s2; + for ({ s2:s2 = 5 } of [{ s2: "" }]) { + } + }); + + (function() { + var s3: string; + for ({ s3 = 5 } of [{ s3: "" }]) { + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + }); + + (function() { + var s3: string; + for ({ s3:s3 = 5 } of [{ s3: "" }]) { + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + }); + + (function() { + let y; + ({ y = 5 } = { y: 1 }) + }); + + (function() { + let y; + ({ y:y = 5 } = { y: 1 }) + }); + + (function() { + let y0: number; + ({ y0 = 5 } = { y0: 1 }) + }); + + (function() { + let y0: number; + ({ y0:y0 = 5 } = { y0: 1 }) + }); + + (function() { + let y1: string; + ({ y1 = 5 } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y1: string; + ({ y1:y1 = 5 } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y2: string, y3: { x: string }; + ({ y2 = 5, y3 = { x: 1 } } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~ +!!! error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. +!!! error TS2322: Types of property 'x' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y2: string, y3: { x: string }; + ({ y2:y2 = 5, y3:y3 = { x: 1 } } = {}) + ~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~ +!!! error TS2322: Type '{ x: number; }' is not assignable to type '{ x: string; }'. +!!! error TS2322: Types of property 'x' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + }); + + (function() { + let y4: number, y5: { x: number }; + ({ y4 = 5, y5 = { x: 1 } } = {}) + }); + + (function() { + let y4: number, y5: { x: number }; + ({ y4:y4 = 5, y5:y5 = { x: 1 } } = {}) + }); + + + (function() { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); + }); + + + (function() { + let z; + ({ z:z = { x: 5 } } = { z: { x: 1 } }); + }); + + (function() { + let a = { s = 5 }; + ~ +!!! error TS2304: Cannot find name 's'. + ~ +!!! error TS1312: '=' can only be used in object literal properties inside destructuring assignment. + }); + + function foo({a = 4, b = { x: 5 }}) { + } \ No newline at end of file diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.js b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.js new file mode 100644 index 00000000000..11068708110 --- /dev/null +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.js @@ -0,0 +1,213 @@ +//// [shorthandPropertyAssignmentsInDestructuring_ES6.ts] + + +(function() { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } +}); +(function() { + var s0; + for ({ s0:s0 = 5 } of [{ s0: 1 }]) { + } +}); + +(function() { + var s1; + for ({ s1 = 5 } of [{}]) { + } +}); + +(function() { + var s1; + for ({ s1:s1 = 5 } of [{}]) { + } +}); + +(function() { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s2; + for ({ s2:s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3:s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + let y; + ({ y = 5 } = { y: 1 }) +}); + +(function() { + let y; + ({ y:y = 5 } = { y: 1 }) +}); + +(function() { + let y0: number; + ({ y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y0: number; + ({ y0:y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y1: string; + ({ y1 = 5 } = {}) +}); + +(function() { + let y1: string; + ({ y1:y1 = 5 } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2 = 5, y3 = { x: 1 } } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2:y2 = 5, y3:y3 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4 = 5, y5 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4:y4 = 5, y5:y5 = { x: 1 } } = {}) +}); + + +(function() { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); +}); + + +(function() { + let z; + ({ z:z = { x: 5 } } = { z: { x: 1 } }); +}); + +(function() { + let a = { s = 5 }; +}); + +function foo({a = 4, b = { x: 5 }}) { +} + +//// [shorthandPropertyAssignmentsInDestructuring_ES6.js] +(function () { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } +}); +(function () { + var s0; + for ({ s0: s0 = 5 } of [{ s0: 1 }]) { + } +}); +(function () { + var s1; + for ({ s1 = 5 } of [{}]) { + } +}); +(function () { + var s1; + for ({ s1: s1 = 5 } of [{}]) { + } +}); +(function () { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } +}); +(function () { + var s2; + for ({ s2: s2 = 5 } of [{ s2: "" }]) { + } +}); +(function () { + var s3; + for ({ s3 = 5 } of [{ s3: "" }]) { + } +}); +(function () { + var s3; + for ({ s3: s3 = 5 } of [{ s3: "" }]) { + } +}); +(function () { + let y; + ({ y = 5 } = { y: 1 }); +}); +(function () { + let y; + ({ y: y = 5 } = { y: 1 }); +}); +(function () { + let y0; + ({ y0 = 5 } = { y0: 1 }); +}); +(function () { + let y0; + ({ y0: y0 = 5 } = { y0: 1 }); +}); +(function () { + let y1; + ({ y1 = 5 } = {}); +}); +(function () { + let y1; + ({ y1: y1 = 5 } = {}); +}); +(function () { + let y2, y3; + ({ y2 = 5, y3 = { x: 1 } } = {}); +}); +(function () { + let y2, y3; + ({ y2: y2 = 5, y3: y3 = { x: 1 } } = {}); +}); +(function () { + let y4, y5; + ({ y4 = 5, y5 = { x: 1 } } = {}); +}); +(function () { + let y4, y5; + ({ y4: y4 = 5, y5: y5 = { x: 1 } } = {}); +}); +(function () { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); +}); +(function () { + let z; + ({ z: z = { x: 5 } } = { z: { x: 1 } }); +}); +(function () { + let a = { s = 5 }; +}); +function foo({ a = 4, b = { x: 5 } }) { +} diff --git a/tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts b/tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts new file mode 100644 index 00000000000..9750ea5d161 --- /dev/null +++ b/tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts @@ -0,0 +1,118 @@ +// @target: ES5 + + +(function() { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } +}); +(function() { + var s0; + for ({ s0:s0 = 5 } of [{ s0: 1 }]) { + } +}); + +(function() { + var s1; + for ({ s1 = 5 } of [{}]) { + } +}); + +(function() { + var s1; + for ({ s1:s1 = 5 } of [{}]) { + } +}); + +(function() { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s2; + for ({ s2:s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3:s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + let y; + ({ y = 5 } = { y: 1 }) +}); + +(function() { + let y; + ({ y:y = 5 } = { y: 1 }) +}); + +(function() { + let y0: number; + ({ y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y0: number; + ({ y0:y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y1: string; + ({ y1 = 5 } = {}) +}); + +(function() { + let y1: string; + ({ y1:y1 = 5 } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2 = 5, y3 = { x: 1 } } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2:y2 = 5, y3:y3 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4 = 5, y5 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4:y4 = 5, y5:y5 = { x: 1 } } = {}) +}); + + +(function() { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); +}); + + +(function() { + let z; + ({ z:z = { x: 5 } } = { z: { x: 1 } }); +}); + +(function() { + let a = { s = 5 }; +}); + +function foo({a = 4, b = { x: 5 }}) { +} \ No newline at end of file diff --git a/tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts b/tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts new file mode 100644 index 00000000000..d479511b11d --- /dev/null +++ b/tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts @@ -0,0 +1,118 @@ +// @target: ES6 + + +(function() { + var s0; + for ({ s0 = 5 } of [{ s0: 1 }]) { + } +}); +(function() { + var s0; + for ({ s0:s0 = 5 } of [{ s0: 1 }]) { + } +}); + +(function() { + var s1; + for ({ s1 = 5 } of [{}]) { + } +}); + +(function() { + var s1; + for ({ s1:s1 = 5 } of [{}]) { + } +}); + +(function() { + var s2; + for ({ s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s2; + for ({ s2:s2 = 5 } of [{ s2: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + var s3: string; + for ({ s3:s3 = 5 } of [{ s3: "" }]) { + } +}); + +(function() { + let y; + ({ y = 5 } = { y: 1 }) +}); + +(function() { + let y; + ({ y:y = 5 } = { y: 1 }) +}); + +(function() { + let y0: number; + ({ y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y0: number; + ({ y0:y0 = 5 } = { y0: 1 }) +}); + +(function() { + let y1: string; + ({ y1 = 5 } = {}) +}); + +(function() { + let y1: string; + ({ y1:y1 = 5 } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2 = 5, y3 = { x: 1 } } = {}) +}); + +(function() { + let y2: string, y3: { x: string }; + ({ y2:y2 = 5, y3:y3 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4 = 5, y5 = { x: 1 } } = {}) +}); + +(function() { + let y4: number, y5: { x: number }; + ({ y4:y4 = 5, y5:y5 = { x: 1 } } = {}) +}); + + +(function() { + let z; + ({ z = { x: 5 } } = { z: { x: 1 } }); +}); + + +(function() { + let z; + ({ z:z = { x: 5 } } = { z: { x: 1 } }); +}); + +(function() { + let a = { s = 5 }; +}); + +function foo({a = 4, b = { x: 5 }}) { +} \ No newline at end of file From 8960f523eaee101b1a60511ac638a927139f7a4c Mon Sep 17 00:00:00 2001 From: jbondc Date: Thu, 8 Oct 2015 07:57:35 -0400 Subject: [PATCH 02/15] Resolve const enum value in index access. --- src/compiler/checker.ts | 7 ++++ tests/cases/compiler/constIndexedAccess.ts | 40 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/cases/compiler/constIndexedAccess.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 551f428ca9a..c36ce9a7667 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8125,6 +8125,7 @@ namespace ts { /** * If indexArgumentExpression is a string literal or number literal, returns its text. + * If indexArgumentExpression is a constant value, returns its string value. * If indexArgumentExpression is a well known symbol, returns the property name corresponding * to this symbol, as long as it is a proper symbol reference. * Otherwise, returns undefined. @@ -8133,6 +8134,12 @@ namespace ts { if (indexArgumentExpression.kind === SyntaxKind.StringLiteral || indexArgumentExpression.kind === SyntaxKind.NumericLiteral) { return (indexArgumentExpression).text; } + if (indexArgumentExpression.kind === SyntaxKind.ElementAccessExpression || indexArgumentExpression.kind === SyntaxKind.PropertyAccessExpression) { + let value = getConstantValue(indexArgumentExpression); + if (value !== undefined) { + return value.toString(); + } + } if (checkThatExpressionIsProperSymbolReference(indexArgumentExpression, indexArgumentType, /*reportError*/ false)) { let rightHandSideName = ((indexArgumentExpression).name).text; return getPropertyNameForKnownSymbolName(rightHandSideName); diff --git a/tests/cases/compiler/constIndexedAccess.ts b/tests/cases/compiler/constIndexedAccess.ts new file mode 100644 index 00000000000..a1b1acc6872 --- /dev/null +++ b/tests/cases/compiler/constIndexedAccess.ts @@ -0,0 +1,40 @@ + +const enum numbers { + zero, + one +} + +interface indexAccess { + 0: string; + 1: number; +} + +let test: indexAccess; + +let s = test[0]; +let n = test[1]; + +let s1 = test[numbers.zero]; +let n1 = test[numbers.one]; + +/* +TODO: revisit with const propagation + +const zero = 0; +const one = 1; + +let s2 = test[zero]; +let n2 = test[one]; + +const zeroRef = zero; +const oneRef = one; + +let s3 = test[zeroRef]; +let n3 = test[oneRef]; + +const zeroRefEnum = numbers.zero; +const oneRefEnum = numbers.one; + +let s4 = test[zeroRefEnum]; +let n4 = test[oneRefEnum]; +*/ \ No newline at end of file From 82eb992dc43ad91ee553b9853ef7f6501b1afd77 Mon Sep 17 00:00:00 2001 From: jbondc Date: Thu, 8 Oct 2015 08:21:28 -0400 Subject: [PATCH 03/15] Accept baselines. --- src/compiler/checker.ts | 12 ++-- .../baselines/reference/constIndexedAccess.js | 69 ++++++++++++++++++ .../reference/constIndexedAccess.symbols | 68 ++++++++++++++++++ .../reference/constIndexedAccess.types | 72 +++++++++++++++++++ 4 files changed, 215 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/constIndexedAccess.js create mode 100644 tests/baselines/reference/constIndexedAccess.symbols create mode 100644 tests/baselines/reference/constIndexedAccess.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c36ce9a7667..d6e5a73d146 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8134,12 +8134,12 @@ namespace ts { if (indexArgumentExpression.kind === SyntaxKind.StringLiteral || indexArgumentExpression.kind === SyntaxKind.NumericLiteral) { return (indexArgumentExpression).text; } - if (indexArgumentExpression.kind === SyntaxKind.ElementAccessExpression || indexArgumentExpression.kind === SyntaxKind.PropertyAccessExpression) { - let value = getConstantValue(indexArgumentExpression); - if (value !== undefined) { - return value.toString(); - } - } + if (indexArgumentExpression.kind === SyntaxKind.ElementAccessExpression || indexArgumentExpression.kind === SyntaxKind.PropertyAccessExpression) { + let value = getConstantValue(indexArgumentExpression); + if (value !== undefined) { + return value.toString(); + } + } if (checkThatExpressionIsProperSymbolReference(indexArgumentExpression, indexArgumentType, /*reportError*/ false)) { let rightHandSideName = ((indexArgumentExpression).name).text; return getPropertyNameForKnownSymbolName(rightHandSideName); diff --git a/tests/baselines/reference/constIndexedAccess.js b/tests/baselines/reference/constIndexedAccess.js new file mode 100644 index 00000000000..ee0e9b8cc36 --- /dev/null +++ b/tests/baselines/reference/constIndexedAccess.js @@ -0,0 +1,69 @@ +//// [constIndexedAccess.ts] + +const enum numbers { + zero, + one +} + +interface indexAccess { + 0: string; + 1: number; +} + +let test: indexAccess; + +let s = test[0]; +let n = test[1]; + +let s1 = test[numbers.zero]; +let n1 = test[numbers.one]; + +/* +TODO: revisit with const propagation + +const zero = 0; +const one = 1; + +let s2 = test[zero]; +let n2 = test[one]; + +const zeroRef = zero; +const oneRef = one; + +let s3 = test[zeroRef]; +let n3 = test[oneRef]; + +const zeroRefEnum = numbers.zero; +const oneRefEnum = numbers.one; + +let s4 = test[zeroRefEnum]; +let n4 = test[oneRefEnum]; +*/ + +//// [constIndexedAccess.js] +var test; +var s = test[0]; +var n = test[1]; +var s1 = test[0 /* zero */]; +var n1 = test[1 /* one */]; +/* +TODO: revisit with const propagation + +const zero = 0; +const one = 1; + +let s2 = test[zero]; +let n2 = test[one]; + +const zeroRef = zero; +const oneRef = one; + +let s3 = test[zeroRef]; +let n3 = test[oneRef]; + +const zeroRefEnum = numbers.zero; +const oneRefEnum = numbers.one; + +let s4 = test[zeroRefEnum]; +let n4 = test[oneRefEnum]; +*/ diff --git a/tests/baselines/reference/constIndexedAccess.symbols b/tests/baselines/reference/constIndexedAccess.symbols new file mode 100644 index 00000000000..ff18f84372e --- /dev/null +++ b/tests/baselines/reference/constIndexedAccess.symbols @@ -0,0 +1,68 @@ +=== tests/cases/compiler/constIndexedAccess.ts === + +const enum numbers { +>numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) + + zero, +>zero : Symbol(numbers.zero, Decl(constIndexedAccess.ts, 1, 20)) + + one +>one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 6)) +} + +interface indexAccess { +>indexAccess : Symbol(indexAccess, Decl(constIndexedAccess.ts, 4, 1)) + + 0: string; + 1: number; +} + +let test: indexAccess; +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>indexAccess : Symbol(indexAccess, Decl(constIndexedAccess.ts, 4, 1)) + +let s = test[0]; +>s : Symbol(s, Decl(constIndexedAccess.ts, 13, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>0 : Symbol(indexAccess.0, Decl(constIndexedAccess.ts, 6, 23)) + +let n = test[1]; +>n : Symbol(n, Decl(constIndexedAccess.ts, 14, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>1 : Symbol(indexAccess.1, Decl(constIndexedAccess.ts, 7, 11)) + +let s1 = test[numbers.zero]; +>s1 : Symbol(s1, Decl(constIndexedAccess.ts, 16, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>numbers.zero : Symbol(numbers.zero, Decl(constIndexedAccess.ts, 1, 20)) +>numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) +>zero : Symbol(numbers.zero, Decl(constIndexedAccess.ts, 1, 20)) + +let n1 = test[numbers.one]; +>n1 : Symbol(n1, Decl(constIndexedAccess.ts, 17, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>numbers.one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 6)) +>numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) +>one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 6)) + +/* +TODO: revisit with const propagation + +const zero = 0; +const one = 1; + +let s2 = test[zero]; +let n2 = test[one]; + +const zeroRef = zero; +const oneRef = one; + +let s3 = test[zeroRef]; +let n3 = test[oneRef]; + +const zeroRefEnum = numbers.zero; +const oneRefEnum = numbers.one; + +let s4 = test[zeroRefEnum]; +let n4 = test[oneRefEnum]; +*/ diff --git a/tests/baselines/reference/constIndexedAccess.types b/tests/baselines/reference/constIndexedAccess.types new file mode 100644 index 00000000000..b4cc0e930d5 --- /dev/null +++ b/tests/baselines/reference/constIndexedAccess.types @@ -0,0 +1,72 @@ +=== tests/cases/compiler/constIndexedAccess.ts === + +const enum numbers { +>numbers : numbers + + zero, +>zero : numbers + + one +>one : numbers +} + +interface indexAccess { +>indexAccess : indexAccess + + 0: string; + 1: number; +} + +let test: indexAccess; +>test : indexAccess +>indexAccess : indexAccess + +let s = test[0]; +>s : string +>test[0] : string +>test : indexAccess +>0 : number + +let n = test[1]; +>n : number +>test[1] : number +>test : indexAccess +>1 : number + +let s1 = test[numbers.zero]; +>s1 : string +>test[numbers.zero] : string +>test : indexAccess +>numbers.zero : numbers +>numbers : typeof numbers +>zero : numbers + +let n1 = test[numbers.one]; +>n1 : number +>test[numbers.one] : number +>test : indexAccess +>numbers.one : numbers +>numbers : typeof numbers +>one : numbers + +/* +TODO: revisit with const propagation + +const zero = 0; +const one = 1; + +let s2 = test[zero]; +let n2 = test[one]; + +const zeroRef = zero; +const oneRef = one; + +let s3 = test[zeroRef]; +let n3 = test[oneRef]; + +const zeroRefEnum = numbers.zero; +const oneRefEnum = numbers.one; + +let s4 = test[zeroRefEnum]; +let n4 = test[oneRefEnum]; +*/ From 9eed58db47724e34fa9ef164522bf616f8227039 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 8 Oct 2015 11:23:52 -0700 Subject: [PATCH 04/15] Fix i4684 --- src/lib/dom.generated.d.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 1d2ad26db36..dbf9dc23532 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -7893,6 +7893,11 @@ declare var Node: { } interface NodeFilter { + acceptNode(n: Node): number; +} + +declare var NodeFilter: { + prototype: NodeFilter; FILTER_ACCEPT: number; FILTER_REJECT: number; FILTER_SKIP: number; @@ -7910,7 +7915,6 @@ interface NodeFilter { SHOW_PROCESSING_INSTRUCTION: number; SHOW_TEXT: number; } -declare var NodeFilter: NodeFilter; interface NodeIterator { expandEntityReferences: boolean; From d229ae4be50b6acddb2d52a4deeb220bca1b975e Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 8 Oct 2015 11:28:18 -0700 Subject: [PATCH 05/15] Escape quotes when emitting React --- src/compiler/emitter.ts | 4 ++-- tests/baselines/reference/tsxReactEmit6.js | 6 ++++++ tests/baselines/reference/tsxReactEmit6.symbols | 7 +++++++ tests/baselines/reference/tsxReactEmit6.types | 8 ++++++++ tests/cases/conformance/jsx/tsxReactEmit6.tsx | 4 ++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 312ea42eefb..7440c905566 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -6848,7 +6848,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (isLineBreak(c)) { if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) { let part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1); - result = (result ? result + "\" + ' ' + \"" : "") + part; + result = (result ? result + "\" + ' ' + \"" : "") + escapeString(part); } firstNonWhitespace = -1; } @@ -6862,7 +6862,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (firstNonWhitespace !== -1) { let part = text.substr(firstNonWhitespace); - result = (result ? result + "\" + ' ' + \"" : "") + part; + result = (result ? result + "\" + ' ' + \"" : "") + escapeString(part); } if (result) { diff --git a/tests/baselines/reference/tsxReactEmit6.js b/tests/baselines/reference/tsxReactEmit6.js index d20ef7051e0..4f583929004 100644 --- a/tests/baselines/reference/tsxReactEmit6.js +++ b/tests/baselines/reference/tsxReactEmit6.js @@ -19,7 +19,11 @@ namespace M { // and M.React.__spread var foo; var spread1 =
; + + // Quotes + var x =
This "quote" thing
; } + //// [file.js] @@ -33,4 +37,6 @@ var M; // and M.React.__spread var foo; var spread1 = M.React.createElement("div", M.React.__spread({x: ''}, foo, {y: ''})); + // Quotes + var x = M.React.createElement("div", null, "This \"quote\" thing"); })(M || (M = {})); diff --git a/tests/baselines/reference/tsxReactEmit6.symbols b/tests/baselines/reference/tsxReactEmit6.symbols index fd717ee4a5b..8eb0561e185 100644 --- a/tests/baselines/reference/tsxReactEmit6.symbols +++ b/tests/baselines/reference/tsxReactEmit6.symbols @@ -36,5 +36,12 @@ namespace M { >x : Symbol(unknown) >foo : Symbol(foo, Decl(react-consumer.tsx, 7, 4)) >y : Symbol(unknown) + + // Quotes + var x =
This "quote" thing
; +>x : Symbol(x, Decl(react-consumer.tsx, 11, 4)) +>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 2, 22)) +>div : Symbol(JSX.IntrinsicElements, Decl(file.tsx, 2, 22)) } + diff --git a/tests/baselines/reference/tsxReactEmit6.types b/tests/baselines/reference/tsxReactEmit6.types index 1b16b84fcc7..b8a307eb9d7 100644 --- a/tests/baselines/reference/tsxReactEmit6.types +++ b/tests/baselines/reference/tsxReactEmit6.types @@ -37,5 +37,13 @@ namespace M { >x : any >foo : any >y : any + + // Quotes + var x =
This "quote" thing
; +>x : JSX.Element +>
This "quote" thing
: JSX.Element +>div : any +>div : any } + diff --git a/tests/cases/conformance/jsx/tsxReactEmit6.tsx b/tests/cases/conformance/jsx/tsxReactEmit6.tsx index 2782f90e503..0e8c772a3f1 100644 --- a/tests/cases/conformance/jsx/tsxReactEmit6.tsx +++ b/tests/cases/conformance/jsx/tsxReactEmit6.tsx @@ -19,4 +19,8 @@ namespace M { // and M.React.__spread var foo; var spread1 =
; + + // Quotes + var x =
This "quote" thing
; } + From afa08181e2a2da66cac85fdeeb71357c55842c88 Mon Sep 17 00:00:00 2001 From: jbondc Date: Thu, 8 Oct 2015 17:30:46 -0400 Subject: [PATCH 06/15] Address code review. Accept baselines. --- .../baselines/reference/constIndexedAccess.js | 66 +++++++------------ .../reference/constIndexedAccess.symbols | 61 ++++++++++------- .../reference/constIndexedAccess.types | 59 +++++++++++------ tests/cases/compiler/constIndexedAccess.ts | 35 ++++------ 4 files changed, 112 insertions(+), 109 deletions(-) diff --git a/tests/baselines/reference/constIndexedAccess.js b/tests/baselines/reference/constIndexedAccess.js index ee0e9b8cc36..db80441bd33 100644 --- a/tests/baselines/reference/constIndexedAccess.js +++ b/tests/baselines/reference/constIndexedAccess.js @@ -1,13 +1,13 @@ //// [constIndexedAccess.ts] const enum numbers { - zero, - one + zero, + one } interface indexAccess { - 0: string; - 1: number; + 0: string; + 1: number; } let test: indexAccess; @@ -18,27 +18,17 @@ let n = test[1]; let s1 = test[numbers.zero]; let n1 = test[numbers.one]; -/* -TODO: revisit with const propagation +let s2 = test[numbers["zero"]]; +let n2 = test[numbers["one"]]; -const zero = 0; -const one = 1; +enum numbersNotConst { + zero, + one +} -let s2 = test[zero]; -let n2 = test[one]; - -const zeroRef = zero; -const oneRef = one; - -let s3 = test[zeroRef]; -let n3 = test[oneRef]; - -const zeroRefEnum = numbers.zero; -const oneRefEnum = numbers.one; - -let s4 = test[zeroRefEnum]; -let n4 = test[oneRefEnum]; -*/ +let s3 = test[numbersNotConst.zero]; +let n3 = test[numbersNotConst.one]; + //// [constIndexedAccess.js] var test; @@ -46,24 +36,12 @@ var s = test[0]; var n = test[1]; var s1 = test[0 /* zero */]; var n1 = test[1 /* one */]; -/* -TODO: revisit with const propagation - -const zero = 0; -const one = 1; - -let s2 = test[zero]; -let n2 = test[one]; - -const zeroRef = zero; -const oneRef = one; - -let s3 = test[zeroRef]; -let n3 = test[oneRef]; - -const zeroRefEnum = numbers.zero; -const oneRefEnum = numbers.one; - -let s4 = test[zeroRefEnum]; -let n4 = test[oneRefEnum]; -*/ +var s2 = test[0 /* "zero" */]; +var n2 = test[1 /* "one" */]; +var numbersNotConst; +(function (numbersNotConst) { + numbersNotConst[numbersNotConst["zero"] = 0] = "zero"; + numbersNotConst[numbersNotConst["one"] = 1] = "one"; +})(numbersNotConst || (numbersNotConst = {})); +var s3 = test[numbersNotConst.zero]; +var n3 = test[numbersNotConst.one]; diff --git a/tests/baselines/reference/constIndexedAccess.symbols b/tests/baselines/reference/constIndexedAccess.symbols index ff18f84372e..2ccb7f11686 100644 --- a/tests/baselines/reference/constIndexedAccess.symbols +++ b/tests/baselines/reference/constIndexedAccess.symbols @@ -3,18 +3,18 @@ const enum numbers { >numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) - zero, + zero, >zero : Symbol(numbers.zero, Decl(constIndexedAccess.ts, 1, 20)) - one ->one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 6)) + one +>one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 9)) } interface indexAccess { >indexAccess : Symbol(indexAccess, Decl(constIndexedAccess.ts, 4, 1)) - 0: string; - 1: number; + 0: string; + 1: number; } let test: indexAccess; @@ -29,7 +29,7 @@ let s = test[0]; let n = test[1]; >n : Symbol(n, Decl(constIndexedAccess.ts, 14, 3)) >test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) ->1 : Symbol(indexAccess.1, Decl(constIndexedAccess.ts, 7, 11)) +>1 : Symbol(indexAccess.1, Decl(constIndexedAccess.ts, 7, 14)) let s1 = test[numbers.zero]; >s1 : Symbol(s1, Decl(constIndexedAccess.ts, 16, 3)) @@ -41,28 +41,43 @@ let s1 = test[numbers.zero]; let n1 = test[numbers.one]; >n1 : Symbol(n1, Decl(constIndexedAccess.ts, 17, 3)) >test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) ->numbers.one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 6)) +>numbers.one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 9)) >numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) ->one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 6)) +>one : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 9)) -/* -TODO: revisit with const propagation +let s2 = test[numbers["zero"]]; +>s2 : Symbol(s2, Decl(constIndexedAccess.ts, 19, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) +>"zero" : Symbol(numbers.zero, Decl(constIndexedAccess.ts, 1, 20)) -const zero = 0; -const one = 1; +let n2 = test[numbers["one"]]; +>n2 : Symbol(n2, Decl(constIndexedAccess.ts, 20, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>numbers : Symbol(numbers, Decl(constIndexedAccess.ts, 0, 0)) +>"one" : Symbol(numbers.one, Decl(constIndexedAccess.ts, 2, 9)) -let s2 = test[zero]; -let n2 = test[one]; +enum numbersNotConst { +>numbersNotConst : Symbol(numbersNotConst, Decl(constIndexedAccess.ts, 20, 30)) -const zeroRef = zero; -const oneRef = one; + zero, +>zero : Symbol(numbersNotConst.zero, Decl(constIndexedAccess.ts, 22, 22)) -let s3 = test[zeroRef]; -let n3 = test[oneRef]; + one +>one : Symbol(numbersNotConst.one, Decl(constIndexedAccess.ts, 23, 9)) +} -const zeroRefEnum = numbers.zero; -const oneRefEnum = numbers.one; +let s3 = test[numbersNotConst.zero]; +>s3 : Symbol(s3, Decl(constIndexedAccess.ts, 27, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>numbersNotConst.zero : Symbol(numbersNotConst.zero, Decl(constIndexedAccess.ts, 22, 22)) +>numbersNotConst : Symbol(numbersNotConst, Decl(constIndexedAccess.ts, 20, 30)) +>zero : Symbol(numbersNotConst.zero, Decl(constIndexedAccess.ts, 22, 22)) + +let n3 = test[numbersNotConst.one]; +>n3 : Symbol(n3, Decl(constIndexedAccess.ts, 28, 3)) +>test : Symbol(test, Decl(constIndexedAccess.ts, 11, 3)) +>numbersNotConst.one : Symbol(numbersNotConst.one, Decl(constIndexedAccess.ts, 23, 9)) +>numbersNotConst : Symbol(numbersNotConst, Decl(constIndexedAccess.ts, 20, 30)) +>one : Symbol(numbersNotConst.one, Decl(constIndexedAccess.ts, 23, 9)) -let s4 = test[zeroRefEnum]; -let n4 = test[oneRefEnum]; -*/ diff --git a/tests/baselines/reference/constIndexedAccess.types b/tests/baselines/reference/constIndexedAccess.types index b4cc0e930d5..eb02c7bde2e 100644 --- a/tests/baselines/reference/constIndexedAccess.types +++ b/tests/baselines/reference/constIndexedAccess.types @@ -3,18 +3,18 @@ const enum numbers { >numbers : numbers - zero, + zero, >zero : numbers - one + one >one : numbers } interface indexAccess { >indexAccess : indexAccess - 0: string; - 1: number; + 0: string; + 1: number; } let test: indexAccess; @@ -49,24 +49,45 @@ let n1 = test[numbers.one]; >numbers : typeof numbers >one : numbers -/* -TODO: revisit with const propagation +let s2 = test[numbers["zero"]]; +>s2 : string +>test[numbers["zero"]] : string +>test : indexAccess +>numbers["zero"] : numbers +>numbers : typeof numbers +>"zero" : string -const zero = 0; -const one = 1; +let n2 = test[numbers["one"]]; +>n2 : number +>test[numbers["one"]] : number +>test : indexAccess +>numbers["one"] : numbers +>numbers : typeof numbers +>"one" : string -let s2 = test[zero]; -let n2 = test[one]; +enum numbersNotConst { +>numbersNotConst : numbersNotConst -const zeroRef = zero; -const oneRef = one; + zero, +>zero : numbersNotConst -let s3 = test[zeroRef]; -let n3 = test[oneRef]; + one +>one : numbersNotConst +} -const zeroRefEnum = numbers.zero; -const oneRefEnum = numbers.one; +let s3 = test[numbersNotConst.zero]; +>s3 : any +>test[numbersNotConst.zero] : any +>test : indexAccess +>numbersNotConst.zero : numbersNotConst +>numbersNotConst : typeof numbersNotConst +>zero : numbersNotConst + +let n3 = test[numbersNotConst.one]; +>n3 : any +>test[numbersNotConst.one] : any +>test : indexAccess +>numbersNotConst.one : numbersNotConst +>numbersNotConst : typeof numbersNotConst +>one : numbersNotConst -let s4 = test[zeroRefEnum]; -let n4 = test[oneRefEnum]; -*/ diff --git a/tests/cases/compiler/constIndexedAccess.ts b/tests/cases/compiler/constIndexedAccess.ts index a1b1acc6872..d71a3cdb9f4 100644 --- a/tests/cases/compiler/constIndexedAccess.ts +++ b/tests/cases/compiler/constIndexedAccess.ts @@ -1,12 +1,12 @@  const enum numbers { - zero, - one + zero, + one } interface indexAccess { - 0: string; - 1: number; + 0: string; + 1: number; } let test: indexAccess; @@ -17,24 +17,13 @@ let n = test[1]; let s1 = test[numbers.zero]; let n1 = test[numbers.one]; -/* -TODO: revisit with const propagation +let s2 = test[numbers["zero"]]; +let n2 = test[numbers["one"]]; -const zero = 0; -const one = 1; +enum numbersNotConst { + zero, + one +} -let s2 = test[zero]; -let n2 = test[one]; - -const zeroRef = zero; -const oneRef = one; - -let s3 = test[zeroRef]; -let n3 = test[oneRef]; - -const zeroRefEnum = numbers.zero; -const oneRefEnum = numbers.one; - -let s4 = test[zeroRefEnum]; -let n4 = test[oneRefEnum]; -*/ \ No newline at end of file +let s3 = test[numbersNotConst.zero]; +let n3 = test[numbersNotConst.one]; From 3d6398162e1fe19d7d8da6d17f6eb98ba9998212 Mon Sep 17 00:00:00 2001 From: jbondc Date: Fri, 9 Oct 2015 11:16:36 -0400 Subject: [PATCH 07/15] Typo --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d6e5a73d146..228b1067bb0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9751,7 +9751,7 @@ namespace ts { return !symbol || symbol === unknownSymbol || (symbol.flags & ~SymbolFlags.EnumMember) !== 0; } case SyntaxKind.ElementAccessExpression: - // old compiler doesn't check indexed assess + // old compiler doesn't check indexed access return true; case SyntaxKind.ParenthesizedExpression: return isReferenceOrErrorExpression((n).expression); From a556209b7e68306bcb9faaa36ac57e0624e3ca8e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 9 Oct 2015 09:55:25 -0700 Subject: [PATCH 08/15] addressed PR feedback --- src/compiler/checker.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- .../shorthandPropertyAssignmentsInDestructuring.errors.txt | 4 ++-- ...shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ece6860e5b2..2ede84062ce 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15477,7 +15477,7 @@ namespace ts { if (prop.kind === SyntaxKind.ShorthandPropertyAssignment && !inDestructuring && (prop).objectAssignmentInitializer) { // having objectAssignmentInitializer is only valid in ObjectAssignmentPattern // outside of destructuring it is a syntax error - return grammarErrorOnNode((prop).equalsToken, Diagnostics.can_only_be_used_in_object_literal_properties_inside_destructuring_assignment); + return grammarErrorOnNode((prop).equalsToken, Diagnostics.can_only_be_used_in_an_object_literal_property_inside_a_destructuring_assignment); } // ECMA-262 11.1.5 Object Initialiser diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a41d5d99005..ae54fda8496 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -800,7 +800,7 @@ "category": "Error", "code": 1311 }, - "'=' can only be used in object literal properties inside destructuring assignment.": { + "'=' can only be used in an object literal property inside a destructuring assignment.": { "category": "Error", "code": 1312 }, diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt index 844078cd8f1..7ac5fe9a26c 100644 --- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring.errors.txt @@ -13,7 +13,7 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(87,19): erro Types of property 'x' are incompatible. Type 'number' is not assignable to type 'string'. tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(113,12): error TS2304: Cannot find name 's'. -tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(113,14): error TS1312: '=' can only be used in object literal properties inside destructuring assignment. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(113,14): error TS1312: '=' can only be used in an object literal property inside a destructuring assignment. ==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts (12 errors) ==== @@ -157,7 +157,7 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring.ts(113,14): err ~ !!! error TS2304: Cannot find name 's'. ~ -!!! error TS1312: '=' can only be used in object literal properties inside destructuring assignment. +!!! error TS1312: '=' can only be used in an object literal property inside a destructuring assignment. }); function foo({a = 4, b = { x: 5 }}) { diff --git a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt index 208a8798c39..7e6b6b35d7f 100644 --- a/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt +++ b/tests/baselines/reference/shorthandPropertyAssignmentsInDestructuring_ES6.errors.txt @@ -13,7 +13,7 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(87,19): Types of property 'x' are incompatible. Type 'number' is not assignable to type 'string'. tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(113,12): error TS2304: Cannot find name 's'. -tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(113,14): error TS1312: '=' can only be used in object literal properties inside destructuring assignment. +tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(113,14): error TS1312: '=' can only be used in an object literal property inside a destructuring assignment. ==== tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts (12 errors) ==== @@ -157,7 +157,7 @@ tests/cases/compiler/shorthandPropertyAssignmentsInDestructuring_ES6.ts(113,14): ~ !!! error TS2304: Cannot find name 's'. ~ -!!! error TS1312: '=' can only be used in object literal properties inside destructuring assignment. +!!! error TS1312: '=' can only be used in an object literal property inside a destructuring assignment. }); function foo({a = 4, b = { x: 5 }}) { From 69ff6f50903aee59cd0aade2ad67558e599976ca Mon Sep 17 00:00:00 2001 From: Martin Vseticka Date: Fri, 2 Oct 2015 21:54:32 +0200 Subject: [PATCH 09/15] Add "A module cannot have multiple default exports." message for multiple "default" exports --- src/compiler/binder.ts | 10 +++++++- src/compiler/diagnosticMessages.json | 4 ++++ .../reference/defaultExportWithOverloads01.js | 16 +++++++++++++ .../defaultExportWithOverloads01.symbols | 13 +++++++++++ .../defaultExportWithOverloads01.types | 13 +++++++++++ .../multipleDefaultExports01.errors.txt | 12 +++++----- .../multipleDefaultExports03.errors.txt | 15 ++++++++++++ .../reference/multipleDefaultExports03.js | 23 +++++++++++++++++++ .../multipleDefaultExports04.errors.txt | 15 ++++++++++++ .../reference/multipleDefaultExports04.js | 17 ++++++++++++++ .../modules/defaultExportWithOverloads01.ts | 7 ++++++ .../es6/modules/multipleDefaultExports03.ts | 8 +++++++ .../es6/modules/multipleDefaultExports04.ts | 8 +++++++ 13 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/defaultExportWithOverloads01.js create mode 100644 tests/baselines/reference/defaultExportWithOverloads01.symbols create mode 100644 tests/baselines/reference/defaultExportWithOverloads01.types create mode 100644 tests/baselines/reference/multipleDefaultExports03.errors.txt create mode 100644 tests/baselines/reference/multipleDefaultExports03.js create mode 100644 tests/baselines/reference/multipleDefaultExports04.errors.txt create mode 100644 tests/baselines/reference/multipleDefaultExports04.js create mode 100644 tests/cases/conformance/es6/modules/defaultExportWithOverloads01.ts create mode 100644 tests/cases/conformance/es6/modules/multipleDefaultExports03.ts create mode 100644 tests/cases/conformance/es6/modules/multipleDefaultExports04.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 65768332360..c12a9afad62 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -185,8 +185,9 @@ namespace ts { function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { Debug.assert(!hasDynamicName(node)); + let isDefaultExport = node.flags & NodeFlags.Default; // The exported symbol for an export default function/class node is always named "default" - let name = node.flags & NodeFlags.Default && parent ? "default" : getDeclarationName(node); + let name = isDefaultExport && parent ? "default" : getDeclarationName(node); let symbol: Symbol; if (name !== undefined) { @@ -227,6 +228,13 @@ namespace ts { let message = symbol.flags & SymbolFlags.BlockScopedVariable ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0; + + forEach(symbol.declarations, declaration => { + if (declaration.flags & NodeFlags.Default) { + message = Diagnostics.A_module_cannot_have_multiple_default_exports; + } + }); + forEach(symbol.declarations, declaration => { file.bindDiagnostics.push(createDiagnosticForNode(declaration.name || declaration, message, getDisplayName(declaration))); }); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f6656edb250..22b65b58111 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1656,6 +1656,10 @@ "category": "Error", "code": 2527 }, + "A module cannot have multiple default exports.": { + "category": "Error", + "code": 2528 + }, "JSX element attributes type '{0}' must be an object type.": { "category": "Error", "code": 2600 diff --git a/tests/baselines/reference/defaultExportWithOverloads01.js b/tests/baselines/reference/defaultExportWithOverloads01.js new file mode 100644 index 00000000000..9ec8cccf5bf --- /dev/null +++ b/tests/baselines/reference/defaultExportWithOverloads01.js @@ -0,0 +1,16 @@ +//// [defaultExportWithOverloads01.ts] + +export default function f(); +export default function f(x: string); +export default function f(...args: any[]) { +} + +//// [defaultExportWithOverloads01.js] +function f() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i - 0] = arguments[_i]; + } +} +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = f; diff --git a/tests/baselines/reference/defaultExportWithOverloads01.symbols b/tests/baselines/reference/defaultExportWithOverloads01.symbols new file mode 100644 index 00000000000..a5ff0df5262 --- /dev/null +++ b/tests/baselines/reference/defaultExportWithOverloads01.symbols @@ -0,0 +1,13 @@ +=== tests/cases/conformance/es6/modules/defaultExportWithOverloads01.ts === + +export default function f(); +>f : Symbol(f, Decl(defaultExportWithOverloads01.ts, 0, 0), Decl(defaultExportWithOverloads01.ts, 1, 28), Decl(defaultExportWithOverloads01.ts, 2, 37)) + +export default function f(x: string); +>f : Symbol(f, Decl(defaultExportWithOverloads01.ts, 0, 0), Decl(defaultExportWithOverloads01.ts, 1, 28), Decl(defaultExportWithOverloads01.ts, 2, 37)) +>x : Symbol(x, Decl(defaultExportWithOverloads01.ts, 2, 26)) + +export default function f(...args: any[]) { +>f : Symbol(f, Decl(defaultExportWithOverloads01.ts, 0, 0), Decl(defaultExportWithOverloads01.ts, 1, 28), Decl(defaultExportWithOverloads01.ts, 2, 37)) +>args : Symbol(args, Decl(defaultExportWithOverloads01.ts, 3, 26)) +} diff --git a/tests/baselines/reference/defaultExportWithOverloads01.types b/tests/baselines/reference/defaultExportWithOverloads01.types new file mode 100644 index 00000000000..c006083b4ba --- /dev/null +++ b/tests/baselines/reference/defaultExportWithOverloads01.types @@ -0,0 +1,13 @@ +=== tests/cases/conformance/es6/modules/defaultExportWithOverloads01.ts === + +export default function f(); +>f : { (): any; (x: string): any; } + +export default function f(x: string); +>f : { (): any; (x: string): any; } +>x : string + +export default function f(...args: any[]) { +>f : { (): any; (x: string): any; } +>args : any[] +} diff --git a/tests/baselines/reference/multipleDefaultExports01.errors.txt b/tests/baselines/reference/multipleDefaultExports01.errors.txt index 72898d474e8..16aa3b2f7b1 100644 --- a/tests/baselines/reference/multipleDefaultExports01.errors.txt +++ b/tests/baselines/reference/multipleDefaultExports01.errors.txt @@ -1,6 +1,6 @@ -tests/cases/conformance/es6/modules/m1.ts(2,22): error TS2300: Duplicate identifier 'foo'. -tests/cases/conformance/es6/modules/m1.ts(6,25): error TS2300: Duplicate identifier 'bar'. -tests/cases/conformance/es6/modules/m1.ts(11,1): error TS2300: Duplicate identifier 'default'. +tests/cases/conformance/es6/modules/m1.ts(2,22): error TS2528: A module cannot have multiple default exports. +tests/cases/conformance/es6/modules/m1.ts(6,25): error TS2528: A module cannot have multiple default exports. +tests/cases/conformance/es6/modules/m1.ts(11,1): error TS2528: A module cannot have multiple default exports. tests/cases/conformance/es6/modules/m2.ts(3,1): error TS2348: Value of type 'typeof foo' is not callable. Did you mean to include 'new'? @@ -8,20 +8,20 @@ tests/cases/conformance/es6/modules/m2.ts(3,1): error TS2348: Value of type 'typ export default class foo { ~~~ -!!! error TS2300: Duplicate identifier 'foo'. +!!! error TS2528: A module cannot have multiple default exports. } export default function bar() { ~~~ -!!! error TS2300: Duplicate identifier 'bar'. +!!! error TS2528: A module cannot have multiple default exports. } var x = 10; export default x; ~~~~~~~~~~~~~~~~~ -!!! error TS2300: Duplicate identifier 'default'. +!!! error TS2528: A module cannot have multiple default exports. ==== tests/cases/conformance/es6/modules/m2.ts (1 errors) ==== import Entity from "./m1" diff --git a/tests/baselines/reference/multipleDefaultExports03.errors.txt b/tests/baselines/reference/multipleDefaultExports03.errors.txt new file mode 100644 index 00000000000..5c4b075b009 --- /dev/null +++ b/tests/baselines/reference/multipleDefaultExports03.errors.txt @@ -0,0 +1,15 @@ +tests/cases/conformance/es6/modules/multipleDefaultExports03.ts(2,22): error TS2528: A module cannot have multiple default exports. +tests/cases/conformance/es6/modules/multipleDefaultExports03.ts(5,22): error TS2528: A module cannot have multiple default exports. + + +==== tests/cases/conformance/es6/modules/multipleDefaultExports03.ts (2 errors) ==== + + export default class C { + ~ +!!! error TS2528: A module cannot have multiple default exports. + } + + export default class C { + ~ +!!! error TS2528: A module cannot have multiple default exports. + } \ No newline at end of file diff --git a/tests/baselines/reference/multipleDefaultExports03.js b/tests/baselines/reference/multipleDefaultExports03.js new file mode 100644 index 00000000000..2824c7a5ac1 --- /dev/null +++ b/tests/baselines/reference/multipleDefaultExports03.js @@ -0,0 +1,23 @@ +//// [multipleDefaultExports03.ts] + +export default class C { +} + +export default class C { +} + +//// [multipleDefaultExports03.js] +var C = (function () { + function C() { + } + return C; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = C; +var C = (function () { + function C() { + } + return C; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = C; diff --git a/tests/baselines/reference/multipleDefaultExports04.errors.txt b/tests/baselines/reference/multipleDefaultExports04.errors.txt new file mode 100644 index 00000000000..e67659f6b9f --- /dev/null +++ b/tests/baselines/reference/multipleDefaultExports04.errors.txt @@ -0,0 +1,15 @@ +tests/cases/conformance/es6/modules/multipleDefaultExports04.ts(2,25): error TS2393: Duplicate function implementation. +tests/cases/conformance/es6/modules/multipleDefaultExports04.ts(5,25): error TS2393: Duplicate function implementation. + + +==== tests/cases/conformance/es6/modules/multipleDefaultExports04.ts (2 errors) ==== + + export default function f() { + ~ +!!! error TS2393: Duplicate function implementation. + } + + export default function f() { + ~ +!!! error TS2393: Duplicate function implementation. + } \ No newline at end of file diff --git a/tests/baselines/reference/multipleDefaultExports04.js b/tests/baselines/reference/multipleDefaultExports04.js new file mode 100644 index 00000000000..73582d7389e --- /dev/null +++ b/tests/baselines/reference/multipleDefaultExports04.js @@ -0,0 +1,17 @@ +//// [multipleDefaultExports04.ts] + +export default function f() { +} + +export default function f() { +} + +//// [multipleDefaultExports04.js] +function f() { +} +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = f; +function f() { +} +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = f; diff --git a/tests/cases/conformance/es6/modules/defaultExportWithOverloads01.ts b/tests/cases/conformance/es6/modules/defaultExportWithOverloads01.ts new file mode 100644 index 00000000000..a6761600a1d --- /dev/null +++ b/tests/cases/conformance/es6/modules/defaultExportWithOverloads01.ts @@ -0,0 +1,7 @@ +// @module: commonjs +// @target: ES5 + +export default function f(); +export default function f(x: string); +export default function f(...args: any[]) { +} \ No newline at end of file diff --git a/tests/cases/conformance/es6/modules/multipleDefaultExports03.ts b/tests/cases/conformance/es6/modules/multipleDefaultExports03.ts new file mode 100644 index 00000000000..f2fe7f1a6c3 --- /dev/null +++ b/tests/cases/conformance/es6/modules/multipleDefaultExports03.ts @@ -0,0 +1,8 @@ +// @module: commonjs +// @target: ES5 + +export default class C { +} + +export default class C { +} \ No newline at end of file diff --git a/tests/cases/conformance/es6/modules/multipleDefaultExports04.ts b/tests/cases/conformance/es6/modules/multipleDefaultExports04.ts new file mode 100644 index 00000000000..1dec7b8bea5 --- /dev/null +++ b/tests/cases/conformance/es6/modules/multipleDefaultExports04.ts @@ -0,0 +1,8 @@ +// @module: commonjs +// @target: ES5 + +export default function f() { +} + +export default function f() { +} \ No newline at end of file From 573652160cb1ae5be28cdc77cd049bbd3cc5764b Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Fri, 9 Oct 2015 16:46:31 -0700 Subject: [PATCH 10/15] Merge pull request #5197 from Microsoft/supportIndentStyle Support different indentation styles --- src/harness/fourslash.ts | 19 ++- src/server/editorServices.ts | 2 +- src/server/session.ts | 1 + src/services/formatting/smartIndenter.ts | 32 +++- src/services/services.ts | 7 + tests/cases/fourslash/fourslash.ts | 11 +- tests/cases/fourslash/indentationBlock.ts | 183 ++++++++++++++++++++++ tests/cases/fourslash/indentationNone.ts | 183 ++++++++++++++++++++++ 8 files changed, 426 insertions(+), 12 deletions(-) create mode 100644 tests/cases/fourslash/indentationBlock.ts create mode 100644 tests/cases/fourslash/indentationNone.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index a846077a85f..3a628bb62c1 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -100,6 +100,8 @@ namespace FourSlash { end: number; } + export import IndentStyle = ts.IndentStyle; + let entityMap: ts.Map = { "&": "&", "\"": """, @@ -309,6 +311,7 @@ namespace FourSlash { TabSize: 4, NewLineCharacter: Harness.IO.newLine(), ConvertTabsToSpaces: true, + IndentStyle: ts.IndentStyle.Smart, InsertSpaceAfterCommaDelimiter: true, InsertSpaceAfterSemicolonInForStatements: true, InsertSpaceBeforeAndAfterBinaryOperators: true, @@ -1695,24 +1698,28 @@ namespace FourSlash { } } - private getIndentation(fileName: string, position: number): number { - return this.languageService.getIndentationAtPosition(fileName, position, this.formatCodeOptions); + private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle): number { + + let formatOptions = ts.clone(this.formatCodeOptions); + formatOptions.IndentStyle = indentStyle; + + return this.languageService.getIndentationAtPosition(fileName, position, formatOptions); } - public verifyIndentationAtCurrentPosition(numberOfSpaces: number) { + public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) { this.taoInvalidReason = "verifyIndentationAtCurrentPosition NYI"; - let actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition); + let actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle); let lineCol = this.getLineColStringAtPosition(this.currentCaretPosition); if (actual !== numberOfSpaces) { this.raiseError(`verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`); } } - public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number) { + public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) { this.taoInvalidReason = "verifyIndentationAtPosition NYI"; - let actual = this.getIndentation(fileName, position); + let actual = this.getIndentation(fileName, position, indentStyle); let lineCol = this.getLineColStringAtPosition(position); if (actual !== numberOfSpaces) { this.raiseError(`verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 7ab46fc689e..436b97821cc 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1177,6 +1177,7 @@ namespace ts.server { TabSize: 4, NewLineCharacter: ts.sys ? ts.sys.newLine : '\n', ConvertTabsToSpaces: true, + IndentStyle: ts.IndentStyle.Smart, InsertSpaceAfterCommaDelimiter: true, InsertSpaceAfterSemicolonInForStatements: true, InsertSpaceBeforeAndAfterBinaryOperators: true, @@ -1187,7 +1188,6 @@ namespace ts.server { PlaceOpenBraceOnNewLineForFunctions: false, PlaceOpenBraceOnNewLineForControlBlocks: false, } - } export interface LineCollection { diff --git a/src/server/session.ts b/src/server/session.ts index da044e7b4c6..f3d3826409e 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -606,6 +606,7 @@ namespace ts.server { TabSize: formatOptions.TabSize, NewLineCharacter: "\n", ConvertTabsToSpaces: formatOptions.ConvertTabsToSpaces, + IndentStyle: ts.IndentStyle.Smart, }; var indentPosition = compilerService.languageService.getIndentationAtPosition(file, position, editorOptions); diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 8035c963cf3..3b68cd0ebb2 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -13,6 +13,12 @@ namespace ts.formatting { return 0; // past EOF } + // no indentation when the indent style is set to none, + // so we can return fast + if (options.IndentStyle === IndentStyle.None) { + return 0; + } + let precedingToken = findPrecedingToken(position, sourceFile); if (!precedingToken) { return 0; @@ -26,6 +32,26 @@ namespace ts.formatting { let lineAtPosition = sourceFile.getLineAndCharacterOfPosition(position).line; + // indentation is first non-whitespace character in a previous line + // for block indentation, we should look for a line which contains something that's not + // whitespace. + if (options.IndentStyle === IndentStyle.Block) { + + // move backwards until we find a line with a non-whitespace character, + // then find the first non-whitespace character for that line. + let current = position; + while (current > 0){ + let char = sourceFile.text.charCodeAt(current); + if (!isWhiteSpace(char) && !isLineBreak(char)) { + break; + } + current--; + } + + let lineStart = ts.getLineStartPositionForPosition(current, sourceFile); + return SmartIndenter.findFirstNonWhitespaceColumn(lineStart, current, sourceFile, options); + } + if (precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression) { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it let actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options); @@ -218,7 +244,7 @@ namespace ts.formatting { function getStartLineAndCharacterForNode(n: Node, sourceFile: SourceFile): LineAndCharacter { return sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)); } - + export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFile): boolean { if (parent.kind === SyntaxKind.IfStatement && (parent).elseStatement === child) { let elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile); @@ -319,7 +345,7 @@ namespace ts.formatting { } return Value.Unknown; - + function getStartingExpression(node: PropertyAccessExpression | CallExpression | ElementAccessExpression) { while (true) { switch (node.kind) { @@ -465,4 +491,4 @@ namespace ts.formatting { } } } -} \ No newline at end of file +} diff --git a/src/services/services.ts b/src/services/services.ts index 9a6afb5f1e0..118c4ef3b7f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1189,6 +1189,13 @@ namespace ts { TabSize: number; NewLineCharacter: string; ConvertTabsToSpaces: boolean; + IndentStyle: IndentStyle; + } + + export enum IndentStyle { + None = 0, + Block = 1, + Smart = 2, } export interface FormatCodeOptions extends EditorOptions { diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 42cfc1248b0..54e86786d14 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -68,6 +68,13 @@ enum EmitReturnStatus { EmitErrorsEncountered = 4 // Emitter errors occurred during emitting process } +// This is a duplicate of the indentstyle in services.ts to expose it to testcases in fourslash +enum IndentStyle { + None, + Block, + Smart, +} + module FourSlashInterface { export interface Marker { @@ -278,8 +285,8 @@ module FourSlashInterface { FourSlash.currentTestState.verifyIndentationAtCurrentPosition(numberOfSpaces); } - public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number) { - FourSlash.currentTestState.verifyIndentationAtPosition(fileName, position, numberOfSpaces); + public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = IndentStyle.Smart) { + FourSlash.currentTestState.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle); } public textAtCaretIs(text: string) { diff --git a/tests/cases/fourslash/indentationBlock.ts b/tests/cases/fourslash/indentationBlock.ts new file mode 100644 index 00000000000..e880c4a0957 --- /dev/null +++ b/tests/cases/fourslash/indentationBlock.ts @@ -0,0 +1,183 @@ +/// + +//// +////module classes { +////{| "indent": 0 |} +//// class Bar { +////{| "indent": 4 |} +//// +//// constructor() { +////{| "indent": 8 |} +//// } +//// +//// private foo: string = ""; +////{| "indent": 8 |} +//// +//// private f() { +//// var a: any[] = [[1, 2], [3, 4], 5]; +////{| "indent": 12 |} +//// return ((1 + 1)); +//// } +//// +////{| "indent": 8 |} +//// private f2() { +//// if (true) { } { }; +//// } +//// } +////} +//// +//// +////module interfaces { +////{| "indent": 0 |} +//// interface Foo { +////{| "indent": 4 |} +//// +//// x: number; +////{| "indent": 8 |} +//// +//// foo(): number; +////{| "indent": 8 |} +//// } +////} +//// +//// +////module nestedModules { +//// module Foo2 { +////{| "indent": 4 |} +//// function f() { +//// } +////{| "indent": 8 |} +//// var x: number; +////{| "indent": 8 |} +//// } +////} +//// +//// +////module Enums { +//// enum Foo3 { +////{| "indent": 4 |} +//// val1, +////{| "indent": 8 |} +//// val2, +////{| "indent": 8 |} +//// } +////{| "indent": 4 |} +////} +//// +//// +////function controlStatements() { +//// for (var i = 0; i < 10; i++) { +////{| "indent": 4 |} +//// } +//// +//// for (var e in foo.bar) { +////{| "indent": 4 |} +//// } +//// +//// with (foo.bar) { +////{| "indent": 4 |} +//// } +//// +//// while (false) { +////{| "indent": 4 |} +//// } +//// +//// do { +////{| "indent": 4 |} +//// } while (false); +//// +//// switch (foo.bar) { +////{| "indent": 4 |} +//// } +//// +//// switch (foo.bar) { +////{| "indent": 4 |} +//// case 1: +////{| "indent": 8 |} +//// break; +//// default: +////{| "indent": 8 |} +//// break; +//// } +////} +//// +//// +////function tryCatch() { +////{| "indent": 0 |} +//// try { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +//// catch (err) { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +////} +//// +//// +////function tryFinally() { +////{| "indent": 0 |} +//// try { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +//// finally { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +////} +//// +//// +////function tryCatchFinally() { +////{| "indent": 0 |} +//// try { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +//// catch (err) { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +//// finally { +////{| "indent": 4 |} +//// } +////{| "indent": 4 |} +////} +//// +//// +////class indentBeforeCurly +////{| "indent": 0 |} +////{| "indent": 0 |}{ +////{| "indent": 0 |} +////} +//// +//// +////function argumentsListIndentation(bar, +//// blah, +//// {| "indent": 13 |} +////); +//// +//// +////function blockIndentAfterIndentedParameter1(bar, +//// blah) { +////{| "indent": 13 |} +////} +//// +//// +////function blockIndentAfterIndentedParameter2(bar, +//// blah) { +//// if (foo) { +////{| "indent": 4 |} +//// } +////} +//// +//// +////// Note: Do not add more tests at the end of this file, as +////// the purpose of this test is to verity smart indent +////// works for unterminated function arguments at the end of a file. +////function unterminatedListIndentation(a, +////{| "indent": 0 |} + +test.markers().forEach(marker => { + verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent, IndentStyle.Block); +}); diff --git a/tests/cases/fourslash/indentationNone.ts b/tests/cases/fourslash/indentationNone.ts new file mode 100644 index 00000000000..078f5ab35f6 --- /dev/null +++ b/tests/cases/fourslash/indentationNone.ts @@ -0,0 +1,183 @@ +/// + +//// +////module classes { +////{| "indent": 0 |} +//// class Bar { +////{| "indent": 0 |} +//// +//// constructor() { +////{| "indent": 0 |} +//// } +//// +//// private foo: string = ""; +////{| "indent": 0 |} +//// +//// private f() { +//// var a: any[] = [[1, 2], [3, 4], 5]; +////{| "indent": 0 |} +//// return ((1 + 1)); +//// } +//// +////{| "indent": 0 |} +//// private f2() { +//// if (true) { } { }; +//// } +//// } +////} +//// +//// +////module interfaces { +////{| "indent": 0 |} +//// interface Foo { +////{| "indent": 0 |} +//// +//// x: number; +////{| "indent": 0 |} +//// +//// foo(): number; +////{| "indent": 0 |} +//// } +////} +//// +//// +////module nestedModules { +//// module Foo2 { +////{| "indent": 0 |} +//// function f() { +//// } +////{| "indent": 0 |} +//// var x: number; +////{| "indent": 0 |} +//// } +////} +//// +//// +////module Enums { +//// enum Foo3 { +////{| "indent": 0 |} +//// val1, +////{| "indent": 0 |} +//// val2, +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +////} +//// +//// +////function controlStatements() { +//// for (var i = 0; i < 10; i++) { +////{| "indent": 0 |} +//// } +//// +//// for (var e in foo.bar) { +////{| "indent": 0 |} +//// } +//// +//// with (foo.bar) { +////{| "indent": 0 |} +//// } +//// +//// while (false) { +////{| "indent": 0 |} +//// } +//// +//// do { +////{| "indent": 0 |} +//// } while (false); +//// +//// switch (foo.bar) { +////{| "indent": 0 |} +//// } +//// +//// switch (foo.bar) { +////{| "indent": 0 |} +//// case 1: +////{| "indent": 0 |} +//// break; +//// default: +////{| "indent": 0 |} +//// break; +//// } +////} +//// +//// +////function tryCatch() { +////{| "indent": 0 |} +//// try { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +//// catch (err) { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +////} +//// +//// +////function tryFinally() { +////{| "indent": 0 |} +//// try { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +//// finally { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +////} +//// +//// +////function tryCatchFinally() { +////{| "indent": 0 |} +//// try { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +//// catch (err) { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +//// finally { +////{| "indent": 0 |} +//// } +////{| "indent": 0 |} +////} +//// +//// +////class indentBeforeCurly +////{| "indent": 0 |} +////{| "indent": 0 |}{ +////{| "indent": 0 |} +////} +//// +//// +////function argumentsListIndentation(bar, +//// blah, +//// {| "indent": 0 |} +////); +//// +//// +////function blockIndentAfterIndentedParameter1(bar, +//// blah) { +////{| "indent": 0 |} +////} +//// +//// +////function blockIndentAfterIndentedParameter2(bar, +//// blah) { +//// if (foo) { +////{| "indent": 0 |} +//// } +////} +//// +//// +////// Note: Do not add more tests at the end of this file, as +////// the purpose of this test is to verity smart indent +////// works for unterminated function arguments at the end of a file. +////function unterminatedListIndentation(a, +////{| "indent": 0 |} + +test.markers().forEach(marker => { + verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent, IndentStyle.None); +}); From a0683276d183f85a1302d52a3a2a6bbc60663d25 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 11 Oct 2015 21:57:17 -0700 Subject: [PATCH 11/15] check functions in class expressions --- src/compiler/checker.ts | 1 + .../reference/functionsInClassExpressions.js | 25 +++++++++++++++ .../functionsInClassExpressions.symbols | 27 ++++++++++++++++ .../functionsInClassExpressions.types | 32 +++++++++++++++++++ .../compiler/functionsInClassExpressions.ts | 10 ++++++ 5 files changed, 95 insertions(+) create mode 100644 tests/baselines/reference/functionsInClassExpressions.js create mode 100644 tests/baselines/reference/functionsInClassExpressions.symbols create mode 100644 tests/baselines/reference/functionsInClassExpressions.types create mode 100644 tests/cases/compiler/functionsInClassExpressions.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d4ce6655a21..b65761eb80b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13897,6 +13897,7 @@ namespace ts { break; case SyntaxKind.ClassExpression: forEach((node).members, checkSourceElement); + forEachChild(node, checkFunctionAndClassExpressionBodies); break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: diff --git a/tests/baselines/reference/functionsInClassExpressions.js b/tests/baselines/reference/functionsInClassExpressions.js new file mode 100644 index 00000000000..debd8138831 --- /dev/null +++ b/tests/baselines/reference/functionsInClassExpressions.js @@ -0,0 +1,25 @@ +//// [functionsInClassExpressions.ts] +let Foo = class { + constructor() { + this.bar++; + } + bar = 0; + inc = () => { + this.bar++; + } + m() { return this.bar; } +} + +//// [functionsInClassExpressions.js] +var Foo = (function () { + function class_1() { + var _this = this; + this.bar = 0; + this.inc = function () { + _this.bar++; + }; + this.bar++; + } + class_1.prototype.m = function () { return this.bar; }; + return class_1; +})(); diff --git a/tests/baselines/reference/functionsInClassExpressions.symbols b/tests/baselines/reference/functionsInClassExpressions.symbols new file mode 100644 index 00000000000..a1da3a3175c --- /dev/null +++ b/tests/baselines/reference/functionsInClassExpressions.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/functionsInClassExpressions.ts === +let Foo = class { +>Foo : Symbol(Foo, Decl(functionsInClassExpressions.ts, 0, 3)) + + constructor() { + this.bar++; +>this.bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this : Symbol((Anonymous class), Decl(functionsInClassExpressions.ts, 0, 9)) +>bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) + } + bar = 0; +>bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) + + inc = () => { +>inc : Symbol((Anonymous class).inc, Decl(functionsInClassExpressions.ts, 4, 12)) + + this.bar++; +>this.bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this : Symbol((Anonymous class), Decl(functionsInClassExpressions.ts, 0, 9)) +>bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) + } + m() { return this.bar; } +>m : Symbol((Anonymous class).m, Decl(functionsInClassExpressions.ts, 7, 5)) +>this.bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +>this : Symbol((Anonymous class), Decl(functionsInClassExpressions.ts, 0, 9)) +>bar : Symbol((Anonymous class).bar, Decl(functionsInClassExpressions.ts, 3, 5)) +} diff --git a/tests/baselines/reference/functionsInClassExpressions.types b/tests/baselines/reference/functionsInClassExpressions.types new file mode 100644 index 00000000000..ee4b5696cc1 --- /dev/null +++ b/tests/baselines/reference/functionsInClassExpressions.types @@ -0,0 +1,32 @@ +=== tests/cases/compiler/functionsInClassExpressions.ts === +let Foo = class { +>Foo : typeof (Anonymous class) +>class { constructor() { this.bar++; } bar = 0; inc = () => { this.bar++; } m() { return this.bar; }} : typeof (Anonymous class) + + constructor() { + this.bar++; +>this.bar++ : number +>this.bar : number +>this : this +>bar : number + } + bar = 0; +>bar : number +>0 : number + + inc = () => { +>inc : () => void +>() => { this.bar++; } : () => void + + this.bar++; +>this.bar++ : number +>this.bar : number +>this : this +>bar : number + } + m() { return this.bar; } +>m : () => number +>this.bar : number +>this : this +>bar : number +} diff --git a/tests/cases/compiler/functionsInClassExpressions.ts b/tests/cases/compiler/functionsInClassExpressions.ts new file mode 100644 index 00000000000..72e0bafd582 --- /dev/null +++ b/tests/cases/compiler/functionsInClassExpressions.ts @@ -0,0 +1,10 @@ +let Foo = class { + constructor() { + this.bar++; + } + bar = 0; + inc = () => { + this.bar++; + } + m() { return this.bar; } +} \ No newline at end of file From c35419e12e4aaeb533299b00864abfdcfbc7ef03 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 11 Oct 2015 22:19:51 -0700 Subject: [PATCH 12/15] add rule to insert space between async keyword and open paren --- src/services/formatting/rules.ts | 8 +++++++- tests/cases/fourslash/formatAsyncKeyword.ts | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/formatAsyncKeyword.ts diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index c3bc8e7802d..12efb774dd3 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -214,6 +214,7 @@ namespace ts.formatting { public SpaceBetweenYieldOrYieldStarAndOperand: Rule; // Async functions + public SpaceBetweenAsyncAndOpenParen: Rule; public SpaceBetweenAsyncAndFunctionKeyword: Rule; // Template strings @@ -369,6 +370,7 @@ namespace ts.formatting { this.SpaceBetweenYieldOrYieldStarAndOperand = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsYieldOrYieldStarWithOperand), RuleAction.Space)); // Async-await + this.SpaceBetweenAsyncAndOpenParen = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsArrowFunctionContext, Rules.IsSameLineTokenContext), RuleAction.Space)); this.SpaceBetweenAsyncAndFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); // template string @@ -402,7 +404,7 @@ namespace ts.formatting { this.NoSpaceBeforeOpenParenInFuncCall, this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator, this.SpaceAfterVoidOperator, - this.SpaceBetweenAsyncAndFunctionKeyword, + this.SpaceBetweenAsyncAndOpenParen, this.SpaceBetweenAsyncAndFunctionKeyword, this.SpaceBetweenTagAndTemplateString, this.NoSpaceAfterTemplateHeadAndMiddle, this.NoSpaceBeforeTemplateMiddleAndTail, // TypeScript-specific rules @@ -703,6 +705,10 @@ namespace ts.formatting { return context.currentTokenSpan.kind !== SyntaxKind.CommaToken; } + static IsArrowFunctionContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ArrowFunction; + } + static IsSameLineTokenContext(context: FormattingContext): boolean { return context.TokensAreOnSameLine(); } diff --git a/tests/cases/fourslash/formatAsyncKeyword.ts b/tests/cases/fourslash/formatAsyncKeyword.ts new file mode 100644 index 00000000000..305d4ea4244 --- /dev/null +++ b/tests/cases/fourslash/formatAsyncKeyword.ts @@ -0,0 +1,13 @@ +/// + +/////*1*/let x = async () => 1; +/////*2*/let y = async() => 1; +/////*3*/let z = async function () { return 1; }; + +format.document(); +goTo.marker("1"); +verify.currentLineContentIs("let x = async () => 1;"); +goTo.marker("2"); +verify.currentLineContentIs("let y = async () => 1;"); +goTo.marker("3"); +verify.currentLineContentIs("let z = async function() { return 1; };") \ No newline at end of file From adf9f9b8dfcb2a989464a4916d744a392a77b78b Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 12 Oct 2015 09:59:41 -0700 Subject: [PATCH 13/15] check initialization of exported block scoped variables --- src/compiler/checker.ts | 7 ++++-- ...exportedBlockScopedDeclarations.errors.txt | 23 +++++++++++++++++++ .../exportedBlockScopedDeclarations.js | 22 ++++++++++++++++++ .../exportedBlockScopedDeclarations.ts | 9 ++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt create mode 100644 tests/baselines/reference/exportedBlockScopedDeclarations.js create mode 100644 tests/cases/compiler/exportedBlockScopedDeclarations.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d4ce6655a21..d91ef73b819 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -610,8 +610,11 @@ namespace ts { // block - scope variable and namespace module. However, only when we // try to resolve name in /*1*/ which is used in variable position, // we want to check for block- scoped - if (meaning & SymbolFlags.BlockScopedVariable && result.flags & SymbolFlags.BlockScopedVariable) { - checkResolvedBlockScopedVariable(result, errorLocation); + if (meaning & SymbolFlags.BlockScopedVariable) { + const exportOrLocalSymbol = getExportSymbolOfValueSymbolIfExported(result); + if (exportOrLocalSymbol.flags & SymbolFlags.BlockScopedVariable) { + checkResolvedBlockScopedVariable(exportOrLocalSymbol, errorLocation); + } } } return result; diff --git a/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt b/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt new file mode 100644 index 00000000000..32136d16320 --- /dev/null +++ b/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt @@ -0,0 +1,23 @@ +tests/cases/compiler/exportedBlockScopedDeclarations.ts(1,13): error TS2448: Block-scoped variable 'foo' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(2,20): error TS2448: Block-scoped variable 'bar' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(4,15): error TS2448: Block-scoped variable 'bar' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(7,22): error TS2448: Block-scoped variable 'bar' used before its declaration. + + +==== tests/cases/compiler/exportedBlockScopedDeclarations.ts (4 errors) ==== + const foo = foo; // compile error + ~~~ +!!! error TS2448: Block-scoped variable 'foo' used before its declaration. + export const bar = bar; // should be compile error + ~~~ +!!! error TS2448: Block-scoped variable 'bar' used before its declaration. + function f() { + const bar = bar; // compile error + ~~~ +!!! error TS2448: Block-scoped variable 'bar' used before its declaration. + } + namespace NS { + export const bar = bar; // should be compile error + ~~~ +!!! error TS2448: Block-scoped variable 'bar' used before its declaration. + } \ No newline at end of file diff --git a/tests/baselines/reference/exportedBlockScopedDeclarations.js b/tests/baselines/reference/exportedBlockScopedDeclarations.js new file mode 100644 index 00000000000..c109aa7542e --- /dev/null +++ b/tests/baselines/reference/exportedBlockScopedDeclarations.js @@ -0,0 +1,22 @@ +//// [exportedBlockScopedDeclarations.ts] +const foo = foo; // compile error +export const bar = bar; // should be compile error +function f() { + const bar = bar; // compile error +} +namespace NS { + export const bar = bar; // should be compile error +} + +//// [exportedBlockScopedDeclarations.js] +define(["require", "exports"], function (require, exports) { + var foo = foo; // compile error + exports.bar = exports.bar; // should be compile error + function f() { + var bar = bar; // compile error + } + var NS; + (function (NS) { + NS.bar = NS.bar; // should be compile error + })(NS || (NS = {})); +}); diff --git a/tests/cases/compiler/exportedBlockScopedDeclarations.ts b/tests/cases/compiler/exportedBlockScopedDeclarations.ts new file mode 100644 index 00000000000..03ccff6c319 --- /dev/null +++ b/tests/cases/compiler/exportedBlockScopedDeclarations.ts @@ -0,0 +1,9 @@ +// @module: amd +const foo = foo; // compile error +export const bar = bar; // should be compile error +function f() { + const bar = bar; // compile error +} +namespace NS { + export const bar = bar; // should be compile error +} \ No newline at end of file From ca988316749b33975afeb68375df072c8c5a9a71 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 12 Oct 2015 10:22:18 -0700 Subject: [PATCH 14/15] addressed PR feedback: added tests for let declarations --- ...exportedBlockScopedDeclarations.errors.txt | 23 ++++++++++++++++++- .../exportedBlockScopedDeclarations.js | 18 +++++++++++++++ .../exportedBlockScopedDeclarations.ts | 9 ++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt b/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt index 32136d16320..06d832c86e1 100644 --- a/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt +++ b/tests/baselines/reference/exportedBlockScopedDeclarations.errors.txt @@ -2,9 +2,13 @@ tests/cases/compiler/exportedBlockScopedDeclarations.ts(1,13): error TS2448: Blo tests/cases/compiler/exportedBlockScopedDeclarations.ts(2,20): error TS2448: Block-scoped variable 'bar' used before its declaration. tests/cases/compiler/exportedBlockScopedDeclarations.ts(4,15): error TS2448: Block-scoped variable 'bar' used before its declaration. tests/cases/compiler/exportedBlockScopedDeclarations.ts(7,22): error TS2448: Block-scoped variable 'bar' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(10,12): error TS2448: Block-scoped variable 'foo1' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(11,19): error TS2448: Block-scoped variable 'bar1' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(13,14): error TS2448: Block-scoped variable 'bar1' used before its declaration. +tests/cases/compiler/exportedBlockScopedDeclarations.ts(16,21): error TS2448: Block-scoped variable 'bar1' used before its declaration. -==== tests/cases/compiler/exportedBlockScopedDeclarations.ts (4 errors) ==== +==== tests/cases/compiler/exportedBlockScopedDeclarations.ts (8 errors) ==== const foo = foo; // compile error ~~~ !!! error TS2448: Block-scoped variable 'foo' used before its declaration. @@ -20,4 +24,21 @@ tests/cases/compiler/exportedBlockScopedDeclarations.ts(7,22): error TS2448: Blo export const bar = bar; // should be compile error ~~~ !!! error TS2448: Block-scoped variable 'bar' used before its declaration. + } + + let foo1 = foo1; // compile error + ~~~~ +!!! error TS2448: Block-scoped variable 'foo1' used before its declaration. + export let bar1 = bar1; // should be compile error + ~~~~ +!!! error TS2448: Block-scoped variable 'bar1' used before its declaration. + function f1() { + let bar1 = bar1; // compile error + ~~~~ +!!! error TS2448: Block-scoped variable 'bar1' used before its declaration. + } + namespace NS1 { + export let bar1 = bar1; // should be compile error + ~~~~ +!!! error TS2448: Block-scoped variable 'bar1' used before its declaration. } \ No newline at end of file diff --git a/tests/baselines/reference/exportedBlockScopedDeclarations.js b/tests/baselines/reference/exportedBlockScopedDeclarations.js index c109aa7542e..81399ddafb5 100644 --- a/tests/baselines/reference/exportedBlockScopedDeclarations.js +++ b/tests/baselines/reference/exportedBlockScopedDeclarations.js @@ -6,6 +6,15 @@ function f() { } namespace NS { export const bar = bar; // should be compile error +} + +let foo1 = foo1; // compile error +export let bar1 = bar1; // should be compile error +function f1() { + let bar1 = bar1; // compile error +} +namespace NS1 { + export let bar1 = bar1; // should be compile error } //// [exportedBlockScopedDeclarations.js] @@ -19,4 +28,13 @@ define(["require", "exports"], function (require, exports) { (function (NS) { NS.bar = NS.bar; // should be compile error })(NS || (NS = {})); + var foo1 = foo1; // compile error + exports.bar1 = exports.bar1; // should be compile error + function f1() { + var bar1 = bar1; // compile error + } + var NS1; + (function (NS1) { + NS1.bar1 = NS1.bar1; // should be compile error + })(NS1 || (NS1 = {})); }); diff --git a/tests/cases/compiler/exportedBlockScopedDeclarations.ts b/tests/cases/compiler/exportedBlockScopedDeclarations.ts index 03ccff6c319..f7a0216e8be 100644 --- a/tests/cases/compiler/exportedBlockScopedDeclarations.ts +++ b/tests/cases/compiler/exportedBlockScopedDeclarations.ts @@ -6,4 +6,13 @@ function f() { } namespace NS { export const bar = bar; // should be compile error +} + +let foo1 = foo1; // compile error +export let bar1 = bar1; // should be compile error +function f1() { + let bar1 = bar1; // compile error +} +namespace NS1 { + export let bar1 = bar1; // should be compile error } \ No newline at end of file From de5286524328d02045e582ebd2d288f178c81139 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Mon, 12 Oct 2015 11:35:36 -0700 Subject: [PATCH 15/15] Remove prototype from NodeFilter static type --- src/lib/dom.generated.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index dbf9dc23532..fa985344412 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -7897,7 +7897,6 @@ interface NodeFilter { } declare var NodeFilter: { - prototype: NodeFilter; FILTER_ACCEPT: number; FILTER_REJECT: number; FILTER_SKIP: number;