| Index: src/scopes.cc
|
| diff --git a/src/scopes.cc b/src/scopes.cc
|
| index 35449643cec2dce0742737c35b33e9b559b9ab0f..43e91741358f00ae35734c8d5f59f6243f122b86 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,11 @@ 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);
|
| + Variable* variable =
|
| + new (zone()) Variable(scope, name, mode, is_valid_lhs, kind,
|
| + initialization_flag, maybe_assigned_flag);
|
| + variable->set_initializer_position(position);
|
| + p->value = variable;
|
| }
|
| return reinterpret_cast<Variable*>(p->value);
|
| }
|
| @@ -263,7 +267,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 +411,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 +428,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::NORMAL, kCreatedInitialized);
|
| VariableProxy* proxy = factory->NewVariableProxy(var);
|
| VariableDeclaration* declaration = factory->NewVariableDeclaration(
|
| proxy, mode, this, RelocInfo::kNoPosition);
|
| @@ -461,7 +471,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 +480,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);
|
| }
|
|
|
|
|
| @@ -768,6 +780,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 +1076,29 @@ 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. 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;
|
| + }
|
| + }
|
| break;
|
|
|
| case BOUND_EVAL_SHADOWED:
|
|
|