Index: src/scopes.cc |
diff --git a/src/scopes.cc b/src/scopes.cc |
index 97a89431f39e1e824acda5d8d3a85c46df568c3c..4e7b14b46fac6bc4385cc230ab93d6383f7e73ff 100644 |
--- a/src/scopes.cc |
+++ b/src/scopes.cc |
@@ -798,6 +798,8 @@ static const char* Header(ScopeType scope_type) { |
case BLOCK_SCOPE: return "block"; |
case WITH_SCOPE: return "with"; |
case ARROW_SCOPE: return "arrow"; |
+ case CLASS_SCOPE: |
+ return "class"; |
} |
UNREACHABLE(); |
return NULL; |
@@ -1070,29 +1072,7 @@ bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy, |
case BOUND: |
// We found a variable binding. |
if (is_strong(language_mode())) { |
- // Check for declaration-after use (for variables) in strong mode. Note |
- // that we can only do this in the case where we have seen the |
- // declaration. And we always allow referencing functions (for now). |
- |
- // If both the use and the declaration are inside an eval scope |
- // (possibly indirectly), or one of them is, we need to check whether |
- // they are inside the same eval scope or different |
- // ones. |
- |
- // TODO(marja,rossberg): Detect errors across different evals (depends |
- // on the future of eval in strong mode). |
- const Scope* eval_for_use = NearestOuterEvalScope(); |
- const Scope* eval_for_declaration = |
- var->scope()->NearestOuterEvalScope(); |
- |
- if (proxy->position() != RelocInfo::kNoPosition && |
- proxy->position() < var->initializer_position() && |
- !var->is_function() && eval_for_use == eval_for_declaration) { |
- DCHECK(proxy->end_position() != RelocInfo::kNoPosition); |
- ReportMessage(proxy->position(), proxy->end_position(), |
- "strong_use_before_declaration", proxy->raw_name()); |
- return false; |
- } |
+ if (!CheckStrongModeDeclaration(proxy, var)) return false; |
} |
break; |
@@ -1137,6 +1117,50 @@ bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy, |
} |
+bool Scope::CheckStrongModeDeclaration(VariableProxy* proxy, Variable* var) { |
+ // Check for declaration-after use (for variables) in strong mode. Note that |
+ // we can only do this in the case where we have seen the declaration. And we |
+ // always allow referencing functions (for now). |
+ |
+ // If both the use and the declaration are inside an eval scope (possibly |
+ // indirectly), or one of them is, we need to check whether they are inside |
+ // the same eval scope or different ones. |
+ |
+ // TODO(marja,rossberg): Detect errors across different evals (depends on the |
+ // future of eval in strong mode). |
+ const Scope* eval_for_use = NearestOuterEvalScope(); |
+ const Scope* eval_for_declaration = var->scope()->NearestOuterEvalScope(); |
+ |
+ // Allow referencing the class name from methods, even though the initializer |
+ // position for class names is only after the body. Note that the only |
+ // variable declared in the class scope is the class name. |
+ bool legal_class_name_reference = false; |
+ if (var->scope()->is_class_scope()) { |
+ // Referencing the class name is only allowed inside methods of that class. |
+ Scope* scope = this; |
+ bool found_method_scope = false; |
+ while (scope && !found_method_scope && scope != var->scope()) { |
+ if (scope->is_function_scope() && scope->outer_scope_ == var->scope()) { |
+ found_method_scope = true; |
arv (Not doing code reviews)
2015/03/03 15:36:28
It is still not clear why this is only matching th
marja
2015/03/03 15:52:14
This check only fires when we have resolved the Va
|
+ break; |
+ } |
+ scope = scope->outer_scope(); |
+ } |
+ legal_class_name_reference = found_method_scope; |
+ } |
+ |
+ if (proxy->position() != RelocInfo::kNoPosition && |
+ proxy->position() < var->initializer_position() && !var->is_function() && |
+ eval_for_use == eval_for_declaration && !legal_class_name_reference) { |
+ DCHECK(proxy->end_position() != RelocInfo::kNoPosition); |
+ ReportMessage(proxy->position(), proxy->end_position(), |
+ "strong_use_before_declaration", proxy->raw_name()); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+ |
bool Scope::ResolveVariablesRecursively(CompilationInfo* info, |
AstNodeFactory* factory) { |
DCHECK(info->script_scope()->is_script_scope()); |
@@ -1201,7 +1225,8 @@ bool Scope::MustAllocate(Variable* var) { |
if ((var->is_this() || var->is_new_target() || !var->raw_name()->IsEmpty()) && |
(var->has_forced_context_allocation() || scope_calls_eval_ || |
inner_scope_calls_eval_ || scope_contains_with_ || is_catch_scope() || |
- is_block_scope() || is_module_scope() || is_script_scope())) { |
+ is_block_scope() || is_class_scope() || is_module_scope() || |
+ is_script_scope())) { |
var->set_is_used(); |
if (scope_calls_eval_ || inner_scope_calls_eval_) var->set_maybe_assigned(); |
} |
@@ -1223,7 +1248,10 @@ bool Scope::MustAllocateInContext(Variable* var) { |
if (has_forced_context_allocation()) return true; |
if (var->mode() == TEMPORARY) return false; |
if (var->mode() == INTERNAL) return true; |
- if (is_catch_scope() || is_block_scope() || is_module_scope()) return true; |
+ if (is_catch_scope() || is_block_scope() || is_class_scope() || |
+ is_module_scope()) { |
+ return true; |
+ } |
if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true; |
return var->has_forced_context_allocation() || |
scope_calls_eval_ || |