Skip to content

Commit cfdfbb8

Browse files
author
arv@chromium.org
committed
ES6: Duplicate properties are no longer an error
This removes the duplicate property checker and updates the tests. BUG=v8:3498 LOG=Y R=marja@chromium.org Review URL: https://codereview.chromium.org/459463002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23239 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
1 parent 930e5cc commit cfdfbb8

7 files changed

Lines changed: 128 additions & 343 deletions

File tree

src/preparser.h

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -496,60 +496,6 @@ class ParserBase : public Traits {
496496
ExpressionT expression,
497497
Scanner::Location location, const char* message, bool* ok);
498498

499-
// Used to detect duplicates in object literals. Each of the values
500-
// kGetterProperty, kSetterProperty and kValueProperty represents
501-
// a type of object literal property. When parsing a property, its
502-
// type value is stored in the DuplicateFinder for the property name.
503-
// Values are chosen so that having intersection bits means the there is
504-
// an incompatibility.
505-
// I.e., you can add a getter to a property that already has a setter, since
506-
// kGetterProperty and kSetterProperty doesn't intersect, but not if it
507-
// already has a getter or a value. Adding the getter to an existing
508-
// setter will store the value (kGetterProperty | kSetterProperty), which
509-
// is incompatible with adding any further properties.
510-
enum PropertyKind {
511-
kNone = 0,
512-
// Bit patterns representing different object literal property types.
513-
kGetterProperty = 1,
514-
kSetterProperty = 2,
515-
kValueProperty = 7,
516-
// Helper constants.
517-
kValueFlag = 4
518-
};
519-
520-
// Validation per ECMA 262 - 11.1.5 "Object Initialiser".
521-
class ObjectLiteralChecker {
522-
public:
523-
ObjectLiteralChecker(ParserBase* parser, StrictMode strict_mode)
524-
: parser_(parser),
525-
finder_(scanner()->unicode_cache()),
526-
strict_mode_(strict_mode) { }
527-
528-
void CheckProperty(Token::Value property, PropertyKind type, bool* ok);
529-
530-
private:
531-
ParserBase* parser() const { return parser_; }
532-
Scanner* scanner() const { return parser_->scanner(); }
533-
534-
// Checks the type of conflict based on values coming from PropertyType.
535-
bool HasConflict(PropertyKind type1, PropertyKind type2) {
536-
return (type1 & type2) != 0;
537-
}
538-
bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) {
539-
return ((type1 & type2) & kValueFlag) != 0;
540-
}
541-
bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) {
542-
return ((type1 ^ type2) & kValueFlag) != 0;
543-
}
544-
bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) {
545-
return ((type1 | type2) & kValueFlag) == 0;
546-
}
547-
548-
ParserBase* parser_;
549-
DuplicateFinder finder_;
550-
StrictMode strict_mode_;
551-
};
552-
553499
// If true, the next (and immediately following) function literal is
554500
// preceded by a parenthesis.
555501
// Heuristically that means that the function will be called immediately,
@@ -1863,8 +1809,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
18631809
int number_of_boilerplate_properties = 0;
18641810
bool has_function = false;
18651811

1866-
ObjectLiteralChecker checker(this, strict_mode());
1867-
18681812
Expect(Token::LBRACE, CHECK_OK);
18691813

18701814
while (peek() != Token::RBRACE) {
@@ -1903,9 +1847,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
19031847
*ok = false;
19041848
return this->EmptyLiteral();
19051849
}
1906-
// Validate the property.
1907-
PropertyKind type = is_getter ? kGetterProperty : kSetterProperty;
1908-
checker.CheckProperty(next, type, CHECK_OK);
19091850
IdentifierT name = this->GetSymbol(scanner_);
19101851
typename Traits::Type::FunctionLiteral value =
19111852
this->ParseFunctionLiteral(
@@ -1969,9 +1910,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
19691910
}
19701911
}
19711912

1972-
// Validate the property
1973-
checker.CheckProperty(next, kValueProperty, CHECK_OK);
1974-
19751913
Expect(Token::COLON, CHECK_OK);
19761914
ExpressionT value = this->ParseAssignmentExpression(true, CHECK_OK);
19771915

@@ -2660,36 +2598,6 @@ ParserBase<Traits>::CheckAndRewriteReferenceExpression(
26602598
#undef CHECK_OK_CUSTOM
26612599

26622600

2663-
template <typename Traits>
2664-
void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
2665-
Token::Value property,
2666-
PropertyKind type,
2667-
bool* ok) {
2668-
int old;
2669-
if (property == Token::NUMBER) {
2670-
old = scanner()->FindNumber(&finder_, type);
2671-
} else {
2672-
old = scanner()->FindSymbol(&finder_, type);
2673-
}
2674-
PropertyKind old_type = static_cast<PropertyKind>(old);
2675-
if (HasConflict(old_type, type)) {
2676-
if (IsDataDataConflict(old_type, type)) {
2677-
// Both are data properties.
2678-
if (strict_mode_ == SLOPPY) return;
2679-
parser()->ReportMessage("strict_duplicate_property");
2680-
} else if (IsDataAccessorConflict(old_type, type)) {
2681-
// Both a data and an accessor property with the same name.
2682-
parser()->ReportMessage("accessor_data_property");
2683-
} else {
2684-
DCHECK(IsAccessorAccessorConflict(old_type, type));
2685-
// Both accessors of the same type.
2686-
parser()->ReportMessage("accessor_get_set");
2687-
}
2688-
*ok = false;
2689-
}
2690-
}
2691-
2692-
26932601
} } // v8::internal
26942602

26952603
#endif // V8_PREPARSER_H

test/cctest/test-parsing.cc

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,7 +2486,7 @@ TEST(StrictObjectLiteralChecking) {
24862486
{ NULL, NULL }
24872487
};
24882488

2489-
// These are only errors in strict mode.
2489+
// ES6 allows duplicate properties even in strict mode.
24902490
const char* statement_data[] = {
24912491
"foo: 1, foo: 2",
24922492
"\"foo\": 1, \"foo\": 2",
@@ -2499,7 +2499,7 @@ TEST(StrictObjectLiteralChecking) {
24992499
};
25002500

25012501
RunParserSyncTest(non_strict_context_data, statement_data, kSuccess);
2502-
RunParserSyncTest(strict_context_data, statement_data, kError);
2502+
RunParserSyncTest(strict_context_data, statement_data, kSuccess);
25032503
}
25042504

25052505

@@ -2512,23 +2512,6 @@ TEST(ErrorsObjectLiteralChecking) {
25122512

25132513
const char* statement_data[] = {
25142514
",",
2515-
"foo: 1, get foo() {}",
2516-
"foo: 1, set foo(v) {}",
2517-
"\"foo\": 1, get \"foo\"() {}",
2518-
"\"foo\": 1, set \"foo\"(v) {}",
2519-
"1: 1, get 1() {}",
2520-
"1: 1, set 1() {}",
2521-
// It's counter-intuitive, but these collide too (even in classic
2522-
// mode). Note that we can have "foo" and foo as properties in classic mode,
2523-
// but we cannot have "foo" and get foo, or foo and get "foo".
2524-
"foo: 1, get \"foo\"() {}",
2525-
"foo: 1, set \"foo\"(v) {}",
2526-
"\"foo\": 1, get foo() {}",
2527-
"\"foo\": 1, set foo(v) {}",
2528-
"1: 1, get \"1\"() {}",
2529-
"1: 1, set \"1\"() {}",
2530-
"\"1\": 1, get 1() {}"
2531-
"\"1\": 1, set 1(v) {}"
25322515
// Wrong number of parameters
25332516
"get bar(x) {}",
25342517
"get bar(x, y) {}",
@@ -2582,6 +2565,24 @@ TEST(NoErrorsObjectLiteralChecking) {
25822565
"super: 6",
25832566
"eval: 7",
25842567
"arguments: 8",
2568+
// Duplicate property names are allowed in ES6.
2569+
"foo: 1, get foo() {}",
2570+
"foo: 1, set foo(v) {}",
2571+
"\"foo\": 1, get \"foo\"() {}",
2572+
"\"foo\": 1, set \"foo\"(v) {}",
2573+
"1: 1, get 1() {}",
2574+
"1: 1, set 1(v) {}",
2575+
// It's counter-intuitive, but these collide too (even in classic
2576+
// mode). Note that we can have "foo" and foo as properties in classic mode,
2577+
// but we cannot have "foo" and get foo, or foo and get "foo".
2578+
"foo: 1, get \"foo\"() {}",
2579+
"foo: 1, set \"foo\"(v) {}",
2580+
"\"foo\": 1, get foo() {}",
2581+
"\"foo\": 1, set foo(v) {}",
2582+
"1: 1, get \"1\"() {}",
2583+
"1: 1, set \"1\"(v) {}",
2584+
"\"1\": 1, get 1() {}",
2585+
"\"1\": 1, set 1(v) {}",
25852586
NULL
25862587
};
25872588

test/mjsunit/number-literal.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2014 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
function test(message, a, b, skipStrictMode) {
6+
assertSame(eval(a), eval(b), message);
7+
if (!skipStrictMode) {
8+
(function() {
9+
'use strict';
10+
assertSame(eval(a), eval(b), message);
11+
})();
12+
}
13+
}
14+
15+
test('hex-int', '0x20', '32');
16+
test('oct-int', '040', '32', true); // Octals disallowed in strict mode.
17+
test('dec-int', '32.00', '32');
18+
test('dec-underflow-int', '32.00000000000000000000000000000000000000001', '32');
19+
test('exp-int', '3.2e1', '32');
20+
test('exp-int', '3200e-2', '32');
21+
test('overflow-inf', '1e2000', 'Infinity');
22+
test('overflow-inf-exact', '1.797693134862315808e+308', 'Infinity');
23+
test('non-overflow-inf-exact', '1.797693134862315807e+308',
24+
'1.7976931348623157e+308');
25+
test('underflow-0', '1e-2000', '0');
26+
test('underflow-0-exact', '2.4703282292062E-324', '0');
27+
test('non-underflow-0-exact', '2.4703282292063E-324', '5e-324');
28+
test('precission-loss-high', '9007199254740992', '9007199254740993');
29+
test('precission-loss-low', '1.9999999999999998', '1.9999999999999997');
30+
test('non-canonical-literal-int', '1.0', '1');
31+
test('non-canonical-literal-frac', '1.50', '1.5');
32+
test('rounding-down', '1.12512512512512452', '1.1251251251251244');
33+
test('rounding-up', '1.12512512512512453', '1.1251251251251246');

test/mjsunit/strict-mode.js

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,6 @@ assertThrows('\
166166
"use strict";\
167167
}', SyntaxError);
168168

169-
// Duplicate data properties.
170-
CheckStrictMode("var x = { dupe : 1, nondupe: 3, dupe : 2 };", SyntaxError);
171-
CheckStrictMode("var x = { '1234' : 1, '2345' : 2, '1234' : 3 };", SyntaxError);
172-
CheckStrictMode("var x = { '1234' : 1, '2345' : 2, 1234 : 3 };", SyntaxError);
173-
CheckStrictMode("var x = { 3.14 : 1, 2.71 : 2, 3.14 : 3 };", SyntaxError);
174-
CheckStrictMode("var x = { 3.14 : 1, '3.14' : 2 };", SyntaxError);
175-
CheckStrictMode("var x = { \
176-
123: 1, \
177-
123.00000000000000000000000000000000000000000000000000000000000000000001: 2 \
178-
}", SyntaxError);
179-
180169
// Non-conflicting data properties.
181170
(function StrictModeNonDuplicate() {
182171
"use strict";
@@ -188,37 +177,52 @@ CheckStrictMode("var x = { \
188177
};
189178
})();
190179

191-
// Two getters (non-strict)
192-
assertThrows("var x = { get foo() { }, get foo() { } };", SyntaxError);
193-
assertThrows("var x = { get foo(){}, get 'foo'(){}};", SyntaxError);
194-
assertThrows("var x = { get 12(){}, get '12'(){}};", SyntaxError);
195-
196-
// Two setters (non-strict)
197-
assertThrows("var x = { set foo(v) { }, set foo(v) { } };", SyntaxError);
198-
assertThrows("var x = { set foo(v) { }, set 'foo'(v) { } };", SyntaxError);
199-
assertThrows("var x = { set 13(v) { }, set '13'(v) { } };", SyntaxError);
200-
201-
// Setter and data (non-strict)
202-
assertThrows("var x = { foo: 'data', set foo(v) { } };", SyntaxError);
203-
assertThrows("var x = { set foo(v) { }, foo: 'data' };", SyntaxError);
204-
assertThrows("var x = { foo: 'data', set 'foo'(v) { } };", SyntaxError);
205-
assertThrows("var x = { set foo(v) { }, 'foo': 'data' };", SyntaxError);
206-
assertThrows("var x = { 'foo': 'data', set foo(v) { } };", SyntaxError);
207-
assertThrows("var x = { set 'foo'(v) { }, foo: 'data' };", SyntaxError);
208-
assertThrows("var x = { 'foo': 'data', set 'foo'(v) { } };", SyntaxError);
209-
assertThrows("var x = { set 'foo'(v) { }, 'foo': 'data' };", SyntaxError);
210-
assertThrows("var x = { 12: 1, set '12'(v){}};", SyntaxError);
211-
assertThrows("var x = { 12: 1, set 12(v){}};", SyntaxError);
212-
assertThrows("var x = { '12': 1, set '12'(v){}};", SyntaxError);
213-
assertThrows("var x = { '12': 1, set 12(v){}};", SyntaxError);
214-
215-
// Getter and data (non-strict)
216-
assertThrows("var x = { foo: 'data', get foo() { } };", SyntaxError);
217-
assertThrows("var x = { get foo() { }, foo: 'data' };", SyntaxError);
218-
assertThrows("var x = { 'foo': 'data', get foo() { } };", SyntaxError);
219-
assertThrows("var x = { get 'foo'() { }, 'foo': 'data' };", SyntaxError);
220-
assertThrows("var x = { '12': 1, get '12'(){}};", SyntaxError);
221-
assertThrows("var x = { '12': 1, get 12(){}};", SyntaxError);
180+
// Duplicate properties are no longer errors in ES6.
181+
(function Duplicates() {
182+
"use strict";
183+
184+
({ dupe : 1, nondupe: 3, dupe : 2 });
185+
({ '1234' : 1, '2345' : 2, '1234' : 3 });
186+
({ '1234' : 1, '2345' : 2, 1234 : 3 });
187+
({ 3.14 : 1, 2.71 : 2, 3.14 : 3 });
188+
({ 3.14 : 1, '3.14' : 2 });
189+
({
190+
123: 1,
191+
123.00000000000000000000000000000000000000000000000000000000000000000001: 2
192+
});
193+
194+
// Two getters
195+
({ get foo() { }, get foo() { } });
196+
({ get foo(){}, get 'foo'(){}});
197+
({ get 12(){}, get '12'(){}});
198+
199+
// Two setters
200+
({ set foo(v) { }, set foo(v) { } });
201+
({ set foo(v) { }, set 'foo'(v) { } });
202+
({ set 13(v) { }, set '13'(v) { } });
203+
204+
// Setter and data
205+
({ foo: 'data', set foo(v) { } });
206+
({ set foo(v) { }, foo: 'data' });
207+
({ foo: 'data', set 'foo'(v) { } });
208+
({ set foo(v) { }, 'foo': 'data' });
209+
({ 'foo': 'data', set foo(v) { } });
210+
({ set 'foo'(v) { }, foo: 'data' });
211+
({ 'foo': 'data', set 'foo'(v) { } });
212+
({ set 'foo'(v) { }, 'foo': 'data' });
213+
({ 12: 1, set '12'(v){}});
214+
({ 12: 1, set 12(v){}});
215+
({ '12': 1, set '12'(v){}});
216+
({ '12': 1, set 12(v){}});
217+
218+
// Getter and data
219+
({ foo: 'data', get foo() { } });
220+
({ get foo() { }, foo: 'data' });
221+
({ 'foo': 'data', get foo() { } });
222+
({ get 'foo'() { }, 'foo': 'data' });
223+
({ '12': 1, get '12'(){}});
224+
({ '12': 1, get 12(){}});
225+
})();
222226

223227
// Assignment to eval or arguments
224228
CheckStrictMode("function strict() { eval = undefined; }", SyntaxError);

0 commit comments

Comments
 (0)