From 259f8a2091e5cea2a27c758e4619454341a7eb69 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 23 Jul 2014 10:40:39 -0700 Subject: [PATCH 1/7] enabled strict mode --- .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 5 +- src/compiler/emitter.ts | 3 +- src/compiler/parser.ts | 162 ++++++++++++++++-- src/compiler/types.ts | 4 +- ...onstructorStaticParamNameErrors.errors.txt | 8 + .../constructorStaticParamNameErrors.js | 14 -- ...duplicatePropertiesInStrictMode.errors.txt | 10 ++ .../reference/parser10.1.1-8gs.errors.txt | 8 +- tests/baselines/reference/parser10.1.1-8gs.js | 25 --- .../reference/parser642331_1.errors.txt | 9 + tests/baselines/reference/parser642331_1.js | 15 -- .../reference/parserStrictMode10.errors.txt | 6 + .../baselines/reference/parserStrictMode10.js | 9 - .../reference/parserStrictMode11.errors.txt | 6 + .../baselines/reference/parserStrictMode11.js | 9 - .../reference/parserStrictMode12.errors.txt | 4 +- .../reference/parserStrictMode13.errors.txt | 8 + .../baselines/reference/parserStrictMode13.js | 13 -- .../reference/parserStrictMode14.errors.txt | 7 +- .../baselines/reference/parserStrictMode14.js | 9 - .../reference/parserStrictMode2.errors.txt | 6 +- .../baselines/reference/parserStrictMode2.js | 13 -- .../reference/parserStrictMode3.errors.txt | 4 +- .../baselines/reference/parserStrictMode3.js | 7 - .../reference/parserStrictMode4.errors.txt | 4 +- .../baselines/reference/parserStrictMode4.js | 7 - .../reference/parserStrictMode5.errors.txt | 4 +- .../baselines/reference/parserStrictMode5.js | 7 - .../reference/parserStrictMode6.errors.txt | 4 +- .../baselines/reference/parserStrictMode6.js | 7 - .../reference/parserStrictMode8.errors.txt | 4 +- .../baselines/reference/parserStrictMode8.js | 9 - .../reference/parserStrictMode9.errors.txt | 6 + .../baselines/reference/parserStrictMode9.js | 9 - .../reference/scanner10.1.1-8gs.errors.txt | 8 +- .../baselines/reference/scanner10.1.1-8gs.js | 25 --- .../duplicatePropertiesInStrictMode.ts | 5 + 38 files changed, 250 insertions(+), 214 deletions(-) create mode 100644 tests/baselines/reference/constructorStaticParamNameErrors.errors.txt delete mode 100644 tests/baselines/reference/constructorStaticParamNameErrors.js create mode 100644 tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt delete mode 100644 tests/baselines/reference/parser10.1.1-8gs.js create mode 100644 tests/baselines/reference/parser642331_1.errors.txt delete mode 100644 tests/baselines/reference/parser642331_1.js create mode 100644 tests/baselines/reference/parserStrictMode10.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode10.js create mode 100644 tests/baselines/reference/parserStrictMode11.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode11.js create mode 100644 tests/baselines/reference/parserStrictMode13.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode13.js delete mode 100644 tests/baselines/reference/parserStrictMode14.js delete mode 100644 tests/baselines/reference/parserStrictMode2.js delete mode 100644 tests/baselines/reference/parserStrictMode3.js delete mode 100644 tests/baselines/reference/parserStrictMode4.js delete mode 100644 tests/baselines/reference/parserStrictMode5.js delete mode 100644 tests/baselines/reference/parserStrictMode6.js delete mode 100644 tests/baselines/reference/parserStrictMode8.js create mode 100644 tests/baselines/reference/parserStrictMode9.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode9.js delete mode 100644 tests/baselines/reference/scanner10.1.1-8gs.js create mode 100644 tests/cases/compiler/duplicatePropertiesInStrictMode.ts diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 1abf9888346..c1ef78440ba 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -99,6 +99,7 @@ module ts { A_constructor_implementation_cannot_be_declared_in_an_ambient_context: { code: 1111, category: DiagnosticCategory.Error, key: "A constructor implementation cannot be declared in an ambient context." }, A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." }, A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." }, + Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "Object literal cannot contain more than one property with the same name in the strict mode." }, Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array()' instead." }, Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 58b6d410998..ca78672ac00 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -388,7 +388,10 @@ "category": "Error", "code": 1113 }, - + "Object literal cannot contain more than one property with the same name in the strict mode.": { + "category": "Error", + "code": 1114 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2000 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 90661c08fc0..d1e2367babb 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1669,8 +1669,7 @@ module ts { function emitDirectivePrologues(statements: Statement[], startWithNewLine: boolean): number { for (var i = 0; i < statements.length; ++i) { - if (statements[i].kind === SyntaxKind.ExpressionStatement && - (statements[i]).expression.kind === SyntaxKind.StringLiteral) { + if (isPrologueDirective(statements[i])) { if (startWithNewLine || i > 0) { writeLine(); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 67b0e2f9dac..dc766b0e89e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -119,6 +119,21 @@ module ts { return file.externalModuleIndicator !== undefined; } + export function isPrologueDirective(node: Node): boolean { + return node.kind === SyntaxKind.ExpressionStatement && (node).expression.kind === SyntaxKind.StringLiteral; + } + + function isEvalOrArgumentsIdentifier(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && + (node).text && + ((node).text === "eval" || (node).text === "arguments") + } + + /// Should be called only on prologue directives (isPrologueDirective(node) should be true) + function isUseStrictPrologueDirective(node: Node): boolean { + return ((node).expression).text === "use strict"; + } + // Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes // stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, // embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns @@ -383,6 +398,7 @@ module ts { var identifierCount = 0; var nodeCount = 0; var lineStarts: number[]; + var isInStrictMode = false; var lookAheadMode = LookAheadMode.NotLookingAhead; var inAmbientContext = false; @@ -418,6 +434,13 @@ module ts { file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2)); } + function reportInvalidUseInStrictMode(node: Identifier): void { + // identifierToString cannot be used here since it uses backreference to 'parent' that is not yet set + var name = sourceText.substring(skipTrivia(sourceText, node.pos), node.end); + grammarErrorOnNode(node, Diagnostics.Invalid_use_of_0_in_strict_mode, name); + } + + function grammarErrorAtPos(start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2)); } @@ -522,7 +545,7 @@ module ts { } function isIdentifier(): boolean { - return token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord; + return token === SyntaxKind.Identifier || (isInStrictMode ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord); } function isSemicolon(): boolean { @@ -767,14 +790,27 @@ module ts { } // Parses a list of elements - function parseList(kind: ParsingContext, parseElement: () => T): NodeArray { + function parseList(kind: ParsingContext, checkForStrictMode: boolean, parseElement: () => T): NodeArray { var saveParsingContext = parsingContext; parsingContext |= 1 << kind; var result = >[]; result.pos = getNodePos(); + var saveIsInStrictMode = isInStrictMode; while (!isListTerminator(kind)) { if (isListElement(kind, /* inErrorRecovery */ false)) { - result.push(parseElement()); + var element = parseElement(); + result.push(element); + if (!isInStrictMode && checkForStrictMode) { + if (isPrologueDirective(element)) { + if (isUseStrictPrologueDirective(element)) { + isInStrictMode = true; + checkForStrictMode = false; + } + } + else { + checkForStrictMode = false; + } + } } else { error(parsingContextErrors(kind)); @@ -784,6 +820,7 @@ module ts { nextToken(); } } + isInStrictMode = saveIsInStrictMode; result.end = getNodeEnd(); parsingContext = saveParsingContext; return result; @@ -968,6 +1005,18 @@ module ts { node.flags |= NodeFlags.Rest; } node.name = parseIdentifier(); + if (node.name.kind === SyntaxKind.Missing && node.flags === 0 && isModifier(token)) { + // in cases like + // 'use strict' + // function foo(static) + // isParameter('static') === true, because of isModifier('static') + // however 'static' is not a legal identifier in a strict mode. + // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) + // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) + // to avoid this we'll advance cursor to the next token. + nextToken(); + } + if (parseOptional(SyntaxKind.QuestionToken)) { node.flags |= NodeFlags.QuestionMark; } @@ -1012,8 +1061,16 @@ module ts { for (var i = 0; i < parameterCount; i++) { var parameter = parameters[i]; - - if (parameter.flags & NodeFlags.Rest) { + // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the + // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code + // or if its FunctionBody is strict code(11.1.5). + // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a + // strict mode FunctionDeclaration or FunctionExpression(13.1) + if (isInStrictMode && isEvalOrArgumentsIdentifier(parameter.name)) { + reportInvalidUseInStrictMode(parameter.name); + return; + } + else if (parameter.flags & NodeFlags.Rest) { if (i !== (parameterCount - 1)) { grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); return; @@ -1170,7 +1227,7 @@ module ts { function parseTypeLiteral(): TypeLiteralNode { var node = createNode(SyntaxKind.TypeLiteral); if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.members = parseList(ParsingContext.TypeMembers, parseTypeMember); + node.members = parseList(ParsingContext.TypeMembers, /*checkForStrictMode*/ false, parseTypeMember); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -1360,6 +1417,11 @@ module ts { // If the expression was a LHS expression, and we have an assignment operator, then // we're in '2' or '3'. Consume the assignement and return. if (isLeftHandSideExpression(expr) && isAssignmentOperator()) { + if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) { + // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) + reportInvalidUseInStrictMode(expr); + } var operator = token; nextToken(); return makeBinaryExpression(expr, operator, parseAssignmentExpression(noIn)); @@ -1659,6 +1721,19 @@ module ts { var operator = token; nextToken(); var operand = parseUnaryExpression(); + if (isInStrictMode) { + // The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression + // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator + if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && isEvalOrArgumentsIdentifier(operand)) { + reportInvalidUseInStrictMode(operand); + } + else if (token === SyntaxKind.DeleteKeyword && operand.kind === SyntaxKind.Identifier) { + // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its + // UnaryExpression is a direct reference to a variable, function argument, or function name + grammarErrorOnNode(operand, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode); + } + } return makeUnaryExpression(SyntaxKind.PrefixOperator, pos, operator, operand); case SyntaxKind.LessThanToken: return parseTypeAssertion(); @@ -1680,6 +1755,12 @@ module ts { Debug.assert(isLeftHandSideExpression(expr)); if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { + // The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression + // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator. + if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) { + reportInvalidUseInStrictMode(expr); + } var operator = token; nextToken(); expr = makeUnaryExpression(SyntaxKind.PostfixOperator, expr.pos, operator, expr); @@ -1866,6 +1947,23 @@ module ts { if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, TrailingCommaBehavior.Preserve); parseExpected(SyntaxKind.CloseBraceToken); + if (isInStrictMode) { + var seen: Map = {}; + forEach(node.properties, (p: Node) => { + // 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 IsDataDescriptor(propId.descriptor) is true. + if (p.kind === SyntaxKind.PropertyAssignment) { + var name = (p).name; + if (hasProperty(seen, name.text)) { + grammarErrorOnNode(name, Diagnostics.Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode); + } + else { + seen[name.text] = true; + } + } + }); + } return finishNode(node); } @@ -1875,6 +1973,11 @@ module ts { var name = isIdentifier() ? parseIdentifier() : undefined; var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); var body = parseBody(/* ignoreMissingOpenBrace */ false); + if (name && isInStrictMode && isEvalOrArgumentsIdentifier(name)) { + // It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the + // Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name(13.1) + reportInvalidUseInStrictMode(name); + } return makeFunctionExpression(SyntaxKind.FunctionExpression, pos, name, sig, body); } @@ -1901,10 +2004,10 @@ module ts { // STATEMENTS - function parseBlock(ignoreMissingOpenBrace: boolean): Block { + function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean): Block { var node = createNode(SyntaxKind.Block); if (parseExpected(SyntaxKind.OpenBraceToken) || ignoreMissingOpenBrace) { - node.statements = parseList(ParsingContext.BlockStatements, parseStatement); + node.statements = parseList(ParsingContext.BlockStatements,checkForStrictMode, parseStatement); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -1914,7 +2017,7 @@ module ts { } function parseBody(ignoreMissingOpenBrace: boolean): Block { - var block = parseBlock(ignoreMissingOpenBrace); + var block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true); block.kind = SyntaxKind.FunctionBlock; return block; } @@ -2035,7 +2138,13 @@ module ts { node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); node.statement = parseStatement(); - return finishNode(node); + node = finishNode(node); + if (isInStrictMode) { + // Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such + // a context is an SyntaxError(12.10) + grammarErrorOnNode(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); + } + return node; } function parseCaseClause(): CaseOrDefaultClause { @@ -2043,7 +2152,7 @@ module ts { parseExpected(SyntaxKind.CaseKeyword); node.expression = parseExpression(); parseExpected(SyntaxKind.ColonToken); - node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); + node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement); return finishNode(node); } @@ -2051,7 +2160,7 @@ module ts { var node = createNode(SyntaxKind.DefaultClause); parseExpected(SyntaxKind.DefaultKeyword); parseExpected(SyntaxKind.ColonToken); - node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); + node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement); return finishNode(node); } @@ -2066,7 +2175,7 @@ module ts { node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); parseExpected(SyntaxKind.OpenBraceToken); - node.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); + node.clauses = parseList(ParsingContext.SwitchClauses, /*checkForStrictMode*/ false, parseCaseOrDefaultClause); parseExpected(SyntaxKind.CloseBraceToken); // Error on duplicate 'default' clauses. @@ -2111,7 +2220,7 @@ module ts { function parseTokenAndBlock(token: SyntaxKind, kind: SyntaxKind): Block { var pos = getNodePos(); parseExpected(token); - var result = parseBlock(/* ignoreMissingOpenBrace */ false); + var result = parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); result.kind = kind; result.pos = pos; return result; @@ -2126,7 +2235,7 @@ module ts { var typeAnnotationColonLength = scanner.getTextPos() - typeAnnotationColonStart; var typeAnnotation = parseTypeAnnotation(); parseExpected(SyntaxKind.CloseParenToken); - var result = parseBlock(/* ignoreMissingOpenBrace */ false); + var result = parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); result.kind = SyntaxKind.CatchBlock; result.pos = pos; result.variable = variable; @@ -2134,6 +2243,11 @@ module ts { if (typeAnnotation) { errorAtPos(typeAnnotationColonStart, typeAnnotationColonLength, Diagnostics.Catch_clause_parameter_cannot_have_a_type_annotation); } + if (isInStrictMode && isEvalOrArgumentsIdentifier(variable)) { + // It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the + // Catch production is eval or arguments + reportInvalidUseInStrictMode(variable); + } return result; } @@ -2206,7 +2320,7 @@ module ts { function parseStatement(): Statement { switch (token) { case SyntaxKind.OpenBraceToken: - return parseBlock(/* ignoreMissingOpenBrace */ false); + return parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); case SyntaxKind.VarKeyword: return parseVariableStatement(); case SyntaxKind.FunctionKeyword: @@ -2284,6 +2398,11 @@ module ts { if (inAmbientContext && node.initializer && errorCountBeforeVariableDeclaration === file.syntacticErrors.length) { grammarErrorAtPos(initializerStart, initializerFirstTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); } + if (isInStrictMode && isEvalOrArgumentsIdentifier(node.name)) { + // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code + // and its Identifier is eval or arguments + reportInvalidUseInStrictMode(node.name); + } return finishNode(node); } @@ -2314,6 +2433,11 @@ module ts { node.parameters = sig.parameters; node.type = sig.type; node.body = parseAndCheckFunctionBody(/*isConstructor*/ false); + if (isInStrictMode && isEvalOrArgumentsIdentifier(node.name)) { + // It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the + // Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name(13.1) + reportInvalidUseInStrictMode(node.name); + } return finishNode(node); } @@ -2656,7 +2780,7 @@ module ts { } var errorCountBeforeClassBody = file.syntacticErrors.length; if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.members = parseList(ParsingContext.ClassMembers, parseClassMemberDeclaration); + node.members = parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassMemberDeclaration); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -2756,7 +2880,7 @@ module ts { function parseModuleBody(): Block { var node = createNode(SyntaxKind.ModuleBlock); if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.statements = parseList(ParsingContext.ModuleElements, parseModuleElement); + node.statements = parseList(ParsingContext.ModuleElements, /*checkForStrictMode*/ false, parseModuleElement); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -3013,7 +3137,7 @@ module ts { var referenceComments = processReferenceComments(); file.referencedFiles = referenceComments.referencedFiles; file.amdDependencies = referenceComments.amdDependencies; - file.statements = parseList(ParsingContext.SourceElements, parseSourceElement); + file.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); file.externalModuleIndicator = getExternalModuleIndicator(); file.nodeCount = nodeCount; file.identifierCount = identifierCount; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5decadcfe17..545e6d60310 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -215,7 +215,9 @@ module ts { FirstReservedWord = BreakKeyword, LastReservedWord = WithKeyword, FirstKeyword = BreakKeyword, - LastKeyword = StringKeyword + LastKeyword = StringKeyword, + FirstFutureReservedWord = ImplementsKeyword, + LastFutureReservedWord = YieldKeyword } export enum NodeFlags { diff --git a/tests/baselines/reference/constructorStaticParamNameErrors.errors.txt b/tests/baselines/reference/constructorStaticParamNameErrors.errors.txt new file mode 100644 index 00000000000..494c28e89e9 --- /dev/null +++ b/tests/baselines/reference/constructorStaticParamNameErrors.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/compiler/constructorStaticParamNameErrors.ts (1 errors) ==== + 'use strict' + // static as constructor parameter name should give error if 'use strict' + class test { + constructor (static) { } + ~~~~~~ +!!! Identifier expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/constructorStaticParamNameErrors.js b/tests/baselines/reference/constructorStaticParamNameErrors.js deleted file mode 100644 index 0db6b5aa995..00000000000 --- a/tests/baselines/reference/constructorStaticParamNameErrors.js +++ /dev/null @@ -1,14 +0,0 @@ -//// [constructorStaticParamNameErrors.ts] -'use strict' -// static as constructor parameter name should give error if 'use strict' -class test { - constructor (static) { } -} - -//// [constructorStaticParamNameErrors.js] -'use strict'; -var test = (function () { - function test(static) { - } - return test; -})(); diff --git a/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt new file mode 100644 index 00000000000..ba6ab28d777 --- /dev/null +++ b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt @@ -0,0 +1,10 @@ +==== tests/cases/compiler/duplicatePropertiesInStrictMode.ts (2 errors) ==== + "use strict"; + var x = { + x: 1, + x: 2 + ~ +!!! Object literal cannot contain more than one property with the same name in the strict mode. + ~ +!!! Duplicate identifier 'x'. + } \ No newline at end of file diff --git a/tests/baselines/reference/parser10.1.1-8gs.errors.txt b/tests/baselines/reference/parser10.1.1-8gs.errors.txt index 4482dd6f1d3..4ed4b8b2635 100644 --- a/tests/baselines/reference/parser10.1.1-8gs.errors.txt +++ b/tests/baselines/reference/parser10.1.1-8gs.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/parser10.1.1-8gs.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/parser10.1.1-8gs.ts (4 errors) ==== /// Copyright (c) 2012 Ecma International. All rights reserved. /// Ecma International makes this code available under the terms and conditions set /// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the @@ -18,4 +18,10 @@ ~~~~~~~~~~~~~ !!! Cannot find name 'NotEarlyError'. var public = 1; + ~~~~~~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/parser10.1.1-8gs.js b/tests/baselines/reference/parser10.1.1-8gs.js deleted file mode 100644 index 6c04bffc223..00000000000 --- a/tests/baselines/reference/parser10.1.1-8gs.js +++ /dev/null @@ -1,25 +0,0 @@ -//// [parser10.1.1-8gs.ts] -/// Copyright (c) 2012 Ecma International. All rights reserved. -/// Ecma International makes this code available under the terms and conditions set -/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the -/// "Use Terms"). Any redistribution of this code must retain the above -/// copyright and this notice and otherwise comply with the Use Terms. - -/** - * @path ch10/10.1/10.1.1/10.1.1-8gs.js - * @description Strict Mode - Use Strict Directive Prologue is ''use strict';' which appears twice in the code - * @noStrict - * @negative ^((?!NotEarlyError).)*$ - */ - -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; - - -//// [parser10.1.1-8gs.js] -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; diff --git a/tests/baselines/reference/parser642331_1.errors.txt b/tests/baselines/reference/parser642331_1.errors.txt new file mode 100644 index 00000000000..3556849b806 --- /dev/null +++ b/tests/baselines/reference/parser642331_1.errors.txt @@ -0,0 +1,9 @@ +==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser642331_1.ts (1 errors) ==== + "use strict"; + + class test { + constructor (static) { } + ~~~~~~ +!!! Identifier expected. + } + \ No newline at end of file diff --git a/tests/baselines/reference/parser642331_1.js b/tests/baselines/reference/parser642331_1.js deleted file mode 100644 index 83833ee6612..00000000000 --- a/tests/baselines/reference/parser642331_1.js +++ /dev/null @@ -1,15 +0,0 @@ -//// [parser642331_1.ts] -"use strict"; - -class test { - constructor (static) { } -} - - -//// [parser642331_1.js] -"use strict"; -var test = (function () { - function test(static) { - } - return test; -})(); diff --git a/tests/baselines/reference/parserStrictMode10.errors.txt b/tests/baselines/reference/parserStrictMode10.errors.txt new file mode 100644 index 00000000000..a887f9bdade --- /dev/null +++ b/tests/baselines/reference/parserStrictMode10.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode10.ts (1 errors) ==== + "use strict"; + function f(eval) { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + } \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode10.js b/tests/baselines/reference/parserStrictMode10.js deleted file mode 100644 index 53ec7686d0e..00000000000 --- a/tests/baselines/reference/parserStrictMode10.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode10.ts] -"use strict"; -function f(eval) { -} - -//// [parserStrictMode10.js] -"use strict"; -function f(eval) { -} diff --git a/tests/baselines/reference/parserStrictMode11.errors.txt b/tests/baselines/reference/parserStrictMode11.errors.txt new file mode 100644 index 00000000000..1dc4e0943e4 --- /dev/null +++ b/tests/baselines/reference/parserStrictMode11.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode11.ts (1 errors) ==== + "use strict"; + var v = function f(eval) { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + }; \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode11.js b/tests/baselines/reference/parserStrictMode11.js deleted file mode 100644 index b34af107f83..00000000000 --- a/tests/baselines/reference/parserStrictMode11.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode11.ts] -"use strict"; -var v = function f(eval) { -}; - -//// [parserStrictMode11.js] -"use strict"; -var v = function f(eval) { -}; diff --git a/tests/baselines/reference/parserStrictMode12.errors.txt b/tests/baselines/reference/parserStrictMode12.errors.txt index 6a04944298f..0d50bc4d87b 100644 --- a/tests/baselines/reference/parserStrictMode12.errors.txt +++ b/tests/baselines/reference/parserStrictMode12.errors.txt @@ -1,5 +1,5 @@ ==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode12.ts (1 errors) ==== "use strict"; var v = { set foo(eval) { } } - ~~~ -!!! Accessors are only available when targeting ECMAScript 5 and higher. \ No newline at end of file + ~~~~ +!!! Invalid use of 'eval' in strict mode. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode13.errors.txt b/tests/baselines/reference/parserStrictMode13.errors.txt new file mode 100644 index 00000000000..49e1e509ca3 --- /dev/null +++ b/tests/baselines/reference/parserStrictMode13.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode13.ts (1 errors) ==== + "use strict"; + try { + } + catch(eval) { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + } \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode13.js b/tests/baselines/reference/parserStrictMode13.js deleted file mode 100644 index c3ace6981f4..00000000000 --- a/tests/baselines/reference/parserStrictMode13.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parserStrictMode13.ts] -"use strict"; -try { -} -catch(eval) { -} - -//// [parserStrictMode13.js] -"use strict"; -try { -} -catch (eval) { -} diff --git a/tests/baselines/reference/parserStrictMode14.errors.txt b/tests/baselines/reference/parserStrictMode14.errors.txt index 6c5793f2772..03cfba0b88e 100644 --- a/tests/baselines/reference/parserStrictMode14.errors.txt +++ b/tests/baselines/reference/parserStrictMode14.errors.txt @@ -1,6 +1,9 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (2 errors) ==== "use strict"; with (a) { + ~~~~~~~~~~ ~ !!! Cannot find name 'a'. - } \ No newline at end of file + } + ~ +!!! 'with' statements are not allowed in strict mode. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode14.js b/tests/baselines/reference/parserStrictMode14.js deleted file mode 100644 index eda7f285f71..00000000000 --- a/tests/baselines/reference/parserStrictMode14.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode14.ts] -"use strict"; -with (a) { -} - -//// [parserStrictMode14.js] -"use strict"; -with (a) { -} diff --git a/tests/baselines/reference/parserStrictMode2.errors.txt b/tests/baselines/reference/parserStrictMode2.errors.txt index 9ed56baa7b3..98563258c11 100644 --- a/tests/baselines/reference/parserStrictMode2.errors.txt +++ b/tests/baselines/reference/parserStrictMode2.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode2.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode2.ts (5 errors) ==== "use strict"; foo1(); ~~~~ @@ -11,4 +11,6 @@ !!! Cannot find name 'foo1'. static(); ~~~~~~ -!!! Cannot find name 'static'. \ No newline at end of file +!!! Declaration or statement expected. + ~ +!!! '=>' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode2.js b/tests/baselines/reference/parserStrictMode2.js deleted file mode 100644 index 79b32ed9a58..00000000000 --- a/tests/baselines/reference/parserStrictMode2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parserStrictMode2.ts] -"use strict"; -foo1(); -foo1(); -foo1(); -static(); - -//// [parserStrictMode2.js] -"use strict"; -foo1(); -foo1(); -foo1(); -static(); diff --git a/tests/baselines/reference/parserStrictMode3.errors.txt b/tests/baselines/reference/parserStrictMode3.errors.txt index 9631404b9d5..ab67566a841 100644 --- a/tests/baselines/reference/parserStrictMode3.errors.txt +++ b/tests/baselines/reference/parserStrictMode3.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode3.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode3.ts (2 errors) ==== "use strict"; eval = 1; ~~~~ +!!! Invalid use of 'eval' in strict mode. + ~~~~ !!! Invalid left-hand side of assignment expression. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode3.js b/tests/baselines/reference/parserStrictMode3.js deleted file mode 100644 index 166d8905a7a..00000000000 --- a/tests/baselines/reference/parserStrictMode3.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode3.ts] -"use strict"; -eval = 1; - -//// [parserStrictMode3.js] -"use strict"; -eval = 1; diff --git a/tests/baselines/reference/parserStrictMode4.errors.txt b/tests/baselines/reference/parserStrictMode4.errors.txt index 173c86131b4..e73d99fcaec 100644 --- a/tests/baselines/reference/parserStrictMode4.errors.txt +++ b/tests/baselines/reference/parserStrictMode4.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode4.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode4.ts (2 errors) ==== "use strict"; arguments = 1; ~~~~~~~~~ +!!! Invalid use of 'arguments' in strict mode. + ~~~~~~~~~ !!! Cannot find name 'arguments'. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode4.js b/tests/baselines/reference/parserStrictMode4.js deleted file mode 100644 index ff1ed9b3a8f..00000000000 --- a/tests/baselines/reference/parserStrictMode4.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode4.ts] -"use strict"; -arguments = 1; - -//// [parserStrictMode4.js] -"use strict"; -arguments = 1; diff --git a/tests/baselines/reference/parserStrictMode5.errors.txt b/tests/baselines/reference/parserStrictMode5.errors.txt index 1c0cf2da223..0cb96d4a4a2 100644 --- a/tests/baselines/reference/parserStrictMode5.errors.txt +++ b/tests/baselines/reference/parserStrictMode5.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode5.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode5.ts (2 errors) ==== "use strict"; eval += 1; + ~~~~ +!!! Invalid use of 'eval' in strict mode. ~~~~~~~~~ !!! Operator '+=' cannot be applied to types '(x: string) => any' and 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode5.js b/tests/baselines/reference/parserStrictMode5.js deleted file mode 100644 index 7e01b0f5d72..00000000000 --- a/tests/baselines/reference/parserStrictMode5.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode5.ts] -"use strict"; -eval += 1; - -//// [parserStrictMode5.js] -"use strict"; -eval += 1; diff --git a/tests/baselines/reference/parserStrictMode6.errors.txt b/tests/baselines/reference/parserStrictMode6.errors.txt index 4dc330e46e8..2d3aef69770 100644 --- a/tests/baselines/reference/parserStrictMode6.errors.txt +++ b/tests/baselines/reference/parserStrictMode6.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode6.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode6.ts (2 errors) ==== "use strict"; eval++; ~~~~ +!!! Invalid use of 'eval' in strict mode. + ~~~~ !!! An arithmetic operand must be of type 'any', 'number' or an enum type. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode6.js b/tests/baselines/reference/parserStrictMode6.js deleted file mode 100644 index 6a4161c3dab..00000000000 --- a/tests/baselines/reference/parserStrictMode6.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode6.ts] -"use strict"; -eval++; - -//// [parserStrictMode6.js] -"use strict"; -eval++; diff --git a/tests/baselines/reference/parserStrictMode8.errors.txt b/tests/baselines/reference/parserStrictMode8.errors.txt index eebb5d59f7d..366b4059010 100644 --- a/tests/baselines/reference/parserStrictMode8.errors.txt +++ b/tests/baselines/reference/parserStrictMode8.errors.txt @@ -1,6 +1,8 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode8.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode8.ts (2 errors) ==== "use strict"; function eval() { ~~~~ +!!! Invalid use of 'eval' in strict mode. + ~~~~ !!! Overload signatures must all be ambient or non-ambient. } \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode8.js b/tests/baselines/reference/parserStrictMode8.js deleted file mode 100644 index 3db5349c459..00000000000 --- a/tests/baselines/reference/parserStrictMode8.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode8.ts] -"use strict"; -function eval() { -} - -//// [parserStrictMode8.js] -"use strict"; -function eval() { -} diff --git a/tests/baselines/reference/parserStrictMode9.errors.txt b/tests/baselines/reference/parserStrictMode9.errors.txt new file mode 100644 index 00000000000..769c69a3943 --- /dev/null +++ b/tests/baselines/reference/parserStrictMode9.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode9.ts (1 errors) ==== + "use strict"; + var v = function eval() { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + }; \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode9.js b/tests/baselines/reference/parserStrictMode9.js deleted file mode 100644 index a30008634c5..00000000000 --- a/tests/baselines/reference/parserStrictMode9.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode9.ts] -"use strict"; -var v = function eval() { -}; - -//// [parserStrictMode9.js] -"use strict"; -var v = function eval() { -}; diff --git a/tests/baselines/reference/scanner10.1.1-8gs.errors.txt b/tests/baselines/reference/scanner10.1.1-8gs.errors.txt index 53fb3724e14..e69d84be612 100644 --- a/tests/baselines/reference/scanner10.1.1-8gs.errors.txt +++ b/tests/baselines/reference/scanner10.1.1-8gs.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/scanner/ecmascript5/scanner10.1.1-8gs.ts (1 errors) ==== +==== tests/cases/conformance/scanner/ecmascript5/scanner10.1.1-8gs.ts (4 errors) ==== /// Copyright (c) 2012 Ecma International. All rights reserved. /// Ecma International makes this code available under the terms and conditions set /// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the @@ -18,4 +18,10 @@ ~~~~~~~~~~~~~ !!! Cannot find name 'NotEarlyError'. var public = 1; + ~~~~~~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/scanner10.1.1-8gs.js b/tests/baselines/reference/scanner10.1.1-8gs.js deleted file mode 100644 index 85dada5e793..00000000000 --- a/tests/baselines/reference/scanner10.1.1-8gs.js +++ /dev/null @@ -1,25 +0,0 @@ -//// [scanner10.1.1-8gs.ts] -/// Copyright (c) 2012 Ecma International. All rights reserved. -/// Ecma International makes this code available under the terms and conditions set -/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the -/// "Use Terms"). Any redistribution of this code must retain the above -/// copyright and this notice and otherwise comply with the Use Terms. - -/** - * @path ch10/10.1/10.1.1/10.1.1-8gs.js - * @description Strict Mode - Use Strict Directive Prologue is ''use strict';' which appears twice in the code - * @noStrict - * @negative ^((?!NotEarlyError).)*$ - */ - -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; - - -//// [scanner10.1.1-8gs.js] -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; diff --git a/tests/cases/compiler/duplicatePropertiesInStrictMode.ts b/tests/cases/compiler/duplicatePropertiesInStrictMode.ts new file mode 100644 index 00000000000..bea869f93a4 --- /dev/null +++ b/tests/cases/compiler/duplicatePropertiesInStrictMode.ts @@ -0,0 +1,5 @@ +"use strict"; +var x = { + x: 1, + x: 2 +} \ No newline at end of file From ddfd0fe0740f17648efcd48d0a3638972df65fd7 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 23 Jul 2014 16:45:23 -0700 Subject: [PATCH 2/7] update check for object literal properties according to ECMA spec --- .../diagnosticInformationMap.generated.ts | 4 +- src/compiler/diagnosticMessages.json | 10 +- src/compiler/parser.ts | 77 +++++++--- .../duplicateObjectLiteralProperty.errors.txt | 4 +- ...duplicatePropertiesInStrictMode.errors.txt | 2 +- .../reference/objectLiteralErrors.errors.txt | 38 ++++- .../reference/objectLiteralErrors.js | 135 ------------------ .../reference/parserStrictMode14.errors.txt | 7 +- .../twoAccessorsWithSameName.errors.txt | 4 +- 9 files changed, 118 insertions(+), 163 deletions(-) delete mode 100644 tests/baselines/reference/objectLiteralErrors.js diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index c1ef78440ba..af0a838843a 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -99,7 +99,9 @@ module ts { A_constructor_implementation_cannot_be_declared_in_an_ambient_context: { code: 1111, category: DiagnosticCategory.Error, key: "A constructor implementation cannot be declared in an ambient context." }, A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." }, A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." }, - Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "Object literal cannot contain more than one property with the same name in the strict mode." }, + An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple properties with the same name in strict mode." }, + An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name: { code: 1115, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple get/set accessors with the same name." }, + An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1116, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." }, Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array()' instead." }, Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ca78672ac00..e135b1de8a3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -388,10 +388,18 @@ "category": "Error", "code": 1113 }, - "Object literal cannot contain more than one property with the same name in the strict mode.": { + "An object literal cannot have multiple properties with the same name in strict mode.": { "category": "Error", "code": 1114 }, + "An object literal cannot have multiple get/set accessors with the same name.": { + "category": "Error", + "code": 1115 + }, + "An object literal cannot have property and accessor with the same name.": { + "category": "Error", + "code": 1116 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2000 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index dc766b0e89e..7778763b3ea 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -131,6 +131,7 @@ module ts { /// Should be called only on prologue directives (isPrologueDirective(node) should be true) function isUseStrictPrologueDirective(node: Node): boolean { + Debug.assert(isPrologueDirective(node)); return ((node).expression).text === "use strict"; } @@ -1415,7 +1416,7 @@ module ts { // Now see if we might be in cases '2' or '3'. // If the expression was a LHS expression, and we have an assignment operator, then - // we're in '2' or '3'. Consume the assignement and return. + // we're in '2' or '3'. Consume the assignment and return. if (isLeftHandSideExpression(expr) && isAssignmentOperator()) { if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) { // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an @@ -1947,23 +1948,61 @@ module ts { if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, TrailingCommaBehavior.Preserve); parseExpected(SyntaxKind.CloseBraceToken); - if (isInStrictMode) { - var seen: Map = {}; - forEach(node.properties, (p: Node) => { - // 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 IsDataDescriptor(propId.descriptor) is true. - if (p.kind === SyntaxKind.PropertyAssignment) { - var name = (p).name; - if (hasProperty(seen, name.text)) { - grammarErrorOnNode(name, Diagnostics.Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode); - } - else { - seen[name.text] = true; + + var seen: Map = {}; + var Property = 1; + var GetAccessor = 2; + var SetAccesor = 4; + var GetOrSetAccessor = GetAccessor | SetAccesor; + forEach(node.properties, (p: Declaration) => { + if (p.kind === SyntaxKind.OmittedExpression) { + return; + } + // 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 + // IsDataDescriptor(propId.descriptor) is true. + // b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true. + // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. + // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true + // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields + var currentKind: number; + if (p.kind === SyntaxKind.PropertyAssignment) { + currentKind = Property; + } + else if (p.kind === SyntaxKind.GetAccessor) { + currentKind = GetAccessor; + } + else if (p.kind === SyntaxKind.SetAccessor) { + currentKind = SetAccesor; + } + else { + Debug.fail("Unexpected syntax kind:" + SyntaxKind[p.kind]); + } + + if (!hasProperty(seen, p.name.text)) { + seen[p.name.text] = currentKind; + } + else { + var existingKind = seen[p.name.text]; + if (currentKind === Property && existingKind === Property) { + if (isInStrictMode) { + grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode); } } - }); - } + else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) { + if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) { + seen[p.name.text] = currentKind | existingKind; + } + else { + grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); + } + } + else { + grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + } + } + }); return finishNode(node); } @@ -2133,7 +2172,9 @@ module ts { function parseWithStatement(): WithStatement { var node = createNode(SyntaxKind.WithStatement); + var startPos = scanner.getTokenPos(); parseExpected(SyntaxKind.WithKeyword); + var endPos = scanner.getStartPos(); parseExpected(SyntaxKind.OpenParenToken); node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); @@ -2141,8 +2182,8 @@ module ts { node = finishNode(node); if (isInStrictMode) { // Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such - // a context is an SyntaxError(12.10) - grammarErrorOnNode(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); + // a context is an + grammarErrorAtPos(startPos, endPos - startPos, Diagnostics.with_statements_are_not_allowed_in_strict_mode) } return node; } diff --git a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt index ec1752971c9..51e9bae840b 100644 --- a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt +++ b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (8 errors) ==== +==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (9 errors) ==== var x = { a: 1, b: true, // OK @@ -30,6 +30,8 @@ ~ !!! Accessors are only available when targeting ECMAScript 5 and higher. ~ +!!! An object literal cannot have multiple get/set accessors with the same name. + ~ !!! Duplicate identifier 'a'. }; \ No newline at end of file diff --git a/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt index ba6ab28d777..e184b7761ea 100644 --- a/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt +++ b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt @@ -4,7 +4,7 @@ x: 1, x: 2 ~ -!!! Object literal cannot contain more than one property with the same name in the strict mode. +!!! An object literal cannot have multiple properties with the same name in strict mode. ~ !!! Duplicate identifier 'x'. } \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralErrors.errors.txt b/tests/baselines/reference/objectLiteralErrors.errors.txt index a36e532b4be..8e1b64f1758 100644 --- a/tests/baselines/reference/objectLiteralErrors.errors.txt +++ b/tests/baselines/reference/objectLiteralErrors.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (41 errors) ==== +==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (59 errors) ==== // Multiple properties with the same name var e1 = { a: 0, a: 0 }; @@ -59,57 +59,93 @@ // Accessor and property with the same name var f1 = { a: 0, get a() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f2 = { a: '', get a() { return ''; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f3 = { a: 0, get a() { return ''; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f4 = { a: true, get a() { return false; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f5 = { a: {}, get a() { return {}; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f6 = { a: 0, get 'a'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''a''. var f7 = { 'a': 0, get a() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f8 = { 'a': 0, get "a"() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '"a"'. var f9 = { 'a': 0, get 'a'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''a''. var f10 = { "a": 0, get 'a'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''a''. var f11 = { 1.0: 0, get '1'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''1''. var f12 = { 0: 0, get 0() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier '0'. var f13 = { 0: 0, get 0() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier '0'. var f14 = { 0: 0, get 0x0() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '0x0'. var f14 = { 0: 0, get 000() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '000'. var f15 = { "100": 0, get 1e2() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '1e2'. var f16 = { 0x20: 0, get 3.2e1() { return 0; } }; ~~~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~~~ !!! Duplicate identifier '3.2e1'. var f17 = { a: 0, get b() { return 1; }, get a() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. // Get and set accessor with mismatched type annotations diff --git a/tests/baselines/reference/objectLiteralErrors.js b/tests/baselines/reference/objectLiteralErrors.js deleted file mode 100644 index 151cf10a6ab..00000000000 --- a/tests/baselines/reference/objectLiteralErrors.js +++ /dev/null @@ -1,135 +0,0 @@ -//// [objectLiteralErrors.ts] - -// Multiple properties with the same name -var e1 = { a: 0, a: 0 }; -var e2 = { a: '', a: '' }; -var e3 = { a: 0, a: '' }; -var e4 = { a: true, a: false }; -var e5 = { a: {}, a: {} }; -var e6 = { a: 0, 'a': 0 }; -var e7 = { 'a': 0, a: 0 }; -var e8 = { 'a': 0, "a": 0 }; -var e9 = { 'a': 0, 'a': 0 }; -var e10 = { "a": 0, 'a': 0 }; -var e11 = { 1.0: 0, '1': 0 }; -var e12 = { 0: 0, 0: 0 }; -var e13 = { 0: 0, 0: 0 }; -var e14 = { 0: 0, 0x0: 0 }; -var e14 = { 0: 0, 000: 0 }; -var e15 = { "100": 0, 1e2: 0 }; -var e16 = { 0x20: 0, 3.2e1: 0 }; -var e17 = { a: 0, b: 1, a: 0 }; - -// Accessor and property with the same name -var f1 = { a: 0, get a() { return 0; } }; -var f2 = { a: '', get a() { return ''; } }; -var f3 = { a: 0, get a() { return ''; } }; -var f4 = { a: true, get a() { return false; } }; -var f5 = { a: {}, get a() { return {}; } }; -var f6 = { a: 0, get 'a'() { return 0; } }; -var f7 = { 'a': 0, get a() { return 0; } }; -var f8 = { 'a': 0, get "a"() { return 0; } }; -var f9 = { 'a': 0, get 'a'() { return 0; } }; -var f10 = { "a": 0, get 'a'() { return 0; } }; -var f11 = { 1.0: 0, get '1'() { return 0; } }; -var f12 = { 0: 0, get 0() { return 0; } }; -var f13 = { 0: 0, get 0() { return 0; } }; -var f14 = { 0: 0, get 0x0() { return 0; } }; -var f14 = { 0: 0, get 000() { return 0; } }; -var f15 = { "100": 0, get 1e2() { return 0; } }; -var f16 = { 0x20: 0, get 3.2e1() { return 0; } }; -var f17 = { a: 0, get b() { return 1; }, get a() { return 0; } }; - -// Get and set accessor with mismatched type annotations -var g1 = { get a(): number { return 4; }, set a(n: string) { } }; -var g2 = { get a() { return 4; }, set a(n: string) { } }; -var g3 = { get a(): number { return undefined; }, set a(n: string) { } }; - - -//// [objectLiteralErrors.js] -var e1 = { a: 0, a: 0 }; -var e2 = { a: '', a: '' }; -var e3 = { a: 0, a: '' }; -var e4 = { a: true, a: false }; -var e5 = { a: {}, a: {} }; -var e6 = { a: 0, 'a': 0 }; -var e7 = { 'a': 0, a: 0 }; -var e8 = { 'a': 0, "a": 0 }; -var e9 = { 'a': 0, 'a': 0 }; -var e10 = { "a": 0, 'a': 0 }; -var e11 = { 1.0: 0, '1': 0 }; -var e12 = { 0: 0, 0: 0 }; -var e13 = { 0: 0, 0: 0 }; -var e14 = { 0: 0, 0x0: 0 }; -var e14 = { 0: 0, 000: 0 }; -var e15 = { "100": 0, 1e2: 0 }; -var e16 = { 0x20: 0, 3.2e1: 0 }; -var e17 = { a: 0, b: 1, a: 0 }; -var f1 = { a: 0, get a() { - return 0; -} }; -var f2 = { a: '', get a() { - return ''; -} }; -var f3 = { a: 0, get a() { - return ''; -} }; -var f4 = { a: true, get a() { - return false; -} }; -var f5 = { a: {}, get a() { - return {}; -} }; -var f6 = { a: 0, get 'a'() { - return 0; -} }; -var f7 = { 'a': 0, get a() { - return 0; -} }; -var f8 = { 'a': 0, get "a"() { - return 0; -} }; -var f9 = { 'a': 0, get 'a'() { - return 0; -} }; -var f10 = { "a": 0, get 'a'() { - return 0; -} }; -var f11 = { 1.0: 0, get '1'() { - return 0; -} }; -var f12 = { 0: 0, get 0() { - return 0; -} }; -var f13 = { 0: 0, get 0() { - return 0; -} }; -var f14 = { 0: 0, get 0x0() { - return 0; -} }; -var f14 = { 0: 0, get 000() { - return 0; -} }; -var f15 = { "100": 0, get 1e2() { - return 0; -} }; -var f16 = { 0x20: 0, get 3.2e1() { - return 0; -} }; -var f17 = { a: 0, get b() { - return 1; -}, get a() { - return 0; -} }; -var g1 = { get a() { - return 4; -}, set a(n) { -} }; -var g2 = { get a() { - return 4; -}, set a(n) { -} }; -var g3 = { get a() { - return undefined; -}, set a(n) { -} }; diff --git a/tests/baselines/reference/parserStrictMode14.errors.txt b/tests/baselines/reference/parserStrictMode14.errors.txt index 03cfba0b88e..42f564329e8 100644 --- a/tests/baselines/reference/parserStrictMode14.errors.txt +++ b/tests/baselines/reference/parserStrictMode14.errors.txt @@ -1,9 +1,8 @@ ==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (2 errors) ==== "use strict"; with (a) { - ~~~~~~~~~~ + ~~~~ +!!! 'with' statements are not allowed in strict mode. ~ !!! Cannot find name 'a'. - } - ~ -!!! 'with' statements are not allowed in strict mode. \ No newline at end of file + } \ No newline at end of file diff --git a/tests/baselines/reference/twoAccessorsWithSameName.errors.txt b/tests/baselines/reference/twoAccessorsWithSameName.errors.txt index e3631f617d9..edac011d718 100644 --- a/tests/baselines/reference/twoAccessorsWithSameName.errors.txt +++ b/tests/baselines/reference/twoAccessorsWithSameName.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/classes/propertyMemberDeclarations/twoAccessorsWithSameName.ts (13 errors) ==== +==== tests/cases/conformance/classes/propertyMemberDeclarations/twoAccessorsWithSameName.ts (14 errors) ==== class C { get x() { return 1; } ~ @@ -44,6 +44,8 @@ ~ !!! Accessors are only available when targeting ECMAScript 5 and higher. ~ +!!! An object literal cannot have multiple get/set accessors with the same name. + ~ !!! Duplicate identifier 'x'. return 1; } From c369e25cbe504bb2bb3f36fcb09dff9848c97df9 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 24 Jul 2014 12:49:54 -0700 Subject: [PATCH 3/7] added comments --- src/compiler/parser.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7778763b3ea..e005f1e6d58 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -801,6 +801,7 @@ module ts { if (isListElement(kind, /* inErrorRecovery */ false)) { var element = parseElement(); result.push(element); + // test elements only if we are not already in strict mode if (!isInStrictMode && checkForStrictMode) { if (isPrologueDirective(element)) { if (isUseStrictPrologueDirective(element)) { From 9112a0e2e214ea50f71a98fb7c7e06d87af8884e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 23 Jul 2014 10:40:39 -0700 Subject: [PATCH 4/7] enabled strict mode --- .../diagnosticInformationMap.generated.ts | 1 + src/compiler/diagnosticMessages.json | 5 +- src/compiler/emitter.ts | 3 +- src/compiler/parser.ts | 162 ++++++++++++++++-- src/compiler/types.ts | 4 +- ...onstructorStaticParamNameErrors.errors.txt | 8 + .../constructorStaticParamNameErrors.js | 14 -- ...duplicatePropertiesInStrictMode.errors.txt | 10 ++ .../reference/parser10.1.1-8gs.errors.txt | 8 +- tests/baselines/reference/parser10.1.1-8gs.js | 25 --- .../reference/parser642331_1.errors.txt | 9 + tests/baselines/reference/parser642331_1.js | 15 -- .../reference/parserStrictMode10.errors.txt | 6 + .../baselines/reference/parserStrictMode10.js | 9 - .../reference/parserStrictMode11.errors.txt | 6 + .../baselines/reference/parserStrictMode11.js | 9 - .../reference/parserStrictMode12.errors.txt | 4 +- .../reference/parserStrictMode13.errors.txt | 8 + .../baselines/reference/parserStrictMode13.js | 13 -- .../reference/parserStrictMode14.errors.txt | 5 +- .../baselines/reference/parserStrictMode14.js | 9 - .../reference/parserStrictMode2.errors.txt | 6 +- .../baselines/reference/parserStrictMode2.js | 13 -- .../reference/parserStrictMode3.errors.txt | 4 +- .../baselines/reference/parserStrictMode3.js | 7 - .../reference/parserStrictMode4.errors.txt | 4 +- .../baselines/reference/parserStrictMode4.js | 7 - .../reference/parserStrictMode5.errors.txt | 4 +- .../baselines/reference/parserStrictMode5.js | 7 - .../reference/parserStrictMode6.errors.txt | 4 +- .../baselines/reference/parserStrictMode6.js | 7 - .../reference/parserStrictMode8.errors.txt | 4 +- .../baselines/reference/parserStrictMode8.js | 9 - .../reference/parserStrictMode9.errors.txt | 6 + .../baselines/reference/parserStrictMode9.js | 9 - .../reference/scanner10.1.1-8gs.errors.txt | 8 +- .../baselines/reference/scanner10.1.1-8gs.js | 25 --- .../duplicatePropertiesInStrictMode.ts | 5 + 38 files changed, 249 insertions(+), 213 deletions(-) create mode 100644 tests/baselines/reference/constructorStaticParamNameErrors.errors.txt delete mode 100644 tests/baselines/reference/constructorStaticParamNameErrors.js create mode 100644 tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt delete mode 100644 tests/baselines/reference/parser10.1.1-8gs.js create mode 100644 tests/baselines/reference/parser642331_1.errors.txt delete mode 100644 tests/baselines/reference/parser642331_1.js create mode 100644 tests/baselines/reference/parserStrictMode10.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode10.js create mode 100644 tests/baselines/reference/parserStrictMode11.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode11.js create mode 100644 tests/baselines/reference/parserStrictMode13.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode13.js delete mode 100644 tests/baselines/reference/parserStrictMode14.js delete mode 100644 tests/baselines/reference/parserStrictMode2.js delete mode 100644 tests/baselines/reference/parserStrictMode3.js delete mode 100644 tests/baselines/reference/parserStrictMode4.js delete mode 100644 tests/baselines/reference/parserStrictMode5.js delete mode 100644 tests/baselines/reference/parserStrictMode6.js delete mode 100644 tests/baselines/reference/parserStrictMode8.js create mode 100644 tests/baselines/reference/parserStrictMode9.errors.txt delete mode 100644 tests/baselines/reference/parserStrictMode9.js delete mode 100644 tests/baselines/reference/scanner10.1.1-8gs.js create mode 100644 tests/cases/compiler/duplicatePropertiesInStrictMode.ts diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 8f58d9f3042..b1a9bc1dfdb 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -99,6 +99,7 @@ module ts { A_constructor_implementation_cannot_be_declared_in_an_ambient_context: { code: 1111, category: DiagnosticCategory.Error, key: "A constructor implementation cannot be declared in an ambient context." }, A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." }, A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." }, + Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "Object literal cannot contain more than one property with the same name in the strict mode." }, Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array()' instead." }, Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b418ec7a404..1f4f2102163 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -388,7 +388,10 @@ "category": "Error", "code": 1113 }, - + "Object literal cannot contain more than one property with the same name in the strict mode.": { + "category": "Error", + "code": 1114 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2000 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 90661c08fc0..d1e2367babb 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1669,8 +1669,7 @@ module ts { function emitDirectivePrologues(statements: Statement[], startWithNewLine: boolean): number { for (var i = 0; i < statements.length; ++i) { - if (statements[i].kind === SyntaxKind.ExpressionStatement && - (statements[i]).expression.kind === SyntaxKind.StringLiteral) { + if (isPrologueDirective(statements[i])) { if (startWithNewLine || i > 0) { writeLine(); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b3693cf194f..b3d3f6c760b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -119,6 +119,21 @@ module ts { return file.externalModuleIndicator !== undefined; } + export function isPrologueDirective(node: Node): boolean { + return node.kind === SyntaxKind.ExpressionStatement && (node).expression.kind === SyntaxKind.StringLiteral; + } + + function isEvalOrArgumentsIdentifier(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && + (node).text && + ((node).text === "eval" || (node).text === "arguments") + } + + /// Should be called only on prologue directives (isPrologueDirective(node) should be true) + function isUseStrictPrologueDirective(node: Node): boolean { + return ((node).expression).text === "use strict"; + } + // Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes // stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, // embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns @@ -383,6 +398,7 @@ module ts { var identifierCount = 0; var nodeCount = 0; var lineStarts: number[]; + var isInStrictMode = false; var lookAheadMode = LookAheadMode.NotLookingAhead; var inAmbientContext = false; @@ -418,6 +434,13 @@ module ts { file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2)); } + function reportInvalidUseInStrictMode(node: Identifier): void { + // identifierToString cannot be used here since it uses backreference to 'parent' that is not yet set + var name = sourceText.substring(skipTrivia(sourceText, node.pos), node.end); + grammarErrorOnNode(node, Diagnostics.Invalid_use_of_0_in_strict_mode, name); + } + + function grammarErrorAtPos(start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2)); } @@ -522,7 +545,7 @@ module ts { } function isIdentifier(): boolean { - return token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord; + return token === SyntaxKind.Identifier || (isInStrictMode ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord); } function isSemicolon(): boolean { @@ -767,14 +790,27 @@ module ts { } // Parses a list of elements - function parseList(kind: ParsingContext, parseElement: () => T): NodeArray { + function parseList(kind: ParsingContext, checkForStrictMode: boolean, parseElement: () => T): NodeArray { var saveParsingContext = parsingContext; parsingContext |= 1 << kind; var result = >[]; result.pos = getNodePos(); + var saveIsInStrictMode = isInStrictMode; while (!isListTerminator(kind)) { if (isListElement(kind, /* inErrorRecovery */ false)) { - result.push(parseElement()); + var element = parseElement(); + result.push(element); + if (!isInStrictMode && checkForStrictMode) { + if (isPrologueDirective(element)) { + if (isUseStrictPrologueDirective(element)) { + isInStrictMode = true; + checkForStrictMode = false; + } + } + else { + checkForStrictMode = false; + } + } } else { error(parsingContextErrors(kind)); @@ -784,6 +820,7 @@ module ts { nextToken(); } } + isInStrictMode = saveIsInStrictMode; result.end = getNodeEnd(); parsingContext = saveParsingContext; return result; @@ -969,6 +1006,18 @@ module ts { node.flags |= NodeFlags.Rest; } node.name = parseIdentifier(); + if (node.name.kind === SyntaxKind.Missing && node.flags === 0 && isModifier(token)) { + // in cases like + // 'use strict' + // function foo(static) + // isParameter('static') === true, because of isModifier('static') + // however 'static' is not a legal identifier in a strict mode. + // so result of this function will be ParameterDeclaration (flags = 0, name = missing, type = undefined, initializer = undefined) + // and current token will not change => parsing of the enclosing parameter list will last till the end of time (or OOM) + // to avoid this we'll advance cursor to the next token. + nextToken(); + } + if (parseOptional(SyntaxKind.QuestionToken)) { node.flags |= NodeFlags.QuestionMark; } @@ -1013,8 +1062,16 @@ module ts { for (var i = 0; i < parameterCount; i++) { var parameter = parameters[i]; - - if (parameter.flags & NodeFlags.Rest) { + // It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the + // Identifier in a PropertySetParameterList of a PropertyAssignment that is contained in strict code + // or if its FunctionBody is strict code(11.1.5). + // It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a + // strict mode FunctionDeclaration or FunctionExpression(13.1) + if (isInStrictMode && isEvalOrArgumentsIdentifier(parameter.name)) { + reportInvalidUseInStrictMode(parameter.name); + return; + } + else if (parameter.flags & NodeFlags.Rest) { if (i !== (parameterCount - 1)) { grammarErrorOnNode(parameter.name, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list); return; @@ -1171,7 +1228,7 @@ module ts { function parseTypeLiteral(): TypeLiteralNode { var node = createNode(SyntaxKind.TypeLiteral); if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.members = parseList(ParsingContext.TypeMembers, parseTypeMember); + node.members = parseList(ParsingContext.TypeMembers, /*checkForStrictMode*/ false, parseTypeMember); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -1361,6 +1418,11 @@ module ts { // If the expression was a LHS expression, and we have an assignment operator, then // we're in '2' or '3'. Consume the assignement and return. if (isLeftHandSideExpression(expr) && isAssignmentOperator()) { + if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) { + // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) + reportInvalidUseInStrictMode(expr); + } var operator = token; nextToken(); return makeBinaryExpression(expr, operator, parseAssignmentExpression(noIn)); @@ -1660,6 +1722,19 @@ module ts { var operator = token; nextToken(); var operand = parseUnaryExpression(); + if (isInStrictMode) { + // The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression + // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator + if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && isEvalOrArgumentsIdentifier(operand)) { + reportInvalidUseInStrictMode(operand); + } + else if (token === SyntaxKind.DeleteKeyword && operand.kind === SyntaxKind.Identifier) { + // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its + // UnaryExpression is a direct reference to a variable, function argument, or function name + grammarErrorOnNode(operand, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode); + } + } return makeUnaryExpression(SyntaxKind.PrefixOperator, pos, operator, operand); case SyntaxKind.LessThanToken: return parseTypeAssertion(); @@ -1681,6 +1756,12 @@ module ts { Debug.assert(isLeftHandSideExpression(expr)); if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && !scanner.hasPrecedingLineBreak()) { + // The identifier eval or arguments may not appear as the LeftHandSideExpression of an + // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression + // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator. + if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) { + reportInvalidUseInStrictMode(expr); + } var operator = token; nextToken(); expr = makeUnaryExpression(SyntaxKind.PostfixOperator, expr.pos, operator, expr); @@ -1867,6 +1948,23 @@ module ts { if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, TrailingCommaBehavior.Preserve); parseExpected(SyntaxKind.CloseBraceToken); + if (isInStrictMode) { + var seen: Map = {}; + forEach(node.properties, (p: Node) => { + // 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 IsDataDescriptor(propId.descriptor) is true. + if (p.kind === SyntaxKind.PropertyAssignment) { + var name = (p).name; + if (hasProperty(seen, name.text)) { + grammarErrorOnNode(name, Diagnostics.Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode); + } + else { + seen[name.text] = true; + } + } + }); + } return finishNode(node); } @@ -1876,6 +1974,11 @@ module ts { var name = isIdentifier() ? parseIdentifier() : undefined; var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken); var body = parseBody(/* ignoreMissingOpenBrace */ false); + if (name && isInStrictMode && isEvalOrArgumentsIdentifier(name)) { + // It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the + // Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name(13.1) + reportInvalidUseInStrictMode(name); + } return makeFunctionExpression(SyntaxKind.FunctionExpression, pos, name, sig, body); } @@ -1902,10 +2005,10 @@ module ts { // STATEMENTS - function parseBlock(ignoreMissingOpenBrace: boolean): Block { + function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean): Block { var node = createNode(SyntaxKind.Block); if (parseExpected(SyntaxKind.OpenBraceToken) || ignoreMissingOpenBrace) { - node.statements = parseList(ParsingContext.BlockStatements, parseStatement); + node.statements = parseList(ParsingContext.BlockStatements,checkForStrictMode, parseStatement); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -1915,7 +2018,7 @@ module ts { } function parseBody(ignoreMissingOpenBrace: boolean): Block { - var block = parseBlock(ignoreMissingOpenBrace); + var block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true); block.kind = SyntaxKind.FunctionBlock; return block; } @@ -2036,7 +2139,13 @@ module ts { node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); node.statement = parseStatement(); - return finishNode(node); + node = finishNode(node); + if (isInStrictMode) { + // Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such + // a context is an SyntaxError(12.10) + grammarErrorOnNode(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); + } + return node; } function parseCaseClause(): CaseOrDefaultClause { @@ -2044,7 +2153,7 @@ module ts { parseExpected(SyntaxKind.CaseKeyword); node.expression = parseExpression(); parseExpected(SyntaxKind.ColonToken); - node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); + node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement); return finishNode(node); } @@ -2052,7 +2161,7 @@ module ts { var node = createNode(SyntaxKind.DefaultClause); parseExpected(SyntaxKind.DefaultKeyword); parseExpected(SyntaxKind.ColonToken); - node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement); + node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement); return finishNode(node); } @@ -2067,7 +2176,7 @@ module ts { node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); parseExpected(SyntaxKind.OpenBraceToken); - node.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause); + node.clauses = parseList(ParsingContext.SwitchClauses, /*checkForStrictMode*/ false, parseCaseOrDefaultClause); parseExpected(SyntaxKind.CloseBraceToken); // Error on duplicate 'default' clauses. @@ -2112,7 +2221,7 @@ module ts { function parseTokenAndBlock(token: SyntaxKind, kind: SyntaxKind): Block { var pos = getNodePos(); parseExpected(token); - var result = parseBlock(/* ignoreMissingOpenBrace */ false); + var result = parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); result.kind = kind; result.pos = pos; return result; @@ -2127,7 +2236,7 @@ module ts { var typeAnnotationColonLength = scanner.getTextPos() - typeAnnotationColonStart; var typeAnnotation = parseTypeAnnotation(); parseExpected(SyntaxKind.CloseParenToken); - var result = parseBlock(/* ignoreMissingOpenBrace */ false); + var result = parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); result.kind = SyntaxKind.CatchBlock; result.pos = pos; result.variable = variable; @@ -2135,6 +2244,11 @@ module ts { if (typeAnnotation) { errorAtPos(typeAnnotationColonStart, typeAnnotationColonLength, Diagnostics.Catch_clause_parameter_cannot_have_a_type_annotation); } + if (isInStrictMode && isEvalOrArgumentsIdentifier(variable)) { + // It is a SyntaxError if a TryStatement with a Catch occurs within strict code and the Identifier of the + // Catch production is eval or arguments + reportInvalidUseInStrictMode(variable); + } return result; } @@ -2207,7 +2321,7 @@ module ts { function parseStatement(): Statement { switch (token) { case SyntaxKind.OpenBraceToken: - return parseBlock(/* ignoreMissingOpenBrace */ false); + return parseBlock(/* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); case SyntaxKind.VarKeyword: return parseVariableStatement(); case SyntaxKind.FunctionKeyword: @@ -2285,6 +2399,11 @@ module ts { if (inAmbientContext && node.initializer && errorCountBeforeVariableDeclaration === file.syntacticErrors.length) { grammarErrorAtPos(initializerStart, initializerFirstTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); } + if (isInStrictMode && isEvalOrArgumentsIdentifier(node.name)) { + // It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code + // and its Identifier is eval or arguments + reportInvalidUseInStrictMode(node.name); + } return finishNode(node); } @@ -2315,6 +2434,11 @@ module ts { node.parameters = sig.parameters; node.type = sig.type; node.body = parseAndCheckFunctionBody(/*isConstructor*/ false); + if (isInStrictMode && isEvalOrArgumentsIdentifier(node.name)) { + // It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the + // Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name(13.1) + reportInvalidUseInStrictMode(node.name); + } return finishNode(node); } @@ -2657,7 +2781,7 @@ module ts { } var errorCountBeforeClassBody = file.syntacticErrors.length; if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.members = parseList(ParsingContext.ClassMembers, parseClassMemberDeclaration); + node.members = parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassMemberDeclaration); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -2757,7 +2881,7 @@ module ts { function parseModuleBody(): Block { var node = createNode(SyntaxKind.ModuleBlock); if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.statements = parseList(ParsingContext.ModuleElements, parseModuleElement); + node.statements = parseList(ParsingContext.ModuleElements, /*checkForStrictMode*/ false, parseModuleElement); parseExpected(SyntaxKind.CloseBraceToken); } else { @@ -3014,7 +3138,7 @@ module ts { var referenceComments = processReferenceComments(); file.referencedFiles = referenceComments.referencedFiles; file.amdDependencies = referenceComments.amdDependencies; - file.statements = parseList(ParsingContext.SourceElements, parseSourceElement); + file.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); file.externalModuleIndicator = getExternalModuleIndicator(); file.nodeCount = nodeCount; file.identifierCount = identifierCount; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5decadcfe17..545e6d60310 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -215,7 +215,9 @@ module ts { FirstReservedWord = BreakKeyword, LastReservedWord = WithKeyword, FirstKeyword = BreakKeyword, - LastKeyword = StringKeyword + LastKeyword = StringKeyword, + FirstFutureReservedWord = ImplementsKeyword, + LastFutureReservedWord = YieldKeyword } export enum NodeFlags { diff --git a/tests/baselines/reference/constructorStaticParamNameErrors.errors.txt b/tests/baselines/reference/constructorStaticParamNameErrors.errors.txt new file mode 100644 index 00000000000..494c28e89e9 --- /dev/null +++ b/tests/baselines/reference/constructorStaticParamNameErrors.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/compiler/constructorStaticParamNameErrors.ts (1 errors) ==== + 'use strict' + // static as constructor parameter name should give error if 'use strict' + class test { + constructor (static) { } + ~~~~~~ +!!! Identifier expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/constructorStaticParamNameErrors.js b/tests/baselines/reference/constructorStaticParamNameErrors.js deleted file mode 100644 index 0db6b5aa995..00000000000 --- a/tests/baselines/reference/constructorStaticParamNameErrors.js +++ /dev/null @@ -1,14 +0,0 @@ -//// [constructorStaticParamNameErrors.ts] -'use strict' -// static as constructor parameter name should give error if 'use strict' -class test { - constructor (static) { } -} - -//// [constructorStaticParamNameErrors.js] -'use strict'; -var test = (function () { - function test(static) { - } - return test; -})(); diff --git a/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt new file mode 100644 index 00000000000..ba6ab28d777 --- /dev/null +++ b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt @@ -0,0 +1,10 @@ +==== tests/cases/compiler/duplicatePropertiesInStrictMode.ts (2 errors) ==== + "use strict"; + var x = { + x: 1, + x: 2 + ~ +!!! Object literal cannot contain more than one property with the same name in the strict mode. + ~ +!!! Duplicate identifier 'x'. + } \ No newline at end of file diff --git a/tests/baselines/reference/parser10.1.1-8gs.errors.txt b/tests/baselines/reference/parser10.1.1-8gs.errors.txt index 4482dd6f1d3..4ed4b8b2635 100644 --- a/tests/baselines/reference/parser10.1.1-8gs.errors.txt +++ b/tests/baselines/reference/parser10.1.1-8gs.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/parser10.1.1-8gs.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/parser10.1.1-8gs.ts (4 errors) ==== /// Copyright (c) 2012 Ecma International. All rights reserved. /// Ecma International makes this code available under the terms and conditions set /// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the @@ -18,4 +18,10 @@ ~~~~~~~~~~~~~ !!! Cannot find name 'NotEarlyError'. var public = 1; + ~~~~~~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/parser10.1.1-8gs.js b/tests/baselines/reference/parser10.1.1-8gs.js deleted file mode 100644 index 6c04bffc223..00000000000 --- a/tests/baselines/reference/parser10.1.1-8gs.js +++ /dev/null @@ -1,25 +0,0 @@ -//// [parser10.1.1-8gs.ts] -/// Copyright (c) 2012 Ecma International. All rights reserved. -/// Ecma International makes this code available under the terms and conditions set -/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the -/// "Use Terms"). Any redistribution of this code must retain the above -/// copyright and this notice and otherwise comply with the Use Terms. - -/** - * @path ch10/10.1/10.1.1/10.1.1-8gs.js - * @description Strict Mode - Use Strict Directive Prologue is ''use strict';' which appears twice in the code - * @noStrict - * @negative ^((?!NotEarlyError).)*$ - */ - -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; - - -//// [parser10.1.1-8gs.js] -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; diff --git a/tests/baselines/reference/parser642331_1.errors.txt b/tests/baselines/reference/parser642331_1.errors.txt new file mode 100644 index 00000000000..3556849b806 --- /dev/null +++ b/tests/baselines/reference/parser642331_1.errors.txt @@ -0,0 +1,9 @@ +==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser642331_1.ts (1 errors) ==== + "use strict"; + + class test { + constructor (static) { } + ~~~~~~ +!!! Identifier expected. + } + \ No newline at end of file diff --git a/tests/baselines/reference/parser642331_1.js b/tests/baselines/reference/parser642331_1.js deleted file mode 100644 index 83833ee6612..00000000000 --- a/tests/baselines/reference/parser642331_1.js +++ /dev/null @@ -1,15 +0,0 @@ -//// [parser642331_1.ts] -"use strict"; - -class test { - constructor (static) { } -} - - -//// [parser642331_1.js] -"use strict"; -var test = (function () { - function test(static) { - } - return test; -})(); diff --git a/tests/baselines/reference/parserStrictMode10.errors.txt b/tests/baselines/reference/parserStrictMode10.errors.txt new file mode 100644 index 00000000000..a887f9bdade --- /dev/null +++ b/tests/baselines/reference/parserStrictMode10.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode10.ts (1 errors) ==== + "use strict"; + function f(eval) { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + } \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode10.js b/tests/baselines/reference/parserStrictMode10.js deleted file mode 100644 index 53ec7686d0e..00000000000 --- a/tests/baselines/reference/parserStrictMode10.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode10.ts] -"use strict"; -function f(eval) { -} - -//// [parserStrictMode10.js] -"use strict"; -function f(eval) { -} diff --git a/tests/baselines/reference/parserStrictMode11.errors.txt b/tests/baselines/reference/parserStrictMode11.errors.txt new file mode 100644 index 00000000000..1dc4e0943e4 --- /dev/null +++ b/tests/baselines/reference/parserStrictMode11.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode11.ts (1 errors) ==== + "use strict"; + var v = function f(eval) { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + }; \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode11.js b/tests/baselines/reference/parserStrictMode11.js deleted file mode 100644 index b34af107f83..00000000000 --- a/tests/baselines/reference/parserStrictMode11.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode11.ts] -"use strict"; -var v = function f(eval) { -}; - -//// [parserStrictMode11.js] -"use strict"; -var v = function f(eval) { -}; diff --git a/tests/baselines/reference/parserStrictMode12.errors.txt b/tests/baselines/reference/parserStrictMode12.errors.txt index 6a04944298f..0d50bc4d87b 100644 --- a/tests/baselines/reference/parserStrictMode12.errors.txt +++ b/tests/baselines/reference/parserStrictMode12.errors.txt @@ -1,5 +1,5 @@ ==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode12.ts (1 errors) ==== "use strict"; var v = { set foo(eval) { } } - ~~~ -!!! Accessors are only available when targeting ECMAScript 5 and higher. \ No newline at end of file + ~~~~ +!!! Invalid use of 'eval' in strict mode. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode13.errors.txt b/tests/baselines/reference/parserStrictMode13.errors.txt new file mode 100644 index 00000000000..49e1e509ca3 --- /dev/null +++ b/tests/baselines/reference/parserStrictMode13.errors.txt @@ -0,0 +1,8 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode13.ts (1 errors) ==== + "use strict"; + try { + } + catch(eval) { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + } \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode13.js b/tests/baselines/reference/parserStrictMode13.js deleted file mode 100644 index c3ace6981f4..00000000000 --- a/tests/baselines/reference/parserStrictMode13.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parserStrictMode13.ts] -"use strict"; -try { -} -catch(eval) { -} - -//// [parserStrictMode13.js] -"use strict"; -try { -} -catch (eval) { -} diff --git a/tests/baselines/reference/parserStrictMode14.errors.txt b/tests/baselines/reference/parserStrictMode14.errors.txt index 2291ebd80b7..03cd5223229 100644 --- a/tests/baselines/reference/parserStrictMode14.errors.txt +++ b/tests/baselines/reference/parserStrictMode14.errors.txt @@ -1,8 +1,11 @@ ==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (2 errors) ==== "use strict"; with (a) { + ~~~~~~~~~~ ~ !!! All symbols within a 'with' block will be resolved to 'any'. ~ !!! Cannot find name 'a'. - } \ No newline at end of file + } + ~ +!!! 'with' statements are not allowed in strict mode. diff --git a/tests/baselines/reference/parserStrictMode14.js b/tests/baselines/reference/parserStrictMode14.js deleted file mode 100644 index eda7f285f71..00000000000 --- a/tests/baselines/reference/parserStrictMode14.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode14.ts] -"use strict"; -with (a) { -} - -//// [parserStrictMode14.js] -"use strict"; -with (a) { -} diff --git a/tests/baselines/reference/parserStrictMode2.errors.txt b/tests/baselines/reference/parserStrictMode2.errors.txt index 9ed56baa7b3..98563258c11 100644 --- a/tests/baselines/reference/parserStrictMode2.errors.txt +++ b/tests/baselines/reference/parserStrictMode2.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode2.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode2.ts (5 errors) ==== "use strict"; foo1(); ~~~~ @@ -11,4 +11,6 @@ !!! Cannot find name 'foo1'. static(); ~~~~~~ -!!! Cannot find name 'static'. \ No newline at end of file +!!! Declaration or statement expected. + ~ +!!! '=>' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode2.js b/tests/baselines/reference/parserStrictMode2.js deleted file mode 100644 index 79b32ed9a58..00000000000 --- a/tests/baselines/reference/parserStrictMode2.js +++ /dev/null @@ -1,13 +0,0 @@ -//// [parserStrictMode2.ts] -"use strict"; -foo1(); -foo1(); -foo1(); -static(); - -//// [parserStrictMode2.js] -"use strict"; -foo1(); -foo1(); -foo1(); -static(); diff --git a/tests/baselines/reference/parserStrictMode3.errors.txt b/tests/baselines/reference/parserStrictMode3.errors.txt index 9631404b9d5..ab67566a841 100644 --- a/tests/baselines/reference/parserStrictMode3.errors.txt +++ b/tests/baselines/reference/parserStrictMode3.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode3.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode3.ts (2 errors) ==== "use strict"; eval = 1; ~~~~ +!!! Invalid use of 'eval' in strict mode. + ~~~~ !!! Invalid left-hand side of assignment expression. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode3.js b/tests/baselines/reference/parserStrictMode3.js deleted file mode 100644 index 166d8905a7a..00000000000 --- a/tests/baselines/reference/parserStrictMode3.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode3.ts] -"use strict"; -eval = 1; - -//// [parserStrictMode3.js] -"use strict"; -eval = 1; diff --git a/tests/baselines/reference/parserStrictMode4.errors.txt b/tests/baselines/reference/parserStrictMode4.errors.txt index 173c86131b4..e73d99fcaec 100644 --- a/tests/baselines/reference/parserStrictMode4.errors.txt +++ b/tests/baselines/reference/parserStrictMode4.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode4.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode4.ts (2 errors) ==== "use strict"; arguments = 1; ~~~~~~~~~ +!!! Invalid use of 'arguments' in strict mode. + ~~~~~~~~~ !!! Cannot find name 'arguments'. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode4.js b/tests/baselines/reference/parserStrictMode4.js deleted file mode 100644 index ff1ed9b3a8f..00000000000 --- a/tests/baselines/reference/parserStrictMode4.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode4.ts] -"use strict"; -arguments = 1; - -//// [parserStrictMode4.js] -"use strict"; -arguments = 1; diff --git a/tests/baselines/reference/parserStrictMode5.errors.txt b/tests/baselines/reference/parserStrictMode5.errors.txt index 1c0cf2da223..0cb96d4a4a2 100644 --- a/tests/baselines/reference/parserStrictMode5.errors.txt +++ b/tests/baselines/reference/parserStrictMode5.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode5.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode5.ts (2 errors) ==== "use strict"; eval += 1; + ~~~~ +!!! Invalid use of 'eval' in strict mode. ~~~~~~~~~ !!! Operator '+=' cannot be applied to types '(x: string) => any' and 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode5.js b/tests/baselines/reference/parserStrictMode5.js deleted file mode 100644 index 7e01b0f5d72..00000000000 --- a/tests/baselines/reference/parserStrictMode5.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode5.ts] -"use strict"; -eval += 1; - -//// [parserStrictMode5.js] -"use strict"; -eval += 1; diff --git a/tests/baselines/reference/parserStrictMode6.errors.txt b/tests/baselines/reference/parserStrictMode6.errors.txt index 4dc330e46e8..2d3aef69770 100644 --- a/tests/baselines/reference/parserStrictMode6.errors.txt +++ b/tests/baselines/reference/parserStrictMode6.errors.txt @@ -1,5 +1,7 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode6.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode6.ts (2 errors) ==== "use strict"; eval++; ~~~~ +!!! Invalid use of 'eval' in strict mode. + ~~~~ !!! An arithmetic operand must be of type 'any', 'number' or an enum type. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode6.js b/tests/baselines/reference/parserStrictMode6.js deleted file mode 100644 index 6a4161c3dab..00000000000 --- a/tests/baselines/reference/parserStrictMode6.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode6.ts] -"use strict"; -eval++; - -//// [parserStrictMode6.js] -"use strict"; -eval++; diff --git a/tests/baselines/reference/parserStrictMode8.errors.txt b/tests/baselines/reference/parserStrictMode8.errors.txt index eebb5d59f7d..366b4059010 100644 --- a/tests/baselines/reference/parserStrictMode8.errors.txt +++ b/tests/baselines/reference/parserStrictMode8.errors.txt @@ -1,6 +1,8 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode8.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode8.ts (2 errors) ==== "use strict"; function eval() { ~~~~ +!!! Invalid use of 'eval' in strict mode. + ~~~~ !!! Overload signatures must all be ambient or non-ambient. } \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode8.js b/tests/baselines/reference/parserStrictMode8.js deleted file mode 100644 index 3db5349c459..00000000000 --- a/tests/baselines/reference/parserStrictMode8.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode8.ts] -"use strict"; -function eval() { -} - -//// [parserStrictMode8.js] -"use strict"; -function eval() { -} diff --git a/tests/baselines/reference/parserStrictMode9.errors.txt b/tests/baselines/reference/parserStrictMode9.errors.txt new file mode 100644 index 00000000000..769c69a3943 --- /dev/null +++ b/tests/baselines/reference/parserStrictMode9.errors.txt @@ -0,0 +1,6 @@ +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode9.ts (1 errors) ==== + "use strict"; + var v = function eval() { + ~~~~ +!!! Invalid use of 'eval' in strict mode. + }; \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode9.js b/tests/baselines/reference/parserStrictMode9.js deleted file mode 100644 index a30008634c5..00000000000 --- a/tests/baselines/reference/parserStrictMode9.js +++ /dev/null @@ -1,9 +0,0 @@ -//// [parserStrictMode9.ts] -"use strict"; -var v = function eval() { -}; - -//// [parserStrictMode9.js] -"use strict"; -var v = function eval() { -}; diff --git a/tests/baselines/reference/scanner10.1.1-8gs.errors.txt b/tests/baselines/reference/scanner10.1.1-8gs.errors.txt index 53fb3724e14..e69d84be612 100644 --- a/tests/baselines/reference/scanner10.1.1-8gs.errors.txt +++ b/tests/baselines/reference/scanner10.1.1-8gs.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/scanner/ecmascript5/scanner10.1.1-8gs.ts (1 errors) ==== +==== tests/cases/conformance/scanner/ecmascript5/scanner10.1.1-8gs.ts (4 errors) ==== /// Copyright (c) 2012 Ecma International. All rights reserved. /// Ecma International makes this code available under the terms and conditions set /// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the @@ -18,4 +18,10 @@ ~~~~~~~~~~~~~ !!! Cannot find name 'NotEarlyError'. var public = 1; + ~~~~~~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. + ~ +!!! Variable declaration expected. \ No newline at end of file diff --git a/tests/baselines/reference/scanner10.1.1-8gs.js b/tests/baselines/reference/scanner10.1.1-8gs.js deleted file mode 100644 index 85dada5e793..00000000000 --- a/tests/baselines/reference/scanner10.1.1-8gs.js +++ /dev/null @@ -1,25 +0,0 @@ -//// [scanner10.1.1-8gs.ts] -/// Copyright (c) 2012 Ecma International. All rights reserved. -/// Ecma International makes this code available under the terms and conditions set -/// forth on http://hg.ecmascript.org/tests/test262/raw-file/tip/LICENSE (the -/// "Use Terms"). Any redistribution of this code must retain the above -/// copyright and this notice and otherwise comply with the Use Terms. - -/** - * @path ch10/10.1/10.1.1/10.1.1-8gs.js - * @description Strict Mode - Use Strict Directive Prologue is ''use strict';' which appears twice in the code - * @noStrict - * @negative ^((?!NotEarlyError).)*$ - */ - -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; - - -//// [scanner10.1.1-8gs.js] -"use strict"; -"use strict"; -throw NotEarlyError; -var public = 1; diff --git a/tests/cases/compiler/duplicatePropertiesInStrictMode.ts b/tests/cases/compiler/duplicatePropertiesInStrictMode.ts new file mode 100644 index 00000000000..bea869f93a4 --- /dev/null +++ b/tests/cases/compiler/duplicatePropertiesInStrictMode.ts @@ -0,0 +1,5 @@ +"use strict"; +var x = { + x: 1, + x: 2 +} \ No newline at end of file From 6572c826a1401ea1b5886bc130e7363f3850b054 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Wed, 23 Jul 2014 16:45:23 -0700 Subject: [PATCH 5/7] update check for object literal properties according to ECMA spec --- .../diagnosticInformationMap.generated.ts | 4 +- src/compiler/diagnosticMessages.json | 10 +- src/compiler/parser.ts | 77 +++++++--- .../duplicateObjectLiteralProperty.errors.txt | 4 +- ...duplicatePropertiesInStrictMode.errors.txt | 2 +- .../reference/objectLiteralErrors.errors.txt | 38 ++++- .../reference/objectLiteralErrors.js | 135 ------------------ .../reference/parserStrictMode14.errors.txt | 5 +- .../twoAccessorsWithSameName.errors.txt | 4 +- 9 files changed, 117 insertions(+), 162 deletions(-) delete mode 100644 tests/baselines/reference/objectLiteralErrors.js diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index b1a9bc1dfdb..9927cb9d98e 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -99,7 +99,9 @@ module ts { A_constructor_implementation_cannot_be_declared_in_an_ambient_context: { code: 1111, category: DiagnosticCategory.Error, key: "A constructor implementation cannot be declared in an ambient context." }, A_class_member_cannot_be_declared_optional: { code: 1112, category: DiagnosticCategory.Error, key: "A class member cannot be declared optional." }, A_default_clause_cannot_appear_more_than_once_in_a_switch_statement: { code: 1113, category: DiagnosticCategory.Error, key: "A 'default' clause cannot appear more than once in a 'switch' statement." }, - Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "Object literal cannot contain more than one property with the same name in the strict mode." }, + An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode: { code: 1114, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple properties with the same name in strict mode." }, + An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name: { code: 1115, category: DiagnosticCategory.Error, key: "An object literal cannot have multiple get/set accessors with the same name." }, + An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1116, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." }, Duplicate_identifier_0: { code: 2000, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array()' instead." }, Multiple_constructor_implementations_are_not_allowed: { code: 2070, category: DiagnosticCategory.Error, key: "Multiple constructor implementations are not allowed." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1f4f2102163..d61be84b5de 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -388,10 +388,18 @@ "category": "Error", "code": 1113 }, - "Object literal cannot contain more than one property with the same name in the strict mode.": { + "An object literal cannot have multiple properties with the same name in strict mode.": { "category": "Error", "code": 1114 }, + "An object literal cannot have multiple get/set accessors with the same name.": { + "category": "Error", + "code": 1115 + }, + "An object literal cannot have property and accessor with the same name.": { + "category": "Error", + "code": 1116 + }, "Duplicate identifier '{0}'.": { "category": "Error", "code": 2000 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b3d3f6c760b..3a40e487970 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -131,6 +131,7 @@ module ts { /// Should be called only on prologue directives (isPrologueDirective(node) should be true) function isUseStrictPrologueDirective(node: Node): boolean { + Debug.assert(isPrologueDirective(node)); return ((node).expression).text === "use strict"; } @@ -1416,7 +1417,7 @@ module ts { // Now see if we might be in cases '2' or '3'. // If the expression was a LHS expression, and we have an assignment operator, then - // we're in '2' or '3'. Consume the assignement and return. + // we're in '2' or '3'. Consume the assignment and return. if (isLeftHandSideExpression(expr) && isAssignmentOperator()) { if (isInStrictMode && isEvalOrArgumentsIdentifier(expr)) { // ECMA 262 (Annex C) The identifier eval or arguments may not appear as the LeftHandSideExpression of an @@ -1948,23 +1949,61 @@ module ts { if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, TrailingCommaBehavior.Preserve); parseExpected(SyntaxKind.CloseBraceToken); - if (isInStrictMode) { - var seen: Map = {}; - forEach(node.properties, (p: Node) => { - // 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 IsDataDescriptor(propId.descriptor) is true. - if (p.kind === SyntaxKind.PropertyAssignment) { - var name = (p).name; - if (hasProperty(seen, name.text)) { - grammarErrorOnNode(name, Diagnostics.Object_literal_cannot_contain_more_than_one_property_with_the_same_name_in_the_strict_mode); - } - else { - seen[name.text] = true; + + var seen: Map = {}; + var Property = 1; + var GetAccessor = 2; + var SetAccesor = 4; + var GetOrSetAccessor = GetAccessor | SetAccesor; + forEach(node.properties, (p: Declaration) => { + if (p.kind === SyntaxKind.OmittedExpression) { + return; + } + // 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 + // IsDataDescriptor(propId.descriptor) is true. + // b.IsDataDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true. + // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. + // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true + // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields + var currentKind: number; + if (p.kind === SyntaxKind.PropertyAssignment) { + currentKind = Property; + } + else if (p.kind === SyntaxKind.GetAccessor) { + currentKind = GetAccessor; + } + else if (p.kind === SyntaxKind.SetAccessor) { + currentKind = SetAccesor; + } + else { + Debug.fail("Unexpected syntax kind:" + SyntaxKind[p.kind]); + } + + if (!hasProperty(seen, p.name.text)) { + seen[p.name.text] = currentKind; + } + else { + var existingKind = seen[p.name.text]; + if (currentKind === Property && existingKind === Property) { + if (isInStrictMode) { + grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode); } } - }); - } + else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) { + if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) { + seen[p.name.text] = currentKind | existingKind; + } + else { + grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_multiple_get_Slashset_accessors_with_the_same_name); + } + } + else { + grammarErrorOnNode(p.name, Diagnostics.An_object_literal_cannot_have_property_and_accessor_with_the_same_name); + } + } + }); return finishNode(node); } @@ -2134,7 +2173,9 @@ module ts { function parseWithStatement(): WithStatement { var node = createNode(SyntaxKind.WithStatement); + var startPos = scanner.getTokenPos(); parseExpected(SyntaxKind.WithKeyword); + var endPos = scanner.getStartPos(); parseExpected(SyntaxKind.OpenParenToken); node.expression = parseExpression(); parseExpected(SyntaxKind.CloseParenToken); @@ -2142,8 +2183,8 @@ module ts { node = finishNode(node); if (isInStrictMode) { // Strict mode code may not include a WithStatement. The occurrence of a WithStatement in such - // a context is an SyntaxError(12.10) - grammarErrorOnNode(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode); + // a context is an + grammarErrorAtPos(startPos, endPos - startPos, Diagnostics.with_statements_are_not_allowed_in_strict_mode) } return node; } diff --git a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt index ec1752971c9..51e9bae840b 100644 --- a/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt +++ b/tests/baselines/reference/duplicateObjectLiteralProperty.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (8 errors) ==== +==== tests/cases/compiler/duplicateObjectLiteralProperty.ts (9 errors) ==== var x = { a: 1, b: true, // OK @@ -30,6 +30,8 @@ ~ !!! Accessors are only available when targeting ECMAScript 5 and higher. ~ +!!! An object literal cannot have multiple get/set accessors with the same name. + ~ !!! Duplicate identifier 'a'. }; \ No newline at end of file diff --git a/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt index ba6ab28d777..e184b7761ea 100644 --- a/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt +++ b/tests/baselines/reference/duplicatePropertiesInStrictMode.errors.txt @@ -4,7 +4,7 @@ x: 1, x: 2 ~ -!!! Object literal cannot contain more than one property with the same name in the strict mode. +!!! An object literal cannot have multiple properties with the same name in strict mode. ~ !!! Duplicate identifier 'x'. } \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralErrors.errors.txt b/tests/baselines/reference/objectLiteralErrors.errors.txt index a36e532b4be..8e1b64f1758 100644 --- a/tests/baselines/reference/objectLiteralErrors.errors.txt +++ b/tests/baselines/reference/objectLiteralErrors.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (41 errors) ==== +==== tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts (59 errors) ==== // Multiple properties with the same name var e1 = { a: 0, a: 0 }; @@ -59,57 +59,93 @@ // Accessor and property with the same name var f1 = { a: 0, get a() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f2 = { a: '', get a() { return ''; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f3 = { a: 0, get a() { return ''; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f4 = { a: true, get a() { return false; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f5 = { a: {}, get a() { return {}; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f6 = { a: 0, get 'a'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''a''. var f7 = { 'a': 0, get a() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. var f8 = { 'a': 0, get "a"() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '"a"'. var f9 = { 'a': 0, get 'a'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''a''. var f10 = { "a": 0, get 'a'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''a''. var f11 = { 1.0: 0, get '1'() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier ''1''. var f12 = { 0: 0, get 0() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier '0'. var f13 = { 0: 0, get 0() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier '0'. var f14 = { 0: 0, get 0x0() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '0x0'. var f14 = { 0: 0, get 000() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '000'. var f15 = { "100": 0, get 1e2() { return 0; } }; ~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~ !!! Duplicate identifier '1e2'. var f16 = { 0x20: 0, get 3.2e1() { return 0; } }; ~~~~~ +!!! An object literal cannot have property and accessor with the same name. + ~~~~~ !!! Duplicate identifier '3.2e1'. var f17 = { a: 0, get b() { return 1; }, get a() { return 0; } }; ~ +!!! An object literal cannot have property and accessor with the same name. + ~ !!! Duplicate identifier 'a'. // Get and set accessor with mismatched type annotations diff --git a/tests/baselines/reference/objectLiteralErrors.js b/tests/baselines/reference/objectLiteralErrors.js deleted file mode 100644 index 151cf10a6ab..00000000000 --- a/tests/baselines/reference/objectLiteralErrors.js +++ /dev/null @@ -1,135 +0,0 @@ -//// [objectLiteralErrors.ts] - -// Multiple properties with the same name -var e1 = { a: 0, a: 0 }; -var e2 = { a: '', a: '' }; -var e3 = { a: 0, a: '' }; -var e4 = { a: true, a: false }; -var e5 = { a: {}, a: {} }; -var e6 = { a: 0, 'a': 0 }; -var e7 = { 'a': 0, a: 0 }; -var e8 = { 'a': 0, "a": 0 }; -var e9 = { 'a': 0, 'a': 0 }; -var e10 = { "a": 0, 'a': 0 }; -var e11 = { 1.0: 0, '1': 0 }; -var e12 = { 0: 0, 0: 0 }; -var e13 = { 0: 0, 0: 0 }; -var e14 = { 0: 0, 0x0: 0 }; -var e14 = { 0: 0, 000: 0 }; -var e15 = { "100": 0, 1e2: 0 }; -var e16 = { 0x20: 0, 3.2e1: 0 }; -var e17 = { a: 0, b: 1, a: 0 }; - -// Accessor and property with the same name -var f1 = { a: 0, get a() { return 0; } }; -var f2 = { a: '', get a() { return ''; } }; -var f3 = { a: 0, get a() { return ''; } }; -var f4 = { a: true, get a() { return false; } }; -var f5 = { a: {}, get a() { return {}; } }; -var f6 = { a: 0, get 'a'() { return 0; } }; -var f7 = { 'a': 0, get a() { return 0; } }; -var f8 = { 'a': 0, get "a"() { return 0; } }; -var f9 = { 'a': 0, get 'a'() { return 0; } }; -var f10 = { "a": 0, get 'a'() { return 0; } }; -var f11 = { 1.0: 0, get '1'() { return 0; } }; -var f12 = { 0: 0, get 0() { return 0; } }; -var f13 = { 0: 0, get 0() { return 0; } }; -var f14 = { 0: 0, get 0x0() { return 0; } }; -var f14 = { 0: 0, get 000() { return 0; } }; -var f15 = { "100": 0, get 1e2() { return 0; } }; -var f16 = { 0x20: 0, get 3.2e1() { return 0; } }; -var f17 = { a: 0, get b() { return 1; }, get a() { return 0; } }; - -// Get and set accessor with mismatched type annotations -var g1 = { get a(): number { return 4; }, set a(n: string) { } }; -var g2 = { get a() { return 4; }, set a(n: string) { } }; -var g3 = { get a(): number { return undefined; }, set a(n: string) { } }; - - -//// [objectLiteralErrors.js] -var e1 = { a: 0, a: 0 }; -var e2 = { a: '', a: '' }; -var e3 = { a: 0, a: '' }; -var e4 = { a: true, a: false }; -var e5 = { a: {}, a: {} }; -var e6 = { a: 0, 'a': 0 }; -var e7 = { 'a': 0, a: 0 }; -var e8 = { 'a': 0, "a": 0 }; -var e9 = { 'a': 0, 'a': 0 }; -var e10 = { "a": 0, 'a': 0 }; -var e11 = { 1.0: 0, '1': 0 }; -var e12 = { 0: 0, 0: 0 }; -var e13 = { 0: 0, 0: 0 }; -var e14 = { 0: 0, 0x0: 0 }; -var e14 = { 0: 0, 000: 0 }; -var e15 = { "100": 0, 1e2: 0 }; -var e16 = { 0x20: 0, 3.2e1: 0 }; -var e17 = { a: 0, b: 1, a: 0 }; -var f1 = { a: 0, get a() { - return 0; -} }; -var f2 = { a: '', get a() { - return ''; -} }; -var f3 = { a: 0, get a() { - return ''; -} }; -var f4 = { a: true, get a() { - return false; -} }; -var f5 = { a: {}, get a() { - return {}; -} }; -var f6 = { a: 0, get 'a'() { - return 0; -} }; -var f7 = { 'a': 0, get a() { - return 0; -} }; -var f8 = { 'a': 0, get "a"() { - return 0; -} }; -var f9 = { 'a': 0, get 'a'() { - return 0; -} }; -var f10 = { "a": 0, get 'a'() { - return 0; -} }; -var f11 = { 1.0: 0, get '1'() { - return 0; -} }; -var f12 = { 0: 0, get 0() { - return 0; -} }; -var f13 = { 0: 0, get 0() { - return 0; -} }; -var f14 = { 0: 0, get 0x0() { - return 0; -} }; -var f14 = { 0: 0, get 000() { - return 0; -} }; -var f15 = { "100": 0, get 1e2() { - return 0; -} }; -var f16 = { 0x20: 0, get 3.2e1() { - return 0; -} }; -var f17 = { a: 0, get b() { - return 1; -}, get a() { - return 0; -} }; -var g1 = { get a() { - return 4; -}, set a(n) { -} }; -var g2 = { get a() { - return 4; -}, set a(n) { -} }; -var g3 = { get a() { - return undefined; -}, set a(n) { -} }; diff --git a/tests/baselines/reference/parserStrictMode14.errors.txt b/tests/baselines/reference/parserStrictMode14.errors.txt index 03cd5223229..a30a8863229 100644 --- a/tests/baselines/reference/parserStrictMode14.errors.txt +++ b/tests/baselines/reference/parserStrictMode14.errors.txt @@ -1,11 +1,10 @@ ==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (2 errors) ==== "use strict"; with (a) { - ~~~~~~~~~~ + ~~~~ +!!! 'with' statements are not allowed in strict mode. ~ !!! All symbols within a 'with' block will be resolved to 'any'. ~ !!! Cannot find name 'a'. } - ~ -!!! 'with' statements are not allowed in strict mode. diff --git a/tests/baselines/reference/twoAccessorsWithSameName.errors.txt b/tests/baselines/reference/twoAccessorsWithSameName.errors.txt index e3631f617d9..edac011d718 100644 --- a/tests/baselines/reference/twoAccessorsWithSameName.errors.txt +++ b/tests/baselines/reference/twoAccessorsWithSameName.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/classes/propertyMemberDeclarations/twoAccessorsWithSameName.ts (13 errors) ==== +==== tests/cases/conformance/classes/propertyMemberDeclarations/twoAccessorsWithSameName.ts (14 errors) ==== class C { get x() { return 1; } ~ @@ -44,6 +44,8 @@ ~ !!! Accessors are only available when targeting ECMAScript 5 and higher. ~ +!!! An object literal cannot have multiple get/set accessors with the same name. + ~ !!! Duplicate identifier 'x'. return 1; } From 48ff93963b08c4db58fae54e0e65f2cf7841f06f Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 24 Jul 2014 12:49:54 -0700 Subject: [PATCH 6/7] added comments --- src/compiler/parser.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 3a40e487970..7afb0440909 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -801,6 +801,7 @@ module ts { if (isListElement(kind, /* inErrorRecovery */ false)) { var element = parseElement(); result.push(element); + // test elements only if we are not already in strict mode if (!isInStrictMode && checkForStrictMode) { if (isPrologueDirective(element)) { if (isUseStrictPrologueDirective(element)) { From 7072711cf99568776fb978956c12654764754e70 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 24 Jul 2014 13:09:03 -0700 Subject: [PATCH 7/7] updated test baselines --- tests/baselines/reference/parserStrictMode14.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/parserStrictMode14.errors.txt b/tests/baselines/reference/parserStrictMode14.errors.txt index a30a8863229..87439c1a29d 100644 --- a/tests/baselines/reference/parserStrictMode14.errors.txt +++ b/tests/baselines/reference/parserStrictMode14.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode14.ts (3 errors) ==== "use strict"; with (a) { ~~~~ @@ -7,4 +7,4 @@ !!! All symbols within a 'with' block will be resolved to 'any'. ~ !!! Cannot find name 'a'. - } + } \ No newline at end of file