Commit cf9492dd authored by dslomov's avatar dslomov Committed by Commit bot

[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}
parent cc3f59db
...@@ -148,6 +148,7 @@ class CallSite { ...@@ -148,6 +148,7 @@ class CallSite {
"Method invoked on undefined or null value.") \ "Method invoked on undefined or null value.") \
T(MethodInvokedOnWrongType, "Method invoked on an object that is not %.") \ T(MethodInvokedOnWrongType, "Method invoked on an object that is not %.") \
T(NoAccess, "no access") \ T(NoAccess, "no access") \
T(NonCoercible, "Cannot match against 'undefined' or 'null'.") \
T(NonExtensibleProto, "% is not extensible") \ T(NonExtensibleProto, "% is not extensible") \
T(NonObjectPropertyLoad, "Cannot read property '%' of %") \ T(NonObjectPropertyLoad, "Cannot read property '%' of %") \
T(NonObjectPropertyStore, "Cannot set property '%' of %") \ T(NonObjectPropertyStore, "Cannot set property '%' of %") \
......
...@@ -4143,6 +4143,32 @@ void Parser::AddAssertIsConstruct(ZoneList<Statement*>* body, int pos) { ...@@ -4143,6 +4143,32 @@ void Parser::AddAssertIsConstruct(ZoneList<Statement*>* 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<Statement*>* Parser::ParseEagerFunctionBody( ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
const AstRawString* function_name, int pos, Variable* fvar, const AstRawString* function_name, int pos, Variable* fvar,
Token::Value fvar_init_op, FunctionKind kind, bool* ok) { Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
......
...@@ -1013,6 +1013,9 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -1013,6 +1013,9 @@ class Parser : public ParserBase<ParserTraits> {
} }
bool inside_with() const { return descriptor_->parser->inside_with(); } bool inside_with() const { return descriptor_->parser->inside_with(); }
Zone* zone() const { return descriptor_->parser->zone(); } Zone* zone() const { return descriptor_->parser->zone(); }
Scope* TemporaryDeclarationScope() const {
return descriptor_->parser->scope_->DeclarationScope();
}
Expression* pattern_; Expression* pattern_;
int initializer_position_; int initializer_position_;
...@@ -1101,6 +1104,7 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -1101,6 +1104,7 @@ class Parser : public ParserBase<ParserTraits> {
IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok); IterationStatement* LookupContinueTarget(const AstRawString* label, bool* ok);
void AddAssertIsConstruct(ZoneList<Statement*>* body, int pos); void AddAssertIsConstruct(ZoneList<Statement*>* body, int pos);
Statement* BuildAssertIsCoercible(Variable* var);
// Factory methods. // Factory methods.
FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos, FunctionLiteral* DefaultConstructor(bool call_super, Scope* scope, int pos,
......
...@@ -209,14 +209,21 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { ...@@ -209,14 +209,21 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
auto temp = descriptor_->declaration_scope->NewTemporary( auto temp = TemporaryDeclarationScope()->NewTemporary(
ast_value_factory()->empty_string()); ast_value_factory()->empty_string());
auto assignment = auto assignment =
factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp), factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp),
current_value_, RelocInfo::kNoPosition); current_value_, RelocInfo::kNoPosition);
block_->AddStatement( block_->AddStatement(
factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition),
zone()); zone());
if (pattern->properties()->length() == 0) {
block_->AddStatement(descriptor_->parser->BuildAssertIsCoercible(temp),
zone());
}
for (ObjectLiteralProperty* property : *pattern->properties()) { for (ObjectLiteralProperty* property : *pattern->properties()) {
// TODO(dslomov): computed property names. // TODO(dslomov): computed property names.
RecurseIntoSubpattern( RecurseIntoSubpattern(
......
...@@ -6378,6 +6378,7 @@ TEST(DestructuringPositiveTests) { ...@@ -6378,6 +6378,7 @@ TEST(DestructuringPositiveTests) {
"{42e-2 : x}", "{42e-2 : x}",
"{'hi' : x}", "{'hi' : x}",
"{var: x}", "{var: x}",
"{}",
NULL}; NULL};
// clang-format on // clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring}; static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring};
......
// 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++;
*%(basename)s:9: TypeError: Assignment to constant variable.
x++;
^
TypeError: Assignment to constant variable.
at *%(basename)s:9:2
...@@ -18,6 +18,26 @@ ...@@ -18,6 +18,26 @@
sum += z; sum += z;
} }
assertEquals(6, sum); 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 @@ ...@@ -30,6 +50,24 @@
let {z} = { z : 3 }; let {z} = { z : 3 };
assertEquals(3, z); 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; let sum = 0;
for(let {x, z} = { x : 0, z : 3 }; z != 0; z--) { for(let {x, z} = { x : 0, z : 3 }; z != 0; z--) {
...@@ -46,6 +84,9 @@ ...@@ -46,6 +84,9 @@
assertEquals(1, x); assertEquals(1, x);
assertEquals(2, y); assertEquals(2, y);
assertThrows(function() { x++; }, TypeError);
assertThrows(function() { y++; }, TypeError);
const {z} = { z : 3 }; const {z} = { z : 3 };
assertEquals(3, z); assertEquals(3, z);
...@@ -54,3 +95,49 @@ ...@@ -54,3 +95,49 @@
assertTrue(false); 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);
}
}());
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