Merge pull request #3517 from Microsoft/strictMode

Remove 'strict mode' from parsing and checking, and make it purely something purely checked at bind time.
This commit is contained in:
CyrusNajmabadi 2015-06-15 23:41:41 -07:00
commit 718dc5b7a8
30 changed files with 411 additions and 332 deletions

View file

@ -88,6 +88,12 @@ namespace ts {
let container: Node;
let blockScopeContainer: Node;
let lastContainer: Node;
// If this file is an external module, then it is automatically in strict-mode according to
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
// not depending on if we see "use strict" in certain places (or if we hit a class/namespace).
let inStrictMode = !!file.externalModuleIndicator;
let symbolCount = 0;
let Symbol = objectAllocator.getSymbolConstructor();
let classifiableNames: Map<string> = {};
@ -531,6 +537,51 @@ namespace ts {
typeLiteralSymbol.members = { [symbol.name]: symbol };
}
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
const enum ElementKind {
Property = 1,
Accessor = 2
}
if (inStrictMode) {
let seen: Map<ElementKind> = {};
for (let prop of node.properties) {
if (prop.name.kind !== SyntaxKind.Identifier) {
continue;
}
let identifier = <Identifier>prop.name;
// 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
let currentKind = prop.kind === SyntaxKind.PropertyAssignment || prop.kind === SyntaxKind.ShorthandPropertyAssignment || prop.kind === SyntaxKind.MethodDeclaration
? ElementKind.Property
: ElementKind.Accessor;
let existingKind = seen[identifier.text];
if (!existingKind) {
seen[identifier.text] = currentKind;
continue;
}
if (currentKind === ElementKind.Property && existingKind === ElementKind.Property) {
let span = getErrorSpanForNode(file, identifier);
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode));
}
}
}
return bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
}
function bindAnonymousDeclaration(node: Declaration, symbolFlags: SymbolFlags, name: string) {
let symbol = createSymbol(symbolFlags, name);
addDeclarationToSymbol(symbol, node, symbolFlags);
@ -563,20 +614,135 @@ namespace ts {
// The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
// check for reserved words used as identifiers in strict mode code.
function checkStrictModeIdentifier(node: Identifier) {
if (node.parserContextFlags & ParserContextFlags.StrictMode &&
if (inStrictMode &&
node.originalKeywordKind >= SyntaxKind.FirstFutureReservedWord &&
node.originalKeywordKind <= SyntaxKind.LastFutureReservedWord &&
!isIdentifierName(node)) {
// Report error only if there are no parse errors in file
if (!file.parseDiagnostics.length) {
let message = getAncestor(node, SyntaxKind.ClassDeclaration) || getAncestor(node, SyntaxKind.ClassExpression) ?
Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode :
Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
file.bindDiagnostics.push(createDiagnosticForNode(node, message, declarationNameToString(node)));
file.bindDiagnostics.push(createDiagnosticForNode(node,
getStrictModeIdentifierMessage(node), declarationNameToString(node)));
}
}
}
function getStrictModeIdentifierMessage(node: Node) {
// Provide specialized messages to help the user understand why we think they're in
// strict mode.
if (getAncestor(node, SyntaxKind.ClassDeclaration) || getAncestor(node, SyntaxKind.ClassExpression)) {
return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode;
}
if (file.externalModuleIndicator) {
return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode;
}
return Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
}
function checkStrictModeBinaryExpression(node: BinaryExpression) {
if (inStrictMode && isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
// 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)
checkStrictModeEvalOrArguments(node, <Identifier>node.left);
}
}
function checkStrictModeCatchClause(node: CatchClause) {
// 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
if (inStrictMode && node.variableDeclaration) {
checkStrictModeEvalOrArguments(node, node.variableDeclaration.name);
}
}
function checkStrictModeDeleteExpression(node: DeleteExpression) {
// Grammar checking
if (inStrictMode && node.expression.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
let span = getErrorSpanForNode(file, node.expression);
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode));
}
}
function isEvalOrArgumentsIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier &&
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
}
function checkStrictModeEvalOrArguments(contextNode: Node, name: Node) {
if (name && name.kind === SyntaxKind.Identifier) {
let identifier = <Identifier>name;
if (isEvalOrArgumentsIdentifier(identifier)) {
// We check first if the name is inside class declaration or class expression; if so give explicit message
// otherwise report generic error message.
let span = getErrorSpanForNode(file, name);
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length,
getStrictModeEvalOrArgumentsMessage(contextNode), identifier.text));
}
}
}
function getStrictModeEvalOrArgumentsMessage(node: Node) {
// Provide specialized messages to help the user understand why we think they're in
// strict mode.
if (getAncestor(node, SyntaxKind.ClassDeclaration) || getAncestor(node, SyntaxKind.ClassExpression)) {
return Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode;
}
if (file.externalModuleIndicator) {
return Diagnostics.Invalid_use_of_0_Modules_are_automatically_in_strict_mode;
}
return Diagnostics.Invalid_use_of_0_in_strict_mode;
}
function checkStrictModeFunctionName(node: FunctionLikeDeclaration) {
if (inStrictMode) {
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1))
checkStrictModeEvalOrArguments(node, node.name);
}
}
function checkStrictModeNumericLiteral(node: LiteralExpression) {
if (inStrictMode && node.flags & NodeFlags.OctalLiteral) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode));
}
}
function checkStrictModePostfixUnaryExpression(node: PostfixUnaryExpression) {
// Grammar checking
// 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 (inStrictMode) {
checkStrictModeEvalOrArguments(node, <Identifier>node.operand);
}
}
function checkStrictModePrefixUnaryExpression(node: PrefixUnaryExpression) {
// Grammar checking
if (inStrictMode) {
if (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) {
checkStrictModeEvalOrArguments(node, <Identifier>node.operand);
}
}
}
function checkStrictModeWithStatement(node: WithStatement) {
// Grammar checking for withStatement
if (inStrictMode) {
grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode);
}
}
function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) {
let span = getSpanOfTokenAtPosition(file, node.pos);
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
}
function getDestructuringParameterName(node: Declaration) {
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
}
@ -584,6 +750,11 @@ namespace ts {
function bind(node: Node) {
node.parent = parent;
var savedInStrictMode = inStrictMode;
if (!savedInStrictMode) {
updateStrictMode(node);
}
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
// and then potentially add the symbol to an appropriate symbol table. Possible
// destination symbol tables are:
@ -601,12 +772,70 @@ namespace ts {
// the current 'container' node when it changes. This helps us know which symbol table
// a local should go into for example.
bindChildren(node);
inStrictMode = savedInStrictMode;
}
function updateStrictMode(node: Node) {
switch (node.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.ModuleBlock:
updateStrictModeStatementList((<SourceFile | ModuleBlock>node).statements);
return;
case SyntaxKind.Block:
if (isFunctionLike(node.parent)) {
updateStrictModeStatementList((<Block>node).statements);
}
return;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
// All classes are automatically in strict mode in ES6.
inStrictMode = true;
return;
}
}
function updateStrictModeStatementList(statements: NodeArray<Statement>) {
for (let statement of statements) {
if (!isPrologueDirective(statement)) {
return;
}
if (isUseStrictPrologueDirective(<ExpressionStatement>statement)) {
inStrictMode = true;
return;
}
}
}
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
function isUseStrictPrologueDirective(node: ExpressionStatement): boolean {
let nodeText = getTextOfNodeFromSourceText(file.text, node.expression);
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
// string to contain unicode escapes (as per ES5).
return nodeText === '"use strict"' || nodeText === "'use strict'";
}
function bindWorker(node: Node) {
switch (node.kind) {
case SyntaxKind.Identifier:
return checkStrictModeIdentifier(<Identifier>node);
case SyntaxKind.BinaryExpression:
return checkStrictModeBinaryExpression(<BinaryExpression>node);
case SyntaxKind.CatchClause:
return checkStrictModeCatchClause(<CatchClause>node);
case SyntaxKind.DeleteExpression:
return checkStrictModeDeleteExpression(<DeleteExpression>node);
case SyntaxKind.NumericLiteral:
return checkStrictModeNumericLiteral(<LiteralExpression>node);
case SyntaxKind.PostfixUnaryExpression:
return checkStrictModePostfixUnaryExpression(<PostfixUnaryExpression>node);
case SyntaxKind.PrefixUnaryExpression:
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
case SyntaxKind.WithStatement:
return checkStrictModeWithStatement(<WithStatement>node);
case SyntaxKind.TypeParameter:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
case SyntaxKind.Parameter:
@ -635,6 +864,7 @@ namespace ts {
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Method | ((<MethodDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None),
isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes);
case SyntaxKind.FunctionDeclaration:
checkStrictModeFunctionName(<FunctionDeclaration>node);
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
case SyntaxKind.Constructor:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Constructor, /*symbolExcludes:*/ SymbolFlags.None);
@ -648,9 +878,10 @@ namespace ts {
case SyntaxKind.TypeLiteral:
return bindAnonymousDeclaration(<TypeLiteralNode>node, SymbolFlags.TypeLiteral, "__type");
case SyntaxKind.ObjectLiteralExpression:
return bindAnonymousDeclaration(<ObjectLiteralExpression>node, SymbolFlags.ObjectLiteral, "__object");
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
checkStrictModeFunctionName(<FunctionExpression>node);
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, "__function");
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
@ -756,6 +987,10 @@ namespace ts {
}
function bindVariableDeclarationOrBindingElement(node: VariableDeclaration | BindingElement) {
if (inStrictMode) {
checkStrictModeEvalOrArguments(node, node.name)
}
if (!isBindingPattern(node.name)) {
if (isBlockOrCatchScoped(node)) {
bindBlockScopedVariableDeclaration(node);
@ -779,6 +1014,12 @@ namespace ts {
}
function bindParameter(node: ParameterDeclaration) {
if (inStrictMode) {
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
// strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
checkStrictModeEvalOrArguments(node, node.name);
}
if (isBindingPattern(node.name)) {
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, getDestructuringParameterName(node));
}

View file

@ -7734,7 +7734,7 @@ namespace ts {
// Grammar checking
let hasGrammarError = checkGrammarFunctionLikeDeclaration(node);
if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) {
checkGrammarFunctionName(node.name) || checkGrammarForGenerator(node);
checkGrammarForGenerator(node);
}
// The identityMapper object is used to indicate that function expressions are wildcards
@ -7891,14 +7891,7 @@ namespace ts {
}
function checkDeleteExpression(node: DeleteExpression): Type {
// Grammar checking
if (node.parserContextFlags & ParserContextFlags.StrictMode && node.expression.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(node.expression, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode);
}
let operandType = checkExpression(node.expression);
checkExpression(node.expression);
return booleanType;
}
@ -7913,14 +7906,6 @@ namespace ts {
}
function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type {
// Grammar checking
// 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 ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken)) {
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.operand);
}
let operandType = checkExpression(node.operand);
switch (node.operator) {
case SyntaxKind.PlusToken:
@ -7947,12 +7932,6 @@ namespace ts {
}
function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type {
// Grammar checking
// 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.
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.operand);
let operandType = checkExpression(node.operand);
let ok = checkArithmeticOperandType(node.operand, operandType, Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
if (ok) {
@ -8132,13 +8111,6 @@ namespace ts {
}
function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) {
// Grammar checking
if (isLeftHandSideExpression(node.left) && isAssignmentOperator(node.operatorToken.kind)) {
// 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)
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.left);
}
let operator = node.operatorToken.kind;
if (operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
return checkDestructuringAssignment(node.left, checkExpression(node.right, contextualMapper), contextualMapper);
@ -8580,11 +8552,9 @@ namespace ts {
// 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 FunctionLikeDeclaration or FunctionExpression(13.1)
// Grammar checking
checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
checkGrammarDecorators(node) || checkGrammarModifiers(node);
checkVariableLikeDeclaration(node);
let func = getContainingFunction(node);
@ -9476,9 +9446,7 @@ namespace ts {
function checkFunctionDeclaration(node: FunctionDeclaration): void {
if (produceDiagnostics) {
checkFunctionLikeDeclaration(node) ||
checkGrammarFunctionName(node.name) ||
checkGrammarForGenerator(node);
checkFunctionLikeDeclaration(node) || checkGrammarForGenerator(node);
checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
@ -10305,12 +10273,7 @@ namespace ts {
}
function checkWithStatement(node: WithStatement) {
// Grammar checking for withStatement
if (!checkGrammarStatementInAmbientContext(node)) {
if (node.parserContextFlags & ParserContextFlags.StrictMode) {
grammarErrorOnFirstToken(node, Diagnostics.with_statements_are_not_allowed_in_strict_mode);
}
}
checkGrammarStatementInAmbientContext(node);
checkExpression(node.expression);
error(node.expression, Diagnostics.All_symbols_within_a_with_block_will_be_resolved_to_any);
@ -10414,10 +10377,6 @@ namespace ts {
grammarErrorOnNode(localSymbol.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, identifierName);
}
}
// 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
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>catchClause.variableDeclaration.name);
}
}
@ -13022,11 +12981,6 @@ namespace ts {
}
}
function checkGrammarFunctionName(name: Node) {
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression (13.1))
return checkGrammarEvalOrArgumentsInStrictMode(name, <Identifier>name);
}
function checkGrammarForInvalidQuestionMark(node: Declaration, questionToken: Node, message: DiagnosticMessage): boolean {
if (questionToken) {
return grammarErrorOnNode(questionToken, message);
@ -13039,7 +12993,6 @@ namespace ts {
let GetAccessor = 2;
let SetAccesor = 4;
let GetOrSetAccessor = GetAccessor | SetAccesor;
let inStrictMode = (node.parserContextFlags & ParserContextFlags.StrictMode) !== 0;
for (let prop of node.properties) {
let name = prop.name;
@ -13086,9 +13039,7 @@ namespace ts {
else {
let existingKind = seen[(<Identifier>name).text];
if (currentKind === Property && existingKind === Property) {
if (inStrictMode) {
grammarErrorOnNode(name, Diagnostics.An_object_literal_cannot_have_multiple_properties_with_the_same_name_in_strict_mode);
}
continue;
}
else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) {
if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) {
@ -13311,9 +13262,6 @@ namespace ts {
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
}
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
return checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
}
function checkGrammarVariableDeclaration(node: VariableDeclaration) {
@ -13345,8 +13293,7 @@ namespace ts {
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
// and its Identifier is eval or arguments
return (checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name)) ||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
return checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name);
}
function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean {
@ -13485,25 +13432,6 @@ namespace ts {
}
}
function checkGrammarEvalOrArgumentsInStrictMode(contextNode: Node, name: Node): boolean {
if (name && name.kind === SyntaxKind.Identifier) {
let identifier = <Identifier>name;
if (contextNode && (contextNode.parserContextFlags & ParserContextFlags.StrictMode) && isEvalOrArgumentsIdentifier(identifier)) {
// We check first if the name is inside class declaration or class expression; if so give explicit message
// otherwise report generic error message.
let message = getAncestor(identifier, SyntaxKind.ClassDeclaration) || getAncestor(identifier, SyntaxKind.ClassExpression) ?
Diagnostics.Invalid_use_of_0_Class_definitions_are_automatically_in_strict_mode :
Diagnostics.Invalid_use_of_0_in_strict_mode;
return grammarErrorOnNode(identifier, message, declarationNameToString(identifier));
}
}
}
function isEvalOrArgumentsIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier &&
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
}
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
if (node.typeParameters) {
return grammarErrorAtPos(getSourceFileOfNode(node), node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
@ -13613,13 +13541,8 @@ namespace ts {
function checkGrammarNumericLiteral(node: Identifier): boolean {
// Grammar checking
if (node.flags & NodeFlags.OctalLiteral) {
if (node.parserContextFlags & ParserContextFlags.StrictMode) {
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode);
}
else if (languageVersion >= ScriptTarget.ES5) {
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher);
}
if (node.flags & NodeFlags.OctalLiteral && languageVersion >= ScriptTarget.ES5) {
return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher);
}
}

View file

@ -171,6 +171,8 @@ namespace ts {
A_class_declaration_without_the_default_modifier_must_have_a_name: { code: 1211, category: DiagnosticCategory.Error, key: "A class declaration without the 'default' modifier must have a name" },
Identifier_expected_0_is_a_reserved_word_in_strict_mode: { code: 1212, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode" },
Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1213, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." },
Identifier_expected_0_is_a_reserved_word_in_strict_mode_Modules_are_automatically_in_strict_mode: { code: 1214, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. Modules are automatically in strict mode." },
Invalid_use_of_0_Modules_are_automatically_in_strict_mode: { code: 1215, category: DiagnosticCategory.Error, key: "Invalid use of '{0}'. Modules are automatically in strict mode." },
Export_assignment_is_not_supported_when_module_flag_is_system: { code: 1218, category: DiagnosticCategory.Error, key: "Export assignment is not supported when '--module' flag is 'system'." },
Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Specify_experimentalDecorators_to_remove_this_warning: { code: 1219, category: DiagnosticCategory.Error, key: "Experimental support for decorators is a feature that is subject to change in a future release. Specify '--experimentalDecorators' to remove this warning." },
Generators_are_only_available_when_targeting_ECMAScript_6_or_higher: { code: 1220, category: DiagnosticCategory.Error, key: "Generators are only available when targeting ECMAScript 6 or higher." },

View file

@ -671,6 +671,14 @@
"category": "Error",
"code": 1213
},
"Identifier expected. '{0}' is a reserved word in strict mode. Modules are automatically in strict mode.": {
"category": "Error",
"code": 1214
},
"Invalid use of '{0}'. Modules are automatically in strict mode.": {
"category": "Error",
"code": 1215
},
"Export assignment is not supported when '--module' flag is 'system'.": {
"category": "Error",
"code": 1218

View file

@ -544,7 +544,7 @@ namespace ts {
token = nextToken();
processReferenceComments(sourceFile);
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseStatement);
sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement);
Debug.assert(token === SyntaxKind.EndOfFileToken);
sourceFile.endOfFileToken = parseTokenNode();
@ -647,10 +647,6 @@ namespace ts {
}
}
function setStrictModeContext(val: boolean) {
setContextFlag(val, ParserContextFlags.StrictMode);
}
function setDisallowInContext(val: boolean) {
setContextFlag(val, ParserContextFlags.DisallowIn);
}
@ -744,10 +740,6 @@ namespace ts {
return (contextFlags & ParserContextFlags.Yield) !== 0;
}
function inStrictModeContext() {
return (contextFlags & ParserContextFlags.StrictMode) !== 0;
}
function inGeneratorParameterContext() {
return (contextFlags & ParserContextFlags.GeneratorParameter) !== 0;
}
@ -1323,31 +1315,17 @@ namespace ts {
}
// Parses a list of elements
function parseList<T extends Node>(kind: ParsingContext, checkForStrictMode: boolean, parseElement: () => T): NodeArray<T> {
function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
let saveParsingContext = parsingContext;
parsingContext |= 1 << kind;
let result = <NodeArray<T>>[];
result.pos = getNodePos();
let savedStrictModeContext = inStrictModeContext();
while (!isListTerminator(kind)) {
if (isListElement(kind, /* inErrorRecovery */ false)) {
let element = parseListElement(kind, parseElement);
result.push(element);
// test elements only if we are not already in strict mode
if (checkForStrictMode && !inStrictModeContext()) {
if (isPrologueDirective(element)) {
if (isUseStrictPrologueDirective(element)) {
setStrictModeContext(true);
checkForStrictMode = false;
}
}
else {
checkForStrictMode = false;
}
}
continue;
}
@ -1356,22 +1334,11 @@ namespace ts {
}
}
setStrictModeContext(savedStrictModeContext);
result.end = getNodeEnd();
parsingContext = saveParsingContext;
return result;
}
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
function isUseStrictPrologueDirective(node: Node): boolean {
Debug.assert(isPrologueDirective(node));
let nodeText = getTextOfNodeFromSourceText(sourceText, (<ExpressionStatement>node).expression);
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
// string to contain unicode escapes (as per ES5).
return nodeText === '"use strict"' || nodeText === "'use strict'";
}
function parseListElement<T extends Node>(parsingContext: ParsingContext, parseElement: () => T): T {
let node = currentNode(parsingContext);
if (node) {
@ -2276,7 +2243,7 @@ namespace ts {
function parseObjectTypeMembers(): NodeArray<Declaration> {
let members: NodeArray<Declaration>;
if (parseExpected(SyntaxKind.OpenBraceToken)) {
members = parseList(ParsingContext.TypeMembers, /*checkForStrictMode*/ false, parseTypeMember);
members = parseList(ParsingContext.TypeMembers, parseTypeMember);
parseExpected(SyntaxKind.CloseBraceToken);
}
else {
@ -2645,12 +2612,6 @@ namespace ts {
return true;
}
if (inStrictModeContext()) {
// If we're in strict mode, then 'yield' is a keyword, could only ever start
// a yield expression.
return true;
}
// We're in a context where 'yield expr' is not allowed. However, if we can
// definitely tell that the user was trying to parse a 'yield expr' and not
// just a normal expr that start with a 'yield' identifier, then parse out
@ -2665,7 +2626,7 @@ namespace ts {
// for now we just check if the next token is an identifier. More heuristics
// can be added here later as necessary. We just need to make sure that we
// don't accidently consume something legal.
return lookAhead(nextTokenIsIdentifierOnSameLine);
return lookAhead(nextTokenIsIdentifierOrKeywordOrNumberOnSameLine);
}
return false;
@ -3508,10 +3469,10 @@ namespace ts {
}
// STATEMENTS
function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean, diagnosticMessage?: DiagnosticMessage): Block {
function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
let node = <Block>createNode(SyntaxKind.Block);
if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) {
node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatement);
node.statements = parseList(ParsingContext.BlockStatements, parseStatement);
parseExpected(SyntaxKind.CloseBraceToken);
}
else {
@ -3531,7 +3492,7 @@ namespace ts {
setDecoratorContext(false);
}
let block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true, diagnosticMessage);
let block = parseBlock(ignoreMissingOpenBrace, diagnosticMessage);
if (saveDecoratorContext) {
setDecoratorContext(true);
@ -3673,7 +3634,7 @@ namespace ts {
parseExpected(SyntaxKind.CaseKeyword);
node.expression = allowInAnd(parseExpression);
parseExpected(SyntaxKind.ColonToken);
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement);
node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
return finishNode(node);
}
@ -3681,7 +3642,7 @@ namespace ts {
let node = <DefaultClause>createNode(SyntaxKind.DefaultClause);
parseExpected(SyntaxKind.DefaultKeyword);
parseExpected(SyntaxKind.ColonToken);
node.statements = parseList(ParsingContext.SwitchClauseStatements, /*checkForStrictMode*/ false, parseStatement);
node.statements = parseList(ParsingContext.SwitchClauseStatements, parseStatement);
return finishNode(node);
}
@ -3697,7 +3658,7 @@ namespace ts {
parseExpected(SyntaxKind.CloseParenToken);
let caseBlock = <CaseBlock>createNode(SyntaxKind.CaseBlock, scanner.getStartPos());
parseExpected(SyntaxKind.OpenBraceToken);
caseBlock.clauses = parseList(ParsingContext.SwitchClauses, /*checkForStrictMode*/ false, parseCaseOrDefaultClause);
caseBlock.clauses = parseList(ParsingContext.SwitchClauses, parseCaseOrDefaultClause);
parseExpected(SyntaxKind.CloseBraceToken);
node.caseBlock = finishNode(caseBlock);
return finishNode(node);
@ -3724,14 +3685,14 @@ namespace ts {
let node = <TryStatement>createNode(SyntaxKind.TryStatement);
parseExpected(SyntaxKind.TryKeyword);
node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
node.tryBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
node.catchClause = token === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined;
// If we don't have a catch clause, then we must have a finally clause. Try to parse
// one out no matter what.
if (!node.catchClause || token === SyntaxKind.FinallyKeyword) {
parseExpected(SyntaxKind.FinallyKeyword);
node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace*/ false);
}
return finishNode(node);
@ -3745,7 +3706,7 @@ namespace ts {
}
parseExpected(SyntaxKind.CloseParenToken);
result.block = parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
result.block = parseBlock(/*ignoreMissingOpenBrace*/ false);
return finishNode(result);
}
@ -3786,6 +3747,11 @@ namespace ts {
return isIdentifierOrKeyword() && !scanner.hasPrecedingLineBreak();
}
function nextTokenIsIdentifierOrKeywordOrNumberOnSameLine() {
nextToken();
return (isIdentifierOrKeyword() || token === SyntaxKind.NumericLiteral) && !scanner.hasPrecedingLineBreak();
}
function isDeclaration(): boolean {
while (true) {
switch (token) {
@ -3913,16 +3879,15 @@ namespace ts {
}
}
function nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine() {
function nextTokenIsIdentifierOrStartOfDestructuring() {
nextToken();
return !scanner.hasPrecedingLineBreak() &&
(isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken);
return isIdentifier() || token === SyntaxKind.OpenBraceToken || token === SyntaxKind.OpenBracketToken;
}
function isLetDeclaration() {
// It is let declaration if in strict mode or next token is identifier\open bracket\open curly on same line.
// otherwise it needs to be treated like identifier
return inStrictModeContext() || lookAhead(nextTokenIsIdentifierOrStartOfDestructuringOnTheSameLine);
// In ES6 'let' always starts a lexical declaration if followed by an identifier or {
// or [.
return lookAhead(nextTokenIsIdentifierOrStartOfDestructuring);
}
function parseStatement(): Statement {
@ -3930,7 +3895,7 @@ namespace ts {
case SyntaxKind.SemicolonToken:
return parseEmptyStatement();
case SyntaxKind.OpenBraceToken:
return parseBlock(/*ignoreMissingOpenBrace*/ false, /*checkForStrictMode*/ false);
return parseBlock(/*ignoreMissingOpenBrace*/ false);
case SyntaxKind.VarKeyword:
return parseVariableStatement(scanner.getStartPos(), /*decorators*/ undefined, /*modifiers*/ undefined);
case SyntaxKind.LetKeyword:
@ -4448,10 +4413,6 @@ namespace ts {
}
function parseClassDeclarationOrExpression(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, kind: SyntaxKind): ClassLikeDeclaration {
// In ES6 specification, All parts of a ClassDeclaration or a ClassExpression are strict mode code
let savedStrictModeContext = inStrictModeContext();
setStrictModeContext(true);
var node = <ClassLikeDeclaration>createNode(kind, fullStart);
node.decorators = decorators;
setModifiers(node, modifiers);
@ -4474,9 +4435,7 @@ namespace ts {
node.members = createMissingList<ClassElement>();
}
var finishedNode = finishNode(node);
setStrictModeContext(savedStrictModeContext);
return finishedNode;
return finishNode(node);
}
function parseHeritageClauses(isClassHeritageClause: boolean): NodeArray<HeritageClause> {
@ -4494,7 +4453,7 @@ namespace ts {
}
function parseHeritageClausesWorker() {
return parseList(ParsingContext.HeritageClauses, /*checkForStrictMode*/ false, parseHeritageClause);
return parseList(ParsingContext.HeritageClauses, parseHeritageClause);
}
function parseHeritageClause() {
@ -4524,7 +4483,7 @@ namespace ts {
}
function parseClassMembers() {
return parseList(ParsingContext.ClassMembers, /*checkForStrictMode*/ false, parseClassElement);
return parseList(ParsingContext.ClassMembers, parseClassElement);
}
function parseInterfaceDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): InterfaceDeclaration {
@ -4582,7 +4541,7 @@ namespace ts {
function parseModuleBlock(): ModuleBlock {
let node = <ModuleBlock>createNode(SyntaxKind.ModuleBlock, scanner.getStartPos());
if (parseExpected(SyntaxKind.OpenBraceToken)) {
node.statements = parseList(ParsingContext.BlockStatements, /*checkForStrictMode*/ false, parseStatement);
node.statements = parseList(ParsingContext.BlockStatements, parseStatement);
parseExpected(SyntaxKind.CloseBraceToken);
}
else {

View file

@ -362,10 +362,6 @@ namespace ts {
export const enum ParserContextFlags {
None = 0,
// Set if this node was parsed in strict mode. Used for grammar error checks, as well as
// checking if the node can be reused in incremental settings.
StrictMode = 1 << 0,
// If this node was parsed in a context where 'in-expressions' are not allowed.
DisallowIn = 1 << 1,
@ -388,7 +384,7 @@ namespace ts {
JavaScriptFile = 1 << 6,
// Context flags set directly by the parser.
ParserGeneratedFlags = StrictMode | DisallowIn | Yield | GeneratorParameter | Decorator | ThisNodeHasError,
ParserGeneratedFlags = DisallowIn | Yield | GeneratorParameter | Decorator | ThisNodeHasError,
// Context flags computed by aggregating child flags upwards.

View file

@ -1,8 +1,11 @@
tests/cases/conformance/es6/variableDeclarations/VariableDeclaration11_es6.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/conformance/es6/variableDeclarations/VariableDeclaration11_es6.ts(2,1): error TS1212: Identifier expected. 'let' is a reserved word in strict mode
tests/cases/conformance/es6/variableDeclarations/VariableDeclaration11_es6.ts(2,1): error TS2304: Cannot find name 'let'.
==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration11_es6.ts (1 errors) ====
==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration11_es6.ts (2 errors) ====
"use strict";
let
!!! error TS1123: Variable declaration list cannot be empty.
~~~
!!! error TS1212: Identifier expected. 'let' is a reserved word in strict mode
~~~
!!! error TS2304: Cannot find name 'let'.

View file

@ -4,4 +4,4 @@ let
//// [VariableDeclaration11_es6.js]
"use strict";
let ;
let;

View file

@ -1,8 +1,14 @@
tests/cases/conformance/es6/yieldExpressions/YieldExpression18_es6.ts(2,1): error TS1163: A 'yield' expression is only allowed in a generator body.
tests/cases/conformance/es6/yieldExpressions/YieldExpression18_es6.ts(2,1): error TS1212: Identifier expected. 'yield' is a reserved word in strict mode
tests/cases/conformance/es6/yieldExpressions/YieldExpression18_es6.ts(2,1): error TS2304: Cannot find name 'yield'.
tests/cases/conformance/es6/yieldExpressions/YieldExpression18_es6.ts(2,7): error TS2304: Cannot find name 'foo'.
==== tests/cases/conformance/es6/yieldExpressions/YieldExpression18_es6.ts (1 errors) ====
==== tests/cases/conformance/es6/yieldExpressions/YieldExpression18_es6.ts (3 errors) ====
"use strict";
yield(foo);
~~~~~
!!! error TS1163: A 'yield' expression is only allowed in a generator body.
!!! error TS1212: Identifier expected. 'yield' is a reserved word in strict mode
~~~~~
!!! error TS2304: Cannot find name 'yield'.
~~~
!!! error TS2304: Cannot find name 'foo'.

View file

@ -4,4 +4,4 @@ yield(foo);
//// [YieldExpression18_es6.js]
"use strict";
yield (foo);
yield(foo);

View file

@ -1,9 +1,10 @@
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(5,20): error TS1005: ',' expected.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(5,27): error TS1109: Expression expected.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(8,23): error TS1109: Expression expected.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(13,16): error TS1102: 'delete' cannot be called on an identifier in strict mode.
==== tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts (3 errors) ====
==== tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts (4 errors) ====
// Unary operator delete
var ANY;
@ -23,5 +24,7 @@ tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperator
class testADelx {
constructor(public s: () => {}) {
delete s; //expect error
~
!!! error TS1102: 'delete' cannot be called on an identifier in strict mode.
}
}

View file

@ -1,8 +1,11 @@
tests/cases/compiler/downlevelLetConst11.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/compiler/downlevelLetConst11.ts(2,1): error TS1212: Identifier expected. 'let' is a reserved word in strict mode
tests/cases/compiler/downlevelLetConst11.ts(2,1): error TS2304: Cannot find name 'let'.
==== tests/cases/compiler/downlevelLetConst11.ts (1 errors) ====
==== tests/cases/compiler/downlevelLetConst11.ts (2 errors) ====
"use strict";
let
!!! error TS1123: Variable declaration list cannot be empty.
~~~
!!! error TS1212: Identifier expected. 'let' is a reserved word in strict mode
~~~
!!! error TS2304: Cannot find name 'let'.

View file

@ -4,4 +4,4 @@ let
//// [downlevelLetConst11.js]
"use strict";
var ;
let;

View file

@ -1,15 +1,18 @@
tests/cases/conformance/externalModules/exportNonInitializedVariablesAMD.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/conformance/externalModules/exportNonInitializedVariablesAMD.ts(3,1): error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/conformance/externalModules/exportNonInitializedVariablesAMD.ts(3,1): error TS2304: Cannot find name 'let'.
tests/cases/conformance/externalModules/exportNonInitializedVariablesAMD.ts(4,6): error TS1123: Variable declaration list cannot be empty.
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesAMD.ts (3 errors) ====
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesAMD.ts (4 errors) ====
var;
!!! error TS1123: Variable declaration list cannot be empty.
let;
~~~
!!! error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~
!!! error TS2304: Cannot find name 'let'.
const;

View file

@ -1,15 +1,18 @@
tests/cases/conformance/externalModules/exportNonInitializedVariablesCommonJS.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/conformance/externalModules/exportNonInitializedVariablesCommonJS.ts(3,1): error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/conformance/externalModules/exportNonInitializedVariablesCommonJS.ts(3,1): error TS2304: Cannot find name 'let'.
tests/cases/conformance/externalModules/exportNonInitializedVariablesCommonJS.ts(4,6): error TS1123: Variable declaration list cannot be empty.
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesCommonJS.ts (3 errors) ====
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesCommonJS.ts (4 errors) ====
var;
!!! error TS1123: Variable declaration list cannot be empty.
let;
~~~
!!! error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~
!!! error TS2304: Cannot find name 'let'.
const;

View file

@ -1,15 +1,18 @@
tests/cases/conformance/externalModules/exportNonInitializedVariablesES6.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/conformance/externalModules/exportNonInitializedVariablesES6.ts(3,1): error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/conformance/externalModules/exportNonInitializedVariablesES6.ts(3,1): error TS2304: Cannot find name 'let'.
tests/cases/conformance/externalModules/exportNonInitializedVariablesES6.ts(4,6): error TS1123: Variable declaration list cannot be empty.
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesES6.ts (3 errors) ====
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesES6.ts (4 errors) ====
var;
!!! error TS1123: Variable declaration list cannot be empty.
let;
~~~
!!! error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~
!!! error TS2304: Cannot find name 'let'.
const;

View file

@ -1,15 +1,18 @@
tests/cases/conformance/externalModules/exportNonInitializedVariablesSystem.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/conformance/externalModules/exportNonInitializedVariablesSystem.ts(3,1): error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/conformance/externalModules/exportNonInitializedVariablesSystem.ts(3,1): error TS2304: Cannot find name 'let'.
tests/cases/conformance/externalModules/exportNonInitializedVariablesSystem.ts(4,6): error TS1123: Variable declaration list cannot be empty.
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesSystem.ts (3 errors) ====
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesSystem.ts (4 errors) ====
var;
!!! error TS1123: Variable declaration list cannot be empty.
let;
~~~
!!! error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~
!!! error TS2304: Cannot find name 'let'.
const;

View file

@ -1,15 +1,18 @@
tests/cases/conformance/externalModules/exportNonInitializedVariablesUMD.ts(2,4): error TS1123: Variable declaration list cannot be empty.
tests/cases/conformance/externalModules/exportNonInitializedVariablesUMD.ts(3,1): error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/conformance/externalModules/exportNonInitializedVariablesUMD.ts(3,1): error TS2304: Cannot find name 'let'.
tests/cases/conformance/externalModules/exportNonInitializedVariablesUMD.ts(4,6): error TS1123: Variable declaration list cannot be empty.
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesUMD.ts (3 errors) ====
==== tests/cases/conformance/externalModules/exportNonInitializedVariablesUMD.ts (4 errors) ====
var;
!!! error TS1123: Variable declaration list cannot be empty.
let;
~~~
!!! error TS1214: Identifier expected. 'let' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~
!!! error TS2304: Cannot find name 'let'.
const;

View file

@ -0,0 +1,23 @@
tests/cases/conformance/es6/modules/t3.ts(1,17): error TS1214: Identifier expected. 'yield' is a reserved word in strict mode. Modules are automatically in strict mode.
==== tests/cases/conformance/es6/modules/t1.ts (0 errors) ====
let set = {
set foo(x: number) {
}
}
let get = 10;
export { set, get };
==== tests/cases/conformance/es6/modules/t2.ts (0 errors) ====
import * as set from "./t1";
==== tests/cases/conformance/es6/modules/t3.ts (1 errors) ====
import { set as yield } from "./t1";
~~~~~
!!! error TS1214: Identifier expected. 'yield' is a reserved word in strict mode. Modules are automatically in strict mode.
==== tests/cases/conformance/es6/modules/t4.ts (0 errors) ====
import { get } from "./t1";

View file

@ -1,30 +0,0 @@
=== tests/cases/conformance/es6/modules/t1.ts ===
let set = {
>set : Symbol(set, Decl(t1.ts, 1, 3))
set foo(x: number) {
>foo : Symbol(foo, Decl(t1.ts, 1, 11))
>x : Symbol(x, Decl(t1.ts, 2, 12))
}
}
let get = 10;
>get : Symbol(get, Decl(t1.ts, 5, 3))
export { set, get };
>set : Symbol(set, Decl(t1.ts, 7, 8))
>get : Symbol(get, Decl(t1.ts, 7, 13))
=== tests/cases/conformance/es6/modules/t2.ts ===
import * as set from "./t1";
>set : Symbol(set, Decl(t2.ts, 0, 6))
=== tests/cases/conformance/es6/modules/t3.ts ===
import { set as yield } from "./t1";
>set : Symbol(yield, Decl(t3.ts, 0, 8))
>yield : Symbol(yield, Decl(t3.ts, 0, 8))
=== tests/cases/conformance/es6/modules/t4.ts ===
import { get } from "./t1";
>get : Symbol(get, Decl(t4.ts, 0, 8))

View file

@ -1,32 +0,0 @@
=== tests/cases/conformance/es6/modules/t1.ts ===
let set = {
>set : { foo: number; }
>{ set foo(x: number) { }} : { foo: number; }
set foo(x: number) {
>foo : number
>x : number
}
}
let get = 10;
>get : number
>10 : number
export { set, get };
>set : { foo: number; }
>get : number
=== tests/cases/conformance/es6/modules/t2.ts ===
import * as set from "./t1";
>set : typeof set
=== tests/cases/conformance/es6/modules/t3.ts ===
import { set as yield } from "./t1";
>set : { foo: number; }
>yield : { foo: number; }
=== tests/cases/conformance/es6/modules/t4.ts ===
import { get } from "./t1";
>get : number

View file

@ -0,0 +1,15 @@
tests/cases/compiler/letAsIdentifier.ts(3,5): error TS2300: Duplicate identifier 'a'.
tests/cases/compiler/letAsIdentifier.ts(6,1): error TS2300: Duplicate identifier 'a'.
==== tests/cases/compiler/letAsIdentifier.ts (2 errors) ====
var let = 10;
var a = 10;
~
!!! error TS2300: Duplicate identifier 'a'.
let = 30;
let
a;
~
!!! error TS2300: Duplicate identifier 'a'.

View file

@ -10,10 +10,10 @@ a;
var let = 10;
var a = 10;
let = 30;
let;
a;
var a;
//// [letAsIdentifier.d.ts]
declare var let: number;
declare var a: number;
declare let a: any;

View file

@ -1,17 +0,0 @@
=== tests/cases/compiler/letAsIdentifier.ts ===
var let = 10;
>let : Symbol(let, Decl(letAsIdentifier.ts, 1, 3))
var a = 10;
>a : Symbol(a, Decl(letAsIdentifier.ts, 2, 3))
let = 30;
>let : Symbol(let, Decl(letAsIdentifier.ts, 1, 3))
let
>let : Symbol(let, Decl(letAsIdentifier.ts, 1, 3))
a;
>a : Symbol(a, Decl(letAsIdentifier.ts, 2, 3))

View file

@ -1,21 +0,0 @@
=== tests/cases/compiler/letAsIdentifier.ts ===
var let = 10;
>let : number
>10 : number
var a = 10;
>a : number
>10 : number
let = 30;
>let = 30 : number
>let : number
>30 : number
let
>let : number
a;
>a : number

View file

@ -1,20 +1,20 @@
tests/cases/compiler/letAsIdentifierInStrictMode.ts(2,5): error TS1212: Identifier expected. 'let' is a reserved word in strict mode
tests/cases/compiler/letAsIdentifierInStrictMode.ts(3,5): error TS2300: Duplicate identifier 'a'.
tests/cases/compiler/letAsIdentifierInStrictMode.ts(4,5): error TS1134: Variable declaration expected.
tests/cases/compiler/letAsIdentifierInStrictMode.ts(4,7): error TS1134: Variable declaration expected.
tests/cases/compiler/letAsIdentifierInStrictMode.ts(4,1): error TS1212: Identifier expected. 'let' is a reserved word in strict mode
tests/cases/compiler/letAsIdentifierInStrictMode.ts(6,1): error TS2300: Duplicate identifier 'a'.
==== tests/cases/compiler/letAsIdentifierInStrictMode.ts (4 errors) ====
"use strict";
var let = 10;
~~~
!!! error TS1212: Identifier expected. 'let' is a reserved word in strict mode
var a = 10;
~
!!! error TS2300: Duplicate identifier 'a'.
let = 30;
~
!!! error TS1134: Variable declaration expected.
~~
!!! error TS1134: Variable declaration expected.
~~~
!!! error TS1212: Identifier expected. 'let' is a reserved word in strict mode
let
a;
~

View file

@ -10,6 +10,5 @@ a;
"use strict";
var let = 10;
var a = 10;
var ;
30;
let = 30;
var a;

View file

@ -1,4 +1,4 @@
tests/cases/compiler/strictModeReservedWordInImportEqualDeclaration.ts(3,8): error TS1212: Identifier expected. 'public' is a reserved word in strict mode
tests/cases/compiler/strictModeReservedWordInImportEqualDeclaration.ts(3,8): error TS1214: Identifier expected. 'public' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/compiler/strictModeReservedWordInImportEqualDeclaration.ts(3,25): error TS2307: Cannot find module '1'.
@ -7,6 +7,6 @@ tests/cases/compiler/strictModeReservedWordInImportEqualDeclaration.ts(3,25): er
"use strict"
import public = require("1");
~~~~~~
!!! error TS1212: Identifier expected. 'public' is a reserved word in strict mode
!!! error TS1214: Identifier expected. 'public' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~
!!! error TS2307: Cannot find module '1'.

View file

@ -1,8 +1,8 @@
tests/cases/compiler/strictModeWordInImportDeclaration.ts(2,13): error TS1212: Identifier expected. 'package' is a reserved word in strict mode
tests/cases/compiler/strictModeWordInImportDeclaration.ts(2,13): error TS1214: Identifier expected. 'package' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/compiler/strictModeWordInImportDeclaration.ts(2,26): error TS2307: Cannot find module './1'.
tests/cases/compiler/strictModeWordInImportDeclaration.ts(3,16): error TS1212: Identifier expected. 'private' is a reserved word in strict mode
tests/cases/compiler/strictModeWordInImportDeclaration.ts(3,16): error TS1214: Identifier expected. 'private' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/compiler/strictModeWordInImportDeclaration.ts(3,30): error TS2307: Cannot find module './1'.
tests/cases/compiler/strictModeWordInImportDeclaration.ts(4,8): error TS1212: Identifier expected. 'public' is a reserved word in strict mode
tests/cases/compiler/strictModeWordInImportDeclaration.ts(4,8): error TS1214: Identifier expected. 'public' is a reserved word in strict mode. Modules are automatically in strict mode.
tests/cases/compiler/strictModeWordInImportDeclaration.ts(4,20): error TS2307: Cannot find module './1'.
@ -10,16 +10,16 @@ tests/cases/compiler/strictModeWordInImportDeclaration.ts(4,20): error TS2307: C
"use strict"
import * as package from "./1"
~~~~~~~
!!! error TS1212: Identifier expected. 'package' is a reserved word in strict mode
!!! error TS1214: Identifier expected. 'package' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~~~
!!! error TS2307: Cannot find module './1'.
import {foo as private} from "./1"
~~~~~~~
!!! error TS1212: Identifier expected. 'private' is a reserved word in strict mode
!!! error TS1214: Identifier expected. 'private' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~~~
!!! error TS2307: Cannot find module './1'.
import public from "./1"
~~~~~~
!!! error TS1212: Identifier expected. 'public' is a reserved word in strict mode
!!! error TS1214: Identifier expected. 'public' is a reserved word in strict mode. Modules are automatically in strict mode.
~~~~~
!!! error TS2307: Cannot find module './1'.

View file

@ -252,11 +252,6 @@ module ts {
});
it('Strict mode 1',() => {
// In non-strict mode 'package' means nothing and can be reused. In strict mode though
// we'll have to reparse the nodes (and generate an error for 'package();'
//
// Note: in this test we don't actually add 'use strict'. This is so we can compare
// reuse with/without a strict mode change.
var source = "foo1();\r\nfoo1();\r\nfoo1();\r\package();";
var oldText = ScriptSnapshot.fromString(source);
@ -266,23 +261,15 @@ module ts {
});
it('Strict mode 2',() => {
// In non-strict mode 'package' means nothing and can be reused. In strict mode though
// we'll have to reparse the nodes (and generate an error for 'package();'
var source = "foo1();\r\nfoo1();\r\nfoo1();\r\package();";
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withInsert(oldText, 0, "'use strict';\r\n");
// Note the decreased reuse of nodes compared to 'Strict mode 1'
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9);
});
it('Strict mode 3',() => {
// In non-strict mode 'package' means nothing and can be reused. In strict mode though
// we'll have to reparse the nodes (and generate an error for 'package();'
//
// Note: in this test we don't actually remove 'use strict'. This is so we can compare
// reuse with/without a strict mode change.
var source = "'strict';\r\nfoo1();\r\nfoo1();\r\nfoo1();\r\npackage();";
var index = source.indexOf('f');
@ -293,16 +280,13 @@ module ts {
});
it('Strict mode 4',() => {
// In non-strict mode 'package' means nothing and can be reused. In strict mode though
// we'll have to reparse the nodes (and generate an error for 'package();'
var source = "'use strict';\r\nfoo1();\r\nfoo1();\r\nfoo1();\r\npackage();";
var index = source.indexOf('f');
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withDelete(oldText, 0, index);
// Note the decreased reuse of nodes compared to testStrictMode3
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9);
});
it('Strict mode 5',() => {
@ -312,7 +296,7 @@ module ts {
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, index, 6, "strict");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 27);
});
it('Strict mode 6',() => {
@ -322,7 +306,7 @@ module ts {
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, index, 6, "blahhh");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 27);
});
it('Strict mode 7',() => {
@ -492,7 +476,6 @@ module ts {
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, index, ": Foo<Bar<".length, "= ");
// Note the decreased reuse of nodes compared to testStrictMode3
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0);
});
@ -545,7 +528,7 @@ module ts {
var index = source.lastIndexOf(";");
var newTextAndChange = withDelete(oldText, index, 1);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 11);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 14);
});
it('Edit after empty type parameter list',() => {
@ -555,7 +538,7 @@ module ts {
var index = source.length;
var newTextAndChange = withInsert(oldText, index, "var x;");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 2);
});
it('Delete parameter after comment',() => {
@ -595,7 +578,7 @@ constructor(name) { }\
var index = source.indexOf("100");
var newTextAndChange = withInsert(oldText, index, "'1', ");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 5);
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 7);
});
it('Insert declare modifier before module',() => {
@ -718,7 +701,7 @@ module m3 { }\
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, 0, "var v =".length, "class C");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); // As specified in ES6 specification, all parts of a ClassDeclaration or a ClassExpression are strict mode code.
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4);
});
it('Moving methods from object literal to class in strict mode', () => {
@ -736,7 +719,7 @@ module m3 { }\
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, 0, "class".length, "interface");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); // As specified in ES6 specification, all parts of a ClassDeclaration or a ClassExpression are strict mode code.
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 18);
});
it('Moving index signatures from class to interface in strict mode', () => {
@ -754,7 +737,7 @@ module m3 { }\
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, 0, "interface".length, "class");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); // As specified in ES6 specification, all parts of a ClassDeclaration or a ClassExpression are strict mode code.
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 18);
});
@ -782,7 +765,7 @@ module m3 { }\
var oldText = ScriptSnapshot.fromString(source);
var newTextAndChange = withChange(oldText, 0, "var v =".length, "class C");
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); // As specified in ES6 specification, all parts of a ClassDeclaration or a ClassExpression are strict mode code.
compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4);
});