Chromium Code Reviews| Index: src/scopes.cc |
| diff --git a/src/scopes.cc b/src/scopes.cc |
| index 35449643cec2dce0742737c35b33e9b559b9ab0f..0c2eadb3fdbdbaa87797f567913b2994e85a7391 100644 |
| --- a/src/scopes.cc |
| +++ b/src/scopes.cc |
| @@ -34,6 +34,7 @@ Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, |
| VariableMode mode, bool is_valid_lhs, |
| Variable::Kind kind, |
| InitializationFlag initialization_flag, |
| + int position, |
| MaybeAssignedFlag maybe_assigned_flag) { |
| // AstRawStrings are unambiguous, i.e., the same string is always represented |
| // by the same AstRawString*. |
| @@ -43,8 +44,9 @@ Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, |
| if (p->value == NULL) { |
| // The variable has not been declared yet -> insert it. |
| DCHECK(p->key == name); |
| - p->value = new (zone()) Variable(scope, name, mode, is_valid_lhs, kind, |
| - initialization_flag, maybe_assigned_flag); |
| + p->value = new (zone()) |
| + Variable(scope, name, mode, is_valid_lhs, kind, initialization_flag, |
| + position, maybe_assigned_flag); |
| } |
| return reinterpret_cast<Variable*>(p->value); |
| } |
| @@ -263,7 +265,12 @@ bool Scope::Analyze(CompilationInfo* info) { |
| // Allocate the variables. |
| { |
| AstNodeFactory ast_node_factory(info->ast_value_factory()); |
| - if (!top->AllocateVariables(info, &ast_node_factory)) return false; |
| + if (!top->AllocateVariables(info, &ast_node_factory)) { |
| + DCHECK(top->pending_error_handler_.has_pending_error()); |
| + top->pending_error_handler_.ThrowPendingError(info->isolate(), |
| + info->script()); |
| + return false; |
| + } |
| } |
| #ifdef DEBUG |
| @@ -402,8 +409,9 @@ Variable* Scope::LookupLocal(const AstRawString* name) { |
| maybe_assigned_flag = kMaybeAssigned; |
| } |
| - Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, |
| - init_flag, maybe_assigned_flag); |
| + Variable* var = |
| + variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, |
| + RelocInfo::kNoPosition, maybe_assigned_flag); |
| var->AllocateTo(location, index); |
| return var; |
| } |
| @@ -418,9 +426,9 @@ Variable* Scope::LookupFunctionVar(const AstRawString* name, |
| VariableMode mode; |
| int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); |
| if (index < 0) return NULL; |
| - Variable* var = new(zone()) Variable( |
| - this, name, mode, true /* is valid LHS */, |
| - Variable::NORMAL, kCreatedInitialized); |
| + Variable* var = new (zone()) |
| + Variable(this, name, mode, true /* is valid LHS */, Variable::FUNCTION, |
| + kCreatedInitialized, RelocInfo::kNoPosition); |
| VariableProxy* proxy = factory->NewVariableProxy(var); |
| VariableDeclaration* declaration = factory->NewVariableDeclaration( |
| proxy, mode, this, RelocInfo::kNoPosition); |
| @@ -461,7 +469,8 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode, |
| Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
| - InitializationFlag init_flag, |
| + InitializationFlag init_flag, int position, |
| + bool is_function, |
| MaybeAssignedFlag maybe_assigned_flag) { |
| DCHECK(!already_resolved()); |
| // This function handles VAR, LET, and CONST modes. DYNAMIC variables are |
| @@ -469,8 +478,9 @@ Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
| // explicitly, and TEMPORARY variables are allocated via NewTemporary(). |
| DCHECK(IsDeclaredVariableMode(mode)); |
| ++num_var_or_const_; |
| - return variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, |
| - maybe_assigned_flag); |
| + return variables_.Declare(this, name, mode, true, |
| + is_function ? Variable::FUNCTION : Variable::NORMAL, |
| + init_flag, position, maybe_assigned_flag); |
| } |
| @@ -499,12 +509,9 @@ void Scope::RemoveUnresolved(VariableProxy* var) { |
| Variable* Scope::NewInternal(const AstRawString* name) { |
| DCHECK(!already_resolved()); |
| - Variable* var = new(zone()) Variable(this, |
| - name, |
| - INTERNAL, |
| - false, |
| - Variable::NORMAL, |
| - kCreatedInitialized); |
| + Variable* var = |
| + new (zone()) Variable(this, name, INTERNAL, false, Variable::NORMAL, |
| + kCreatedInitialized, RelocInfo::kNoPosition); |
| internals_.Add(var, zone()); |
| return var; |
| } |
| @@ -512,12 +519,9 @@ Variable* Scope::NewInternal(const AstRawString* name) { |
| Variable* Scope::NewTemporary(const AstRawString* name) { |
| DCHECK(!already_resolved()); |
| - Variable* var = new(zone()) Variable(this, |
| - name, |
| - TEMPORARY, |
| - true, |
| - Variable::NORMAL, |
| - kCreatedInitialized); |
| + Variable* var = |
| + new (zone()) Variable(this, name, TEMPORARY, true, Variable::NORMAL, |
| + kCreatedInitialized, RelocInfo::kNoPosition); |
| temps_.Add(var, zone()); |
| return var; |
| } |
| @@ -768,6 +772,20 @@ void Scope::GetNestedScopeChain(Isolate* isolate, |
| } |
| +void Scope::ReportMessage(int start_position, int end_position, |
| + const char* message, const AstRawString* arg) { |
| + // Propagate the error to the topmost scope targeted by this scope analysis |
| + // phase. |
| + Scope* top = this; |
| + while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) { |
| + top = top->outer_scope(); |
| + } |
| + |
| + top->pending_error_handler_.ReportMessageAt(start_position, end_position, |
| + message, arg, kReferenceError); |
| +} |
| + |
| + |
| #ifdef DEBUG |
| static const char* Header(ScopeType scope_type) { |
| switch (scope_type) { |
| @@ -1050,6 +1068,27 @@ bool Scope::ResolveVariable(CompilationInfo* info, VariableProxy* proxy, |
| switch (binding_kind) { |
| 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. |
|
rossberg
2015/02/23 13:45:26
Can you add a TODO regarding different evals? I su
marja
2015/02/24 13:29:34
Added a todo.
So one error case is:
This throws:
|
| + const Scope* eval_for_use = NearestOuterEvalScope(); |
| + const Scope* eval_for_declaration = |
| + var->scope()->NearestOuterEvalScope(); |
| + |
| + if (proxy->position() != RelocInfo::kNoPosition && |
| + proxy->position() < var->position() && !var->is_function() && |
|
rossberg
2015/02/23 13:45:26
I don't believe this is good enough. Consider:
marja
2015/02/24 13:29:35
Fixed this to use initializer_position(), undid th
|
| + 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; |
| + } |
| + } |
| break; |
| case BOUND_EVAL_SHADOWED: |