Fix evaluation order of computed properties
The evaluation order is observable. Align with what test262 expects.
This commit is contained in:
parent
48e4c63a0e
commit
e995085d0c
2 changed files with 29 additions and 4 deletions
29
quickjs.c
29
quickjs.c
|
@ -23716,11 +23716,40 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
|
||||||
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
|
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
// comply with rather obtuse evaluation order of computed properties:
|
||||||
|
// obj[key]=val evaluates val->obj->key when obj is null/undefined
|
||||||
|
// but key->obj->val when an object
|
||||||
|
// FIXME(bnoordhuis) less stack shuffling; don't to_propkey twice in
|
||||||
|
// happy path; replace `dup is_undefined_or_null if_true` with new
|
||||||
|
// opcode if_undefined_or_null? replace `swap dup` with over?
|
||||||
|
if (op == '=' && opcode == OP_get_array_el) {
|
||||||
|
int label_next = -1;
|
||||||
|
JSFunctionDef *fd = s->cur_func;
|
||||||
|
assert(OP_to_propkey2 == fd->byte_code.buf[fd->last_opcode_pos]);
|
||||||
|
fd->byte_code.size = fd->last_opcode_pos;
|
||||||
|
fd->last_opcode_pos = -1;
|
||||||
|
emit_op(s, OP_swap); // obj key -> key obj
|
||||||
|
emit_op(s, OP_dup);
|
||||||
|
emit_op(s, OP_is_undefined_or_null);
|
||||||
|
label_next = emit_goto(s, OP_if_true, -1);
|
||||||
|
emit_op(s, OP_swap);
|
||||||
|
emit_op(s, OP_to_propkey);
|
||||||
|
emit_op(s, OP_swap);
|
||||||
|
emit_label(s, label_next);
|
||||||
|
emit_op(s, OP_swap);
|
||||||
|
}
|
||||||
|
|
||||||
if (js_parse_assign_expr2(s, parse_flags)) {
|
if (js_parse_assign_expr2(s, parse_flags)) {
|
||||||
JS_FreeAtom(s->ctx, name);
|
JS_FreeAtom(s->ctx, name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (op == '=' && opcode == OP_get_array_el) {
|
||||||
|
emit_op(s, OP_swap); // obj key val -> obj val key
|
||||||
|
emit_op(s, OP_to_propkey);
|
||||||
|
emit_op(s, OP_swap);
|
||||||
|
}
|
||||||
|
|
||||||
if (op == '=') {
|
if (op == '=') {
|
||||||
if (opcode == OP_get_ref_value && name == name0) {
|
if (opcode == OP_get_ref_value && name == name0) {
|
||||||
set_object_name(s, name);
|
set_object_name(s, name);
|
||||||
|
|
|
@ -3,10 +3,6 @@ test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: Test262Er
|
||||||
test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: strict mode: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier
|
test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: strict mode: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier
|
||||||
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: unexpected error type: Test262: This statement should not be evaluated.
|
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: unexpected error type: Test262: This statement should not be evaluated.
|
||||||
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: strict mode: unexpected error type: Test262: This statement should not be evaluated.
|
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: strict mode: unexpected error type: Test262: This statement should not be evaluated.
|
||||||
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError
|
|
||||||
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
|
|
||||||
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError
|
|
||||||
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
|
|
||||||
test262/test/language/expressions/function/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
|
test262/test/language/expressions/function/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
|
||||||
test262/test/language/expressions/function/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
|
test262/test/language/expressions/function/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
|
||||||
test262/test/language/expressions/generators/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
|
test262/test/language/expressions/generators/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
|
||||||
|
|
Loading…
Reference in a new issue