From cf9492ddd818f336a9dc1269cdb7557ec709d12c Mon Sep 17 00:00:00 2001 From: dslomov Date: Mon, 18 May 2015 13:15:08 -0700 Subject: [PATCH] [destructuring] More tests for object literal pattern R=arv@chromium.org,rossberg@chromium.org BUG=v8:811 LOG=N Review URL: https://codereview.chromium.org/1139773005 Cr-Commit-Position: refs/heads/master@{#28457} --- src/messages.h | 1 + src/parser.cc | 26 +++++++++ src/parser.h | 4 ++ src/pattern-rewriter.cc | 9 ++- test/cctest/test-parsing.cc | 1 + test/message/destructuring-modify-const.js | 9 +++ test/message/destructuring-modify-const.out | 5 ++ test/mjsunit/harmony/destructuring.js | 87 +++++++++++++++++++++++++++++ 8 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 test/message/destructuring-modify-const.js create mode 100644 test/message/destructuring-modify-const.out diff --git a/src/messages.h b/src/messages.h index bfc78c7..75314e9 100644 --- a/src/messages.h +++ b/src/messages.h @@ -148,6 +148,7 @@ class CallSite { "Method invoked on undefined or null value.") \ T(MethodInvokedOnWrongType, "Method invoked on an object that is not %.") \ T(NoAccess, "no access") \ + T(NonCoercible, "Cannot match against 'undefined' or 'null'.") \ T(NonExtensibleProto, "% is not extensible") \ T(NonObjectPropertyLoad, "Cannot read property '%' of %") \ T(NonObjectPropertyStore, "Cannot set property '%' of %") \ diff --git a/src/parser.cc b/src/parser.cc index 0f63d0b..dde2c7a 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -4143,6 +4143,32 @@ void Parser::AddAssertIsConstruct(ZoneList* body, int pos) { } +Statement* Parser::BuildAssertIsCoercible(Variable* var) { + // if (var === null || var === undefined) + // throw /* type error kNonCoercible) */; + + Expression* condition = factory()->NewBinaryOperation( + Token::OR, factory()->NewCompareOperation( + Token::EQ_STRICT, factory()->NewVariableProxy(var), + factory()->NewUndefinedLiteral(RelocInfo::kNoPosition), + RelocInfo::kNoPosition), + factory()->NewCompareOperation( + Token::EQ_STRICT, factory()->NewVariableProxy(var), + factory()->NewNullLiteral(RelocInfo::kNoPosition), + RelocInfo::kNoPosition), + RelocInfo::kNoPosition); + Expression* throw_type_error = this->NewThrowTypeError( + MessageTemplate::kNonCoercible, ast_value_factory()->empty_string(), + RelocInfo::kNoPosition); + IfStatement* if_statement = factory()->NewIfStatement( + condition, factory()->NewExpressionStatement(throw_type_error, + RelocInfo::kNoPosition), + factory()->NewEmptyStatement(RelocInfo::kNoPosition), + RelocInfo::kNoPosition); + return if_statement; +} + + ZoneList* Parser::ParseEagerFunctionBody( const AstRawString* function_name, int pos, Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) { diff --git a/src/parser.h b/src/parser.h index 4b4f12a..19ddb69 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1013,6 +1013,9 @@ class Parser : public ParserBase { } bool inside_with() const { return descriptor_->parser->inside_with(); } Zone* zone() const { return descriptor_->parser->zone(); } + Scope* TemporaryDeclarationScope() const { + return descriptor_->parser->scope_->DeclarationScope(); + } Expression* pattern_; int initializer_position_; @@ -1101,6 +1104,7 @@ class Parser : public ParserBase { IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok); void AddAssertIsConstruct(ZoneList* body, int pos); + Statement* BuildAssertIsCoercible(Variable* var); // Factory methods. FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos, diff --git a/src/pattern-rewriter.cc b/src/pattern-rewriter.cc index 949be73..9f24a39 100644 --- a/src/pattern-rewriter.cc +++ b/src/pattern-rewriter.cc @@ -209,14 +209,21 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { - auto temp = descriptor_->declaration_scope->NewTemporary( + auto temp = TemporaryDeclarationScope()->NewTemporary( ast_value_factory()->empty_string()); auto assignment = factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp), current_value_, RelocInfo::kNoPosition); + block_->AddStatement( factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), zone()); + + if (pattern->properties()->length() == 0) { + block_->AddStatement(descriptor_->parser->BuildAssertIsCoercible(temp), + zone()); + } + for (ObjectLiteralProperty* property : *pattern->properties()) { // TODO(dslomov): computed property names. RecurseIntoSubpattern( diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index afe638d..c22b3f2 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -6378,6 +6378,7 @@ TEST(DestructuringPositiveTests) { "{42e-2 : x}", "{'hi' : x}", "{var: x}", + "{}", NULL}; // clang-format on static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring}; diff --git a/test/message/destructuring-modify-const.js b/test/message/destructuring-modify-const.js new file mode 100644 index 0000000..cabd924 --- /dev/null +++ b/test/message/destructuring-modify-const.js @@ -0,0 +1,9 @@ +// 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'; + +const { x : x, y : y } = { x : 1, y : 2 }; +x++; diff --git a/test/message/destructuring-modify-const.out b/test/message/destructuring-modify-const.out new file mode 100644 index 0000000..19bffa6 --- /dev/null +++ b/test/message/destructuring-modify-const.out @@ -0,0 +1,5 @@ +*%(basename)s:9: TypeError: Assignment to constant variable. +x++; + ^ +TypeError: Assignment to constant variable. + at *%(basename)s:9:2 diff --git a/test/mjsunit/harmony/destructuring.js b/test/mjsunit/harmony/destructuring.js index 3cfb6fc..83d0563 100644 --- a/test/mjsunit/harmony/destructuring.js +++ b/test/mjsunit/harmony/destructuring.js @@ -18,6 +18,26 @@ sum += z; } assertEquals(6, sum); + + + var log = []; + var o = { + get x() { + log.push("x"); + return 0; + }, + get y() { + log.push("y"); + return { + get z() { log.push("z"); return 1; } + } + } + }; + var { x : x0, y : { z : z1 }, x : x1 } = o; + assertSame(0, x0); + assertSame(1, z1); + assertSame(0, x1); + assertArrayEquals(["x", "y", "z", "x"], log); }()); @@ -30,6 +50,24 @@ let {z} = { z : 3 }; assertEquals(3, z); + let log = []; + let o = { + get x() { + log.push("x"); + return 0; + }, + get y() { + log.push("y"); + return { + get z() { log.push("z"); return 1; } + } + } + }; + let { x : x0, y : { z : z1 }, x : x1 } = o; + assertSame(0, x0); + assertSame(1, z1); + assertSame(0, x1); + assertArrayEquals(["x", "y", "z", "x"], log); let sum = 0; for(let {x, z} = { x : 0, z : 3 }; z != 0; z--) { @@ -46,6 +84,9 @@ assertEquals(1, x); assertEquals(2, y); + assertThrows(function() { x++; }, TypeError); + assertThrows(function() { y++; }, TypeError); + const {z} = { z : 3 }; assertEquals(3, z); @@ -54,3 +95,49 @@ assertTrue(false); } }()); + + +(function TestFailingMatchesSloppy() { + var {x, y} = {}; + assertSame(undefined, x); + assertSame(undefined, y); + + var { x : { z1 }, y2} = { x : {}, y2 : 42 } + assertSame(undefined, z1); + assertSame(42, y2); +}()); + + +(function TestFailingMatchesStrict() { + 'use strict'; + var {x, y} = {}; + assertSame(undefined, x); + assertSame(undefined, y); + + var { x : { z1 }, y2} = { x : {}, y2 : 42 } + assertSame(undefined, z1); + assertSame(42, y2); + + { + let {x1,y1} = {}; + assertSame(undefined, x1); + assertSame(undefined, y1); + + let { x : { z1 }, y2} = { x : {}, y2 : 42 } + assertSame(undefined, z1); + assertSame(42, y2); + } +}()); + + +(function TestExceptions() { + for (var val of [null, undefined]) { + assertThrows(function() { var {} = val; }, TypeError); + assertThrows(function() { var {x} = val; }, TypeError); + assertThrows(function() { var { x : {} } = { x : val }; }, TypeError); + assertThrows(function() { 'use strict'; let {} = val; }, TypeError); + assertThrows(function() { 'use strict'; let {x} = val; }, TypeError); + assertThrows(function() { 'use strict'; let { x : {} } = { x : val }; }, + TypeError); + } +}()); -- 2.7.4