Re-re-land "[es6] Implement destructuring binding in try/catch"

http://crrev.com/80a1e004f4ef619b54a2d87bf2108719a8411860 was reverted
due to a Blink test failure. That test has been marked as failing on
the Blink side in https://chromium.googlesource.com/chromium/src/+/ac11c6df133.

BUG=v8:811
LOG=y
TBR=rossberg@chromium.org
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

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

Cr-Commit-Position: refs/heads/master@{#31842}
This commit is contained in:
adamk 2015-11-05 12:21:20 -08:00 committed by Commit bot
parent 7ff114e287
commit e33c4b450f
9 changed files with 131 additions and 8 deletions

View File

@ -255,6 +255,7 @@ class AstValue : public ZoneObject {
F(dot_module, ".module") \
F(dot_result, ".result") \
F(dot_switch_tag, ".switch_tag") \
F(dot_catch, ".catch") \
F(empty, "") \
F(eval, "eval") \
F(let, "let") \

View File

@ -1074,7 +1074,8 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
// unchanged if the property already exists.
InsertSloppyBlockFunctionVarBindings(scope, &ok);
}
if (ok && (is_strict(language_mode()) || allow_harmony_sloppy())) {
if (ok && (is_strict(language_mode()) || allow_harmony_sloppy() ||
allow_harmony_destructuring())) {
CheckConflictingVarDeclarations(scope_, &ok);
}
@ -3162,21 +3163,79 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Scope* catch_scope = NULL;
Variable* catch_variable = NULL;
Block* catch_block = NULL;
const AstRawString* name = NULL;
if (tok == Token::CATCH) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
catch_scope = NewScope(scope_, CATCH_SCOPE);
catch_scope->set_start_position(scanner()->location().beg_pos);
name = ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
ExpressionClassifier pattern_classifier;
Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
const AstRawString* name = ast_value_factory()->dot_catch_string();
bool is_simple = pattern->IsVariableProxy();
if (is_simple) {
auto proxy = pattern->AsVariableProxy();
scope_->RemoveUnresolved(proxy);
name = proxy->raw_name();
}
catch_variable = catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
Variable::NORMAL);
BlockState block_state(&scope_, catch_scope);
catch_block = ParseBlock(NULL, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
{
BlockState block_state(&scope_, catch_scope);
// TODO(adamk): Make a version of ParseScopedBlock that takes a scope and
// a block.
catch_block =
factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
block_scope->set_start_position(scanner()->location().beg_pos);
{
BlockState block_state(&scope_, block_scope);
Target target(&this->target_stack_, catch_block);
if (!is_simple) {
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
descriptor.parser = this;
descriptor.declaration_scope = scope_;
descriptor.scope = scope_;
descriptor.hoist_scope = nullptr;
descriptor.mode = LET;
descriptor.is_const = false;
descriptor.needs_init = true;
descriptor.declaration_pos = pattern->position();
descriptor.initialization_pos = pattern->position();
descriptor.init_op = Token::INIT_LET;
DeclarationParsingResult::Declaration decl(
pattern, pattern->position(),
factory()->NewVariableProxy(catch_variable));
PatternRewriter::DeclareAndInitializeVariables(
catch_block, &descriptor, &decl, nullptr, CHECK_OK);
}
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
Statement* stat = ParseStatementListItem(CHECK_OK);
if (stat && !stat->IsEmpty()) {
catch_block->statements()->Add(stat, zone());
}
}
Consume(Token::RBRACE);
}
block_scope->set_end_position(scanner()->location().end_pos);
block_scope = block_scope->FinalizeBlockScope();
catch_block->set_scope(block_scope);
}
catch_scope->set_end_position(scanner()->location().end_pos);
tok = peek();
@ -4376,7 +4435,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
if (is_sloppy(language_mode) && allow_harmony_sloppy_function()) {
InsertSloppyBlockFunctionVarBindings(scope, CHECK_OK);
}
if (is_strict(language_mode) || allow_harmony_sloppy()) {
if (is_strict(language_mode) || allow_harmony_sloppy() ||
allow_harmony_destructuring()) {
CheckConflictingVarDeclarations(scope, CHECK_OK);
}
}

View File

@ -1039,9 +1039,12 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
if (tok == Token::CATCH) {
Consume(Token::CATCH);
Expect(Token::LPAREN, CHECK_OK);
ParseIdentifier(kDontAllowRestrictedIdentifiers, CHECK_OK);
ExpressionClassifier pattern_classifier;
ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
{
// TODO(adamk): Make this CATCH_SCOPE
Scope* with_scope = NewScope(scope_, WITH_SCOPE);
BlockState block_state(&scope_, with_scope);
ParseBlock(CHECK_OK);

View File

@ -6555,6 +6555,7 @@ TEST(DestructuringPositiveTests) {
{"function f(argument1, ", ") {}"},
{"var f = (", ") => {};"},
{"var f = (argument1,", ") => {};"},
{"try {} catch(", ") {}"},
{NULL, NULL}};
// clang-format off
@ -6616,6 +6617,7 @@ TEST(DestructuringNegativeTests) {
{"var f = (", ") => {};"},
{"var f = ", " => {};"},
{"var f = (argument1,", ") => {};"},
{"try {} catch(", ") {}"},
{NULL, NULL}};
// clang-format off

View File

@ -0,0 +1,11 @@
// 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-destructuring
"use strict";
try {
} catch ({x}) {
let x;
}

View File

@ -0,0 +1,4 @@
*%(basename)s:10: SyntaxError: Identifier 'x' has already been declared
let x;
^
SyntaxError: Identifier 'x' has already been declared

View File

@ -0,0 +1,10 @@
// 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-destructuring
try {
} catch ({x}) {
var x;
}

View File

@ -0,0 +1,4 @@
*%(basename)s:9: SyntaxError: Identifier 'x' has already been declared
var x;
^
SyntaxError: Identifier 'x' has already been declared

View File

@ -1098,8 +1098,36 @@
function(){ eval("(class{foo(a, {}) {'use strict';}});") }, SyntaxError);
})();
(function TestLegacyConstDestructuringInForLoop() {
var result;
for (const {foo} of [{foo: 1}]) { result = foo; }
assertEquals(1, result);
})();
(function TestCatch() {
"use strict";
// For testing proper scoping.
var foo = "hello", bar = "world", baz = 42;
try {
throw {foo: 1, bar: 2};
} catch ({foo, bar, baz = 3}) {
assertEquals(1, foo);
assertEquals(2, bar);
assertEquals(3, baz);
}
try {
throw [1, 2, 3];
} catch ([foo, ...bar]) {
assertEquals(1, foo);
assertEquals([2, 3], bar);
}
assertEquals("hello", foo);
assertEquals("world", bar);
assertEquals(42, baz);
})();