From 47d3bb1c0b294b26e97a70988c10c756d266af84 Mon Sep 17 00:00:00 2001 From: rossberg Date: Thu, 23 Jul 2015 02:58:38 -0700 Subject: [PATCH] [es6] Fix function context check for super and new.target R=adamk@chromium.org BUG=v8:3330 LOG=N Review URL: https://codereview.chromium.org/1244423003 Cr-Commit-Position: refs/heads/master@{#29803} --- src/preparser.h | 17 ++--------------- src/scopes.cc | 10 ++++++---- src/scopes.h | 13 ++++++------- test/mjsunit/harmony/new-target.js | 16 +++++++++++++++- test/mjsunit/harmony/super.js | 31 ++++++++++++++++++++++++++++++- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/preparser.h b/src/preparser.h index 8680f88..5ed1cd6 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -3504,13 +3504,7 @@ ParserBase::ParseSuperExpression(bool is_new, int pos = position(); Expect(Token::SUPER, CHECK_OK); - Scope* scope = scope_->DeclarationScope(); - while (scope->is_eval_scope() || scope->is_arrow_scope()) { - scope = scope->outer_scope(); - DCHECK_NOT_NULL(scope); - scope = scope->DeclarationScope(); - } - + Scope* scope = scope_->ReceiverScope(); FunctionKind kind = scope->function_kind(); if (IsConciseMethod(kind) || IsAccessorFunction(kind) || i::IsConstructor(kind)) { @@ -3548,14 +3542,7 @@ ParserBase::ParseNewTargetExpression(bool* ok) { Consume(Token::PERIOD); ExpectContextualKeyword(CStrVector("target"), CHECK_OK); - Scope* scope = scope_->DeclarationScope(); - while (scope->is_eval_scope() || scope->is_arrow_scope()) { - scope = scope->outer_scope(); - DCHECK_NOT_NULL(scope); - scope = scope->DeclarationScope(); - } - - if (!scope->is_function_scope()) { + if (!scope_->ReceiverScope()->is_function_scope()) { ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedNewTarget); *ok = false; diff --git a/src/scopes.cc b/src/scopes.cc index a044b76..6e1c18d 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -763,24 +763,26 @@ int Scope::ContextChainLength(Scope* scope) { } -Scope* Scope::ScriptScope() { +Scope* Scope::DeclarationScope() { Scope* scope = this; - while (!scope->is_script_scope()) { + while (!scope->is_declaration_scope()) { scope = scope->outer_scope(); } return scope; } -Scope* Scope::DeclarationScope() { +Scope* Scope::ReceiverScope() { Scope* scope = this; - while (!scope->is_declaration_scope()) { + while (!scope->is_script_scope() && + (!scope->is_function_scope() || scope->is_arrow_scope())) { scope = scope->outer_scope(); } return scope; } + Handle Scope::GetScopeInfo(Isolate* isolate) { if (scope_info_.is_null()) { scope_info_ = ScopeInfo::Create(isolate, zone(), this); diff --git a/src/scopes.h b/src/scopes.h index f935418..e565ff6 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -483,15 +483,14 @@ class Scope: public ZoneObject { // The number of contexts between this and scope; zero if this == scope. int ContextChainLength(Scope* scope); - // Find the script scope. - // Used in modules implemenetation to find hosting scope. - // TODO(rossberg): is this needed? - Scope* ScriptScope(); - - // Find the first function, global, or eval scope. This is the scope - // where var declarations will be hoisted to in the implementation. + // Find the first function, script, eval or (declaration) block scope. This is + // the scope where var declarations will be hoisted to in the implementation. Scope* DeclarationScope(); + // Find the first (non-arrow) function or script scope. This is where + // 'this' is bound, and what determines the function kind. + Scope* ReceiverScope(); + Handle GetScopeInfo(Isolate* isolate); // Get the chain of nested scopes within this scope for the source statement diff --git a/test/mjsunit/harmony/new-target.js b/test/mjsunit/harmony/new-target.js index 0d2873b..9498099 100644 --- a/test/mjsunit/harmony/new-target.js +++ b/test/mjsunit/harmony/new-target.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-new-target --harmony-reflect +// Flags: --harmony-new-target --harmony-reflect --harmony-destructuring // Flags: --harmony-rest-parameters --harmony-arrow-functions @@ -368,3 +368,17 @@ a2 = 3; f(1, 2, 3); })(); + + +(function TestOtherScopes() { + function f1() { return eval("'use strict'; new.target") } + assertSame(f1, new f1); + function f2() { with ({}) return new.target } + assertSame(f2, new f2); + function f3({a}) { return new.target } + assertSame(f3, new f3({})); + function f4(...a) { return new.target } + assertSame(f4, new f4); + function f5() { 'use strict'; { let x; return new.target } } + assertSame(f5, new f5); +})(); diff --git a/test/mjsunit/harmony/super.js b/test/mjsunit/harmony/super.js index ab572b0..601adda 100644 --- a/test/mjsunit/harmony/super.js +++ b/test/mjsunit/harmony/super.js @@ -3,7 +3,8 @@ // found in the LICENSE file. // Flags: --harmony-arrow-functions --allow-natives-syntax -// Flags: --harmony-spreadcalls +// Flags: --harmony-spreadcalls --harmony-destructuring +// Flags: --harmony-rest-parameters --harmony-sloppy (function TestSuperNamedLoads() { function Base() { } @@ -2122,6 +2123,34 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); })(); +(function TestSuperInOtherScopes() { + var p = {x: 99}; + var o0 = {__proto__: p, f() { return eval("'use strict'; super.x") }}; + assertEquals(p.x, o0.f()); + var o1 = {__proto__: p, f() { with ({}) return super.x }}; + assertEquals(p.x, o1.f()); + var o2 = {__proto__: p, f({a}) { return super.x }}; + assertEquals(p.x, o2.f({})); + var o3 = {__proto__: p, f(...a) { return super.x }}; + assertEquals(p.x, o3.f()); + var o4 = {__proto__: p, f() { 'use strict'; { let x; return super.x } }}; + assertEquals(p.x, o4.f()); +})(); + + +(function TestSuperCallInOtherScopes() { + class C {constructor() { this.x = 99 }} + class D0 extends C {constructor() { eval("'use strict'; super()") }} + assertEquals(99, (new D0).x); + class D2 extends C {constructor({a}) { super() }} + assertEquals(99, (new D2({})).x); + class D3 extends C {constructor(...a) { super() }} + assertEquals(99, (new D3()).x); + class D4 extends C {constructor() { { let x; super() } }} + assertEquals(99, (new D4).x); +})(); + + (function TestSuperCallInEval() { 'use strict'; class Base { -- 2.7.4