For-of on null or undefined is an error
The latest ES6 draft changed the behavior of for-of on null / undefined, which for once is a simplification. R=rossberg@chromium.org BUG= Review URL: https://codereview.chromium.org/416033002 Patch from Andy Wingo <wingo@igalia.com>. git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22602 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b5a5148260
commit
029b8a2379
@ -1276,15 +1276,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
|
||||
// As with for-in, skip the loop if the iterator is null or undefined.
|
||||
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
|
||||
__ b(eq, loop_statement.break_label());
|
||||
__ CompareRoot(r0, Heap::kNullValueRootIndex);
|
||||
__ b(eq, loop_statement.break_label());
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -1271,16 +1271,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
|
||||
// As with for-in, skip the loop if the iterator is null or undefined.
|
||||
Register iterator = x0;
|
||||
__ JumpIfRoot(iterator, Heap::kUndefinedValueRootIndex,
|
||||
loop_statement.break_label());
|
||||
__ JumpIfRoot(iterator, Heap::kNullValueRootIndex,
|
||||
loop_statement.break_label());
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -243,7 +243,6 @@ class AstValue : public ZoneObject {
|
||||
F(dot_for, ".for") \
|
||||
F(dot_generator, ".generator") \
|
||||
F(dot_generator_object, ".generator_object") \
|
||||
F(dot_iterable, ".iterable") \
|
||||
F(dot_iterator, ".iterator") \
|
||||
F(dot_module, ".module") \
|
||||
F(dot_result, ".result") \
|
||||
|
10
src/ast.h
10
src/ast.h
@ -961,13 +961,11 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
|
||||
void Initialize(Expression* each,
|
||||
Expression* subject,
|
||||
Statement* body,
|
||||
Expression* assign_iterable,
|
||||
Expression* assign_iterator,
|
||||
Expression* next_result,
|
||||
Expression* result_done,
|
||||
Expression* assign_each) {
|
||||
ForEachStatement::Initialize(each, subject, body);
|
||||
assign_iterable_ = assign_iterable;
|
||||
assign_iterator_ = assign_iterator;
|
||||
next_result_ = next_result;
|
||||
result_done_ = result_done;
|
||||
@ -978,12 +976,7 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
|
||||
return subject();
|
||||
}
|
||||
|
||||
// var iterable = subject;
|
||||
Expression* assign_iterable() const {
|
||||
return assign_iterable_;
|
||||
}
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
// var iterator = subject[Symbol.iterator]();
|
||||
Expression* assign_iterator() const {
|
||||
return assign_iterator_;
|
||||
}
|
||||
@ -1018,7 +1011,6 @@ class ForOfStatement V8_FINAL : public ForEachStatement {
|
||||
back_edge_id_(GetNextId(zone)) {
|
||||
}
|
||||
|
||||
Expression* assign_iterable_;
|
||||
Expression* assign_iterator_;
|
||||
Expression* next_result_;
|
||||
Expression* result_done_;
|
||||
|
@ -1207,15 +1207,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
|
||||
// As with for-in, skip the loop if the iterator is null or undefined.
|
||||
__ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, loop_statement.break_label());
|
||||
__ CompareRoot(eax, Heap::kNullValueRootIndex);
|
||||
__ j(equal, loop_statement.break_label());
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -1272,16 +1272,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
__ mov(a0, v0);
|
||||
|
||||
// As with for-in, skip the loop if the iterator is null or undefined.
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(loop_statement.break_label(), eq, a0, Operand(at));
|
||||
__ LoadRoot(at, Heap::kNullValueRootIndex);
|
||||
__ Branch(loop_statement.break_label(), eq, a0, Operand(at));
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -1267,16 +1267,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
__ mov(a0, v0);
|
||||
|
||||
// As with for-in, skip the loop if the iterator is null or undefined.
|
||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||
__ Branch(loop_statement.break_label(), eq, a0, Operand(at));
|
||||
__ LoadRoot(at, Heap::kNullValueRootIndex);
|
||||
__ Branch(loop_statement.break_label(), eq, a0, Operand(at));
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -2749,37 +2749,26 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
|
||||
ForOfStatement* for_of = stmt->AsForOfStatement();
|
||||
|
||||
if (for_of != NULL) {
|
||||
Variable* iterable = scope_->DeclarationScope()->NewTemporary(
|
||||
ast_value_factory_->dot_iterable_string());
|
||||
Variable* iterator = scope_->DeclarationScope()->NewTemporary(
|
||||
ast_value_factory_->dot_iterator_string());
|
||||
Variable* result = scope_->DeclarationScope()->NewTemporary(
|
||||
ast_value_factory_->dot_result_string());
|
||||
|
||||
Expression* assign_iterable;
|
||||
Expression* assign_iterator;
|
||||
Expression* next_result;
|
||||
Expression* result_done;
|
||||
Expression* assign_each;
|
||||
|
||||
// var iterable = subject;
|
||||
// var iterator = subject[Symbol.iterator]();
|
||||
{
|
||||
Expression* iterable_proxy = factory()->NewVariableProxy(iterable);
|
||||
assign_iterable = factory()->NewAssignment(
|
||||
Token::ASSIGN, iterable_proxy, subject, subject->position());
|
||||
}
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
{
|
||||
Expression* iterable_proxy = factory()->NewVariableProxy(iterable);
|
||||
Expression* iterator_symbol_literal =
|
||||
factory()->NewSymbolLiteral("symbolIterator", RelocInfo::kNoPosition);
|
||||
// FIXME(wingo): Unhappily, it will be a common error that the RHS of a
|
||||
// for-of doesn't have a Symbol.iterator property. We should do better
|
||||
// than informing the user that "undefined is not a function".
|
||||
int pos = subject->position();
|
||||
Expression* iterator_property = factory()->NewProperty(
|
||||
iterable_proxy, iterator_symbol_literal, pos);
|
||||
Expression* iterator_property =
|
||||
factory()->NewProperty(subject, iterator_symbol_literal, pos);
|
||||
ZoneList<Expression*>* iterator_arguments =
|
||||
new(zone()) ZoneList<Expression*>(0, zone());
|
||||
Expression* iterator_call = factory()->NewCall(
|
||||
@ -2826,7 +2815,6 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
|
||||
}
|
||||
|
||||
for_of->Initialize(each, subject, body,
|
||||
assign_iterable,
|
||||
assign_iterator,
|
||||
next_result,
|
||||
result_done,
|
||||
|
@ -1241,15 +1241,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
|
||||
// As with for-in, skip the loop if the iterable is null or undefined.
|
||||
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, loop_statement.break_label());
|
||||
__ CompareRoot(rax, Heap::kNullValueRootIndex);
|
||||
__ j(equal, loop_statement.break_label());
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -1204,15 +1204,6 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
||||
Iteration loop_statement(this, stmt);
|
||||
increment_loop_depth();
|
||||
|
||||
// var iterable = subject
|
||||
VisitForAccumulatorValue(stmt->assign_iterable());
|
||||
|
||||
// As with for-in, skip the loop if the iterator is null or undefined.
|
||||
__ CompareRoot(eax, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, loop_statement.break_label());
|
||||
__ CompareRoot(eax, Heap::kNullValueRootIndex);
|
||||
__ j(equal, loop_statement.break_label());
|
||||
|
||||
// var iterator = iterable[Symbol.iterator]();
|
||||
VisitForEffect(stmt->assign_iterator());
|
||||
|
||||
|
@ -213,9 +213,9 @@ assertEquals([1, 2],
|
||||
{ value: 37, done: true },
|
||||
never_getter(never_getter({}, 'done'), 'value')])));
|
||||
|
||||
// Null and undefined do not cause an error.
|
||||
assertEquals(0, fold(sum, 0, unreachable(null)));
|
||||
assertEquals(0, fold(sum, 0, unreachable(undefined)));
|
||||
// Unlike the case with for-in, null and undefined cause an error.
|
||||
assertThrows('fold(sum, 0, unreachable(null))', TypeError);
|
||||
assertThrows('fold(sum, 0, unreachable(undefined))', TypeError);
|
||||
|
||||
// Other non-iterators do cause an error.
|
||||
assertThrows('fold(sum, 0, unreachable({}))', TypeError);
|
||||
|
Loading…
Reference in New Issue
Block a user