Use Scope::function_kind_ to distinguish arrow function scopes

Previously, arrow function scopes had a separate ScopeType. However,
Scope::DeserializeScopeChain() erroneously deserialized ARROW_SCOPE
ScopeInfos as FUNCTION_SCOPE. This could lead to bugs such as the
attached one, where "super" was disallowed where it should have
been allowed.

This patch utilizes the Scope's FunctionKind to distinguish arrow
functions from others. Besides fixing the above bug, this also
simplifies code in various places that had to deal with two different
ScopeTypes both of which meant "function".

BUG=v8:4466
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31154}
This commit is contained in:
adamk 2015-10-07 07:55:38 -07:00 committed by Commit bot
parent 6c97e54f27
commit 24565b8598
10 changed files with 45 additions and 25 deletions

View File

@ -75,8 +75,7 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
context_ = Handle<Context>(context_->previous(), isolate_);
}
}
if (scope_info->scope_type() == FUNCTION_SCOPE ||
scope_info->scope_type() == ARROW_SCOPE) {
if (scope_info->scope_type() == FUNCTION_SCOPE) {
nested_scope_chain_.Add(scope_info);
}
} else {
@ -86,8 +85,7 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
// Check whether we are in global, eval or function code.
Zone zone;
if (scope_info->scope_type() != FUNCTION_SCOPE &&
scope_info->scope_type() != ARROW_SCOPE) {
if (scope_info->scope_type() != FUNCTION_SCOPE) {
// Global or eval code.
ParseInfo info(&zone, script);
if (scope_info->scope_type() == SCRIPT_SCOPE) {
@ -183,7 +181,6 @@ ScopeIterator::ScopeType ScopeIterator::Type() {
Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
switch (scope_info->scope_type()) {
case FUNCTION_SCOPE:
case ARROW_SCOPE:
DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
return ScopeTypeLocal;
case MODULE_SCOPE:

View File

@ -757,8 +757,7 @@ enum ScopeType {
SCRIPT_SCOPE, // The top-level scope for a script or a top-level eval.
CATCH_SCOPE, // The scope introduced by catch.
BLOCK_SCOPE, // The scope introduced by a new block.
WITH_SCOPE, // The scope introduced by with.
ARROW_SCOPE // The top-level scope for an arrow function literal.
WITH_SCOPE // The scope introduced by with.
};
// The mips architecture prior to revision 5 has inverted encoding for sNaN.

View File

@ -1190,7 +1190,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
if (shared_info->is_arrow()) {
Scope* scope =
NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
scope->SetLanguageMode(shared_info->language_mode());
scope->set_start_position(shared_info->start_position());
ExpressionClassifier formals_classifier;

View File

@ -111,8 +111,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
FunctionState top_state(&function_state_, &scope_, top_scope, kNormalFunction,
&top_factory);
scope_->SetLanguageMode(language_mode);
Scope* function_scope = NewScope(
scope_, IsArrowFunction(kind) ? ARROW_SCOPE : FUNCTION_SCOPE, kind);
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
PreParserFactory function_factory(NULL);
FunctionState function_state(&function_state_, &scope_, function_scope, kind,

View File

@ -307,16 +307,14 @@ class ParserBase : public Traits {
};
Scope* NewScope(Scope* parent, ScopeType scope_type) {
// Must always pass the function kind for FUNCTION_SCOPE and ARROW_SCOPE.
// Must always pass the function kind for FUNCTION_SCOPE.
DCHECK(scope_type != FUNCTION_SCOPE);
DCHECK(scope_type != ARROW_SCOPE);
return NewScope(parent, scope_type, kNormalFunction);
}
Scope* NewScope(Scope* parent, ScopeType scope_type, FunctionKind kind) {
DCHECK(ast_value_factory());
DCHECK(scope_type != MODULE_SCOPE || FLAG_harmony_modules);
DCHECK(!IsArrowFunction(kind) || scope_type == ARROW_SCOPE);
Scope* result = new (zone())
Scope(zone(), parent, scope_type, ast_value_factory(), kind);
result->Initialize();
@ -2929,7 +2927,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
parenthesized_formals, CHECK_OK);
Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
FormalParametersT parameters(scope);
if (!arrow_formals_classifier.is_simple_parameter_list()) {
scope->SetHasNonSimpleParameters();

View File

@ -343,7 +343,6 @@ int ScopeInfo::ContextLength() {
scope_type() == WITH_SCOPE ||
(scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
is_declaration_scope()) ||
(scope_type() == ARROW_SCOPE && CallsSloppyEval()) ||
(scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
scope_type() == MODULE_SCOPE;

View File

@ -844,16 +844,18 @@ void Scope::ReportMessage(int start_position, int end_position,
#ifdef DEBUG
static const char* Header(ScopeType scope_type, bool is_declaration_scope) {
static const char* Header(ScopeType scope_type, FunctionKind function_kind,
bool is_declaration_scope) {
switch (scope_type) {
case EVAL_SCOPE: return "eval";
case FUNCTION_SCOPE: return "function";
// TODO(adamk): Should we print concise method scopes specially?
case FUNCTION_SCOPE:
return IsArrowFunction(function_kind) ? "arrow" : "function";
case MODULE_SCOPE: return "module";
case SCRIPT_SCOPE: return "global";
case CATCH_SCOPE: return "catch";
case BLOCK_SCOPE: return is_declaration_scope ? "varblock" : "block";
case WITH_SCOPE: return "with";
case ARROW_SCOPE: return "arrow";
}
UNREACHABLE();
return NULL;
@ -935,7 +937,7 @@ void Scope::Print(int n) {
int n1 = n0 + 2; // indentation
// Print header.
Indent(n0, Header(scope_type_, is_declaration_scope()));
Indent(n0, Header(scope_type_, function_kind_, is_declaration_scope()));
if (!scope_name_->IsEmpty()) {
PrintF(" ");
PrintName(scope_name_);

View File

@ -302,15 +302,15 @@ class Scope: public ZoneObject {
// Specific scope types.
bool is_eval_scope() const { return scope_type_ == EVAL_SCOPE; }
bool is_function_scope() const {
return scope_type_ == FUNCTION_SCOPE || scope_type_ == ARROW_SCOPE;
}
bool is_function_scope() const { return scope_type_ == FUNCTION_SCOPE; }
bool is_module_scope() const { return scope_type_ == MODULE_SCOPE; }
bool is_script_scope() const { return scope_type_ == SCRIPT_SCOPE; }
bool is_catch_scope() const { return scope_type_ == CATCH_SCOPE; }
bool is_block_scope() const { return scope_type_ == BLOCK_SCOPE; }
bool is_with_scope() const { return scope_type_ == WITH_SCOPE; }
bool is_arrow_scope() const { return scope_type_ == ARROW_SCOPE; }
bool is_arrow_scope() const {
return is_function_scope() && IsArrowFunction(function_kind_);
}
bool is_declaration_scope() const { return is_declaration_scope_; }
void set_is_declaration_scope() { is_declaration_scope_ = true; }

View File

@ -1211,9 +1211,9 @@ TEST(ScopePositions) {
" }", "\n"
" more;", i::FUNCTION_SCOPE, i::SLOPPY },
{ " start;\n", "(a,b) => a + b", "; more;",
i::ARROW_SCOPE, i::SLOPPY },
i::FUNCTION_SCOPE, i::SLOPPY },
{ " start;\n", "(a,b) => { return a+b; }", "\nmore;",
i::ARROW_SCOPE, i::SLOPPY },
i::FUNCTION_SCOPE, i::SLOPPY },
{ " start;\n"
" (function fun", "(a,b) { infunction; }", ")();",
i::FUNCTION_SCOPE, i::SLOPPY },

View File

@ -0,0 +1,26 @@
// 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.
"use strict";
class Parent {
parentMethod(x, y) {
assertEquals(42, x);
assertEquals('hello world', y);
}
}
class Child extends Parent {
method(x) {
let outer = (y) => {
let inner = () => {
super.parentMethod(x, y);
};
inner();
};
outer('hello world');
}
}
new Child().method(42);