Chromium Code Reviews| 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"; |
|
rossberg
2015/03/04 10:39:27
Nit: format like others.
marja
2015/03/04 11:14:38
clang-format wants it this way :/ Instead, formatt
rossberg
2015/03/04 12:39:33
I wish we would just fracking nuke this clang-form
|
| } |
| 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; |
|
rossberg
2015/03/04 10:39:27
Can't we simplify the logic by returning true here
marja
2015/03/04 11:14:38
Done.
|
| + 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_ || |