Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1811)

Unified Diff: src/scopes.cc

Issue 943543002: [strong] Declaration-after-use errors. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: more fixes + tests Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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:

Powered by Google App Engine
This is Rietveld 408576698