Commit 0bdaa4d8 authored by adamk's avatar adamk Committed by Commit bot

Fix eval calls in initializers of arrow function parameters

This requires copying usage flags from the outer scope to the
arrow scope upon encountering the arrow token.

In order to properly pass-on the calls_eval bit, now record
that bit on script scopes just like everywhere else, and add
necessary code to scopes.cc to handle that change in behavior.

Also factored out scope flag propagation to its own method to
make the call site simple (though note that only the eval
bit makes any difference for arrows).

BUG=v8:4395
LOG=n

Review URL: https://codereview.chromium.org/1423613002

Cr-Commit-Position: refs/heads/master@{#31660}
parent 4c3c89c1
......@@ -2942,6 +2942,10 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
Scope* scope =
this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
// Because the arrow's parameters were parsed in the outer scope, any
// usage flags that might have been triggered there need to be copied
// to the arrow scope.
scope_->PropagateUsageFlagsToScope(scope);
FormalParametersT parameters(scope);
if (!arrow_formals_classifier.is_simple_parameter_list()) {
scope->SetHasNonSimpleParameters();
......
......@@ -386,22 +386,32 @@ Scope* Scope::FinalizeBlockScope() {
outer_scope()->unresolved_.Add(unresolved_[i], zone());
}
// Propagate usage flags to outer scope.
// TODO(adamk): Why doesn't this call PropagateScopeInfo()?
if (uses_arguments()) outer_scope_->RecordArgumentsUsage();
if (uses_super_property()) outer_scope_->RecordSuperPropertyUsage();
if (scope_calls_eval_) outer_scope_->RecordEvalCall();
PropagateUsageFlagsToScope(outer_scope_);
return NULL;
}
void Scope::ReplaceOuterScope(Scope* outer_scope) {
void Scope::ReplaceOuterScope(Scope* outer) {
DCHECK_NOT_NULL(outer);
DCHECK_NOT_NULL(outer_scope_);
DCHECK(!already_resolved());
DCHECK(!outer->already_resolved());
DCHECK(!outer_scope_->already_resolved());
outer_scope_->RemoveInnerScope(this);
outer_scope_ = outer_scope;
outer_scope_->AddInnerScope(this);
// TODO(adamk): Do we need to propagate usage flags here?
outer->AddInnerScope(this);
outer_scope_ = outer;
}
void Scope::PropagateUsageFlagsToScope(Scope* other) {
DCHECK_NOT_NULL(other);
DCHECK(!already_resolved());
DCHECK(!other->already_resolved());
if (uses_arguments()) other->RecordArgumentsUsage();
if (uses_super_property()) other->RecordSuperPropertyUsage();
if (calls_eval()) other->RecordEvalCall();
if (scope_contains_with_) other->RecordWithStatement();
}
......@@ -1120,7 +1130,8 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
if (var != NULL && proxy->is_assigned()) var->set_maybe_assigned();
*binding_kind = DYNAMIC_LOOKUP;
return NULL;
} else if (calls_sloppy_eval() && name_can_be_shadowed) {
} else if (calls_sloppy_eval() && !is_script_scope() &&
name_can_be_shadowed) {
// A variable binding may have been found in an outer scope, but the current
// scope makes a sloppy 'eval' call, so the found variable may not be
// the correct one (the 'eval' may introduce a binding with the same name).
......
......@@ -117,6 +117,10 @@ class Scope: public ZoneObject {
// Assumes outer_scope_ is non-null.
void ReplaceOuterScope(Scope* outer_scope);
// Propagates any eagerly-gathered scope usage flags (such as calls_eval())
// to the passed-in scope.
void PropagateUsageFlagsToScope(Scope* other);
Zone* zone() const { return zone_; }
// ---------------------------------------------------------------------------
......@@ -237,7 +241,7 @@ class Scope: public ZoneObject {
void RecordWithStatement() { scope_contains_with_ = true; }
// Inform the scope that the corresponding code contains an eval call.
void RecordEvalCall() { if (!is_script_scope()) scope_calls_eval_ = true; }
void RecordEvalCall() { scope_calls_eval_ = true; }
// Inform the scope that the corresponding code uses "arguments".
void RecordArgumentsUsage() { scope_uses_arguments_ = true; }
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --harmony-default-parameters --harmony-destructuring
((x, y = eval('x')) => assertEquals(42, y))(42);
((x, {y = eval('x')}) => assertEquals(42, y))(42, {});
......@@ -96,3 +96,9 @@
new D();
})();
(function testScopeFlags() {
((x, y = eval('x')) => assertEquals(42, y))(42);
((x, {y = eval('x')}) => assertEquals(42, y))(42, {});
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment