Skip to content

Commit b6b42e8

Browse files
committedDec 29, 2023
Fix evaluation order of computed properties
The evaluation order is observable. Align with what test262 expects.
1 parent 64c9ac5 commit b6b42e8

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed
 

‎quickjs.c

+29
Original file line numberDiff line numberDiff line change
@@ -23702,11 +23702,40 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
2370223702
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
2370323703
return -1;
2370423704

23705+
// comply with rather obtuse evaluation order of computed properties:
23706+
// obj[prop]=key evaluates val->obj->prop when obj is null/undefined
23707+
// but prop->obj->val when an object
23708+
// FIXME(bnoordhuis) less stack shuffling; don't to_propkey twice in
23709+
// happy path; replace `dup is_undefined_or_null if_true` with new
23710+
// opcode if_undefined_or_null? replace `swap dup` with over?
23711+
if (op == '=' && opcode == OP_get_array_el) {
23712+
int label_next = -1;
23713+
JSFunctionDef *fd = s->cur_func;
23714+
assert(OP_to_propkey2 == fd->byte_code.buf[fd->last_opcode_pos]);
23715+
fd->byte_code.size = fd->last_opcode_pos;
23716+
fd->last_opcode_pos = -1;
23717+
emit_op(s, OP_swap); // obj prop -> prop obj
23718+
emit_op(s, OP_dup);
23719+
emit_op(s, OP_is_undefined_or_null);
23720+
label_next = emit_goto(s, OP_if_true, -1);
23721+
emit_op(s, OP_swap);
23722+
emit_op(s, OP_to_propkey);
23723+
emit_op(s, OP_swap);
23724+
emit_label(s, label_next);
23725+
emit_op(s, OP_swap);
23726+
}
23727+
2370523728
if (js_parse_assign_expr2(s, parse_flags)) {
2370623729
JS_FreeAtom(s->ctx, name);
2370723730
return -1;
2370823731
}
2370923732

23733+
if (op == '=' && opcode == OP_get_array_el) {
23734+
emit_op(s, OP_swap); // obj prop val -> obj val prop
23735+
emit_op(s, OP_to_propkey);
23736+
emit_op(s, OP_swap);
23737+
}
23738+
2371023739
if (op == '=') {
2371123740
if (opcode == OP_get_ref_value && name == name0) {
2371223741
set_object_name(s, name);

‎test262_errors.txt

-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detac
1515
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
1616
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: unexpected error type: Test262: This statement should not be evaluated.
1717
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: strict mode: unexpected error type: Test262: This statement should not be evaluated.
18-
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError
19-
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
20-
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError
21-
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
2218
test262/test/language/expressions/function/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
2319
test262/test/language/expressions/function/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
2420
test262/test/language/expressions/generators/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier

0 commit comments

Comments
 (0)