added collision check for '_this'

This commit is contained in:
Vladimir Matveev
2014-07-18 16:13:21 -07:00
parent 1abedc30c4
commit 30ecd19029
21 changed files with 417 additions and 6 deletions

View File

@@ -59,6 +59,7 @@ module ts {
var mergedSymbols: Symbol[] = [];
var symbolLinks: SymbolLinks[] = [];
var nodeLinks: NodeLinks[] = [];
var potentialThisCollisions: Node[] = [];
var diagnostics: Diagnostic[] = [];
var diagnosticsModified: boolean = false;
@@ -3210,6 +3211,7 @@ module ts {
getNodeLinks(node).resolvedSymbol = symbol;
checkCollisionWithCapturedSuperVariable(node, node);
checkCollisionWithCapturedThisVariable(node, node);
checkCollisionWithIndexVariableInGeneratedCode(node, node);
return getTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol));
@@ -4436,6 +4438,7 @@ module ts {
}
checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithArgumentsInGeneratedCode(node);
if (program.getCompilerOptions().noImplicitAny && !node.type) {
switch (node.kind) {
@@ -4970,21 +4973,59 @@ module ts {
}
}
function checkCollisionWithCapturedSuperVariable(node: Node, name: Identifier) {
if (!(name && name.text === "_super")) {
return;
function needCollisionCheckForIdentifier(node: Node, identifier: Identifier, name: string): boolean {
if (!(identifier && identifier.text === name)) {
return false;
}
if (node.kind === SyntaxKind.Property ||
node.kind === SyntaxKind.Method ||
node.kind === SyntaxKind.GetAccessor ||
node.kind === SyntaxKind.SetAccessor) {
// it is ok to have member named '_super' - member access is always qualified
return;
// it is ok to have member named '_super' or '_this' - member access is always qualified
return false
}
if (isInAmbientContext(node)) {
// ambient context - no codegen impact
return false;
}
if (node.kind === SyntaxKind.Parameter && !(<FunctionDeclaration>node.parent).body) {
// just an overload - no codegen impact
return false;
}
return true;
}
function checkCollisionWithCapturedThisVariable(node: Node, name: Identifier): void {
if (!needCollisionCheckForIdentifier(node, name, "_this")) {
return;
}
potentialThisCollisions.push(node);
}
// this function will run after checking the source file so 'CaptureThis' for all nodes
function checkIfThisIsCapturedInEnclosingScope(node: Node): void {
var current = node;
while (current) {
if (getNodeCheckFlags(current) & NodeCheckFlags.CaptureThis) {
var isDeclaration = node.kind !== SyntaxKind.Identifier;
if (isDeclaration) {
error((<Declaration>node).name, Diagnostics.Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference);
}
else {
error(node, Diagnostics.Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference);
}
return;
}
current = current.parent;
}
}
function checkCollisionWithCapturedSuperVariable(node: Node, name: Identifier) {
if (!needCollisionCheckForIdentifier(node, name, "_super")) {
return;
}
@@ -5029,6 +5070,7 @@ module ts {
}
checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
if (!useTypeFromValueDeclaration) {
// TypeScript 1.0 spec (April 2014): 5.1
// Multiple declarations for the same variable name in the same declaration space are permitted,
@@ -5298,6 +5340,7 @@ module ts {
checkDeclarationModifiers(node);
checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0);
checkTypeParameters(node.typeParameters);
checkCollisionWithCapturedThisVariable(node, node.name);
var symbol = getSymbolOfNode(node);
var type = <InterfaceType>getDeclaredTypeOfSymbol(symbol);
var staticType = <ObjectType>getTypeOfSymbol(symbol);
@@ -5498,6 +5541,7 @@ module ts {
function checkEnumDeclaration(node: EnumDeclaration) {
checkDeclarationModifiers(node);
checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0);
checkCollisionWithCapturedThisVariable(node, node.name);
var enumSymbol = getSymbolOfNode(node);
var enumType = getDeclaredTypeOfSymbol(enumSymbol);
var autoValue = 0;
@@ -5569,6 +5613,7 @@ module ts {
function checkModuleDeclaration(node: ModuleDeclaration) {
checkDeclarationModifiers(node);
checkCollisionWithCapturedThisVariable(node, node.name);
var symbol = getSymbolOfNode(node);
if (symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length > 1 && !isInAmbientContext(node)) {
var classOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol);
@@ -5594,6 +5639,7 @@ module ts {
function checkImportDeclaration(node: ImportDeclaration) {
checkDeclarationModifiers(node);
checkCollisionWithCapturedThisVariable(node, node.name);
var symbol = getSymbolOfNode(node);
var target: Symbol;
@@ -5751,6 +5797,7 @@ module ts {
var links = getNodeLinks(node);
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
emitExtends = false;
potentialThisCollisions.length = 0;
forEach(node.statements, checkSourceElement);
if (node.flags & NodeFlags.ExternalModule) {
var symbol = getExportAssignmentSymbol(node.symbol);
@@ -5759,6 +5806,10 @@ module ts {
getSymbolLinks(symbol).referenced = true;
}
}
if (potentialThisCollisions.length) {
forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope);
potentialThisCollisions.length = 0;
}
if (emitExtends) links.flags |= NodeCheckFlags.EmitExtends;
links.flags |= NodeCheckFlags.TypeChecked;
}

View File

@@ -135,7 +135,9 @@ module ts {
Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: { code: 2194, category: DiagnosticCategory.Error, key: "Return type of constructor signature must be assignable to the instance type of the class" },
Ambient_external_module_declaration_cannot_specify_relative_module_name: { code: 2196, category: DiagnosticCategory.Error, key: "Ambient external module declaration cannot specify relative module name." },
Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: { code: 2197, category: DiagnosticCategory.Error, key: "Import declaration in an ambient external module declaration cannot reference external module through relative external module name." },
Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: { code: 2200, category: DiagnosticCategory.Error, key: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference." },
Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: { code: 2205, category: DiagnosticCategory.Error, key: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference." },
Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: { code: 2206, category: DiagnosticCategory.Error, key: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference." },
Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference: { code: 2207, category: DiagnosticCategory.Error, key: "Expression resolves to '_super' that compiler uses to capture base class reference." },
Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter: { code: 2224, category: DiagnosticCategory.Error, key: "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter." },
Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: { code: 2225, category: DiagnosticCategory.Error, key: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters." },

View File

@@ -534,10 +534,18 @@
"category": "Error",
"code": 2197
},
"Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": {
"category": "Error",
"code": 2200
},
"Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.": {
"category": "Error",
"code": 2205
},
"Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.": {
"category": "Error",
"code": 2206
},
"Expression resolves to '_super' that compiler uses to capture base class reference.": {
"category": "Error",
"code": 2207