]> git.kaiwu.me - quickjs.git/commitdiff
Annex B: allow call expression as assignment target in non-strict mode, but throw...
authorFabrice Bellard <fabrice@bellard.org>
Mon, 28 Sep 2026 15:36:29 +0000 (17:36 +0200)
committerFabrice Bellard <fabrice@bellard.org>
Mon, 28 Sep 2026 15:36:29 +0000 (17:36 +0200)
quickjs.c
test262_errors.txt

index 4d3803d51f31e0c7c288612f92a7a51a62abc449..0e8916ebe74fafa2a9bb515f8dcae24ffa9b73c7 100644 (file)
--- a/quickjs.c
+++ b/quickjs.c
@@ -18490,6 +18490,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
 #define JS_THROW_VAR_UNINITIALIZED  2
 #define JS_THROW_ERROR_DELETE_SUPER   3
 #define JS_THROW_ERROR_ITERATOR_THROW 4
+#define JS_THROW_ERROR_INVALID_LVALUE_CALL 5
             {
                 JSAtom atom;
                 int type;
@@ -18510,6 +18511,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
                 else
                 if (type == JS_THROW_ERROR_ITERATOR_THROW)
                     JS_ThrowTypeError(ctx, "iterator does not have a throw method");
+                else
+                if (type == JS_THROW_ERROR_INVALID_LVALUE_CALL)
+                    JS_ThrowReferenceError(ctx, "invalid assignment left-hand side");
                 else
                     JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
             }
@@ -26110,7 +26114,6 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
     scope = 0;
     name = JS_ATOM_NULL;
     label = -1;
-    depth = 0;
     switch(opcode = get_prev_opcode(fd)) {
     case OP_scope_get_var:
         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
@@ -26142,6 +26145,22 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
     case OP_get_super_value:
         depth = 3;
         break;
+    case OP_call:
+    case OP_call_method:
+        /* Annex B: allow call expression as assignment target in
+           non-strict mode, but throw ReferenceError at runtime. */
+        if ((fd->js_mode & JS_MODE_STRICT) ||
+            tok == TOK_LAND_ASSIGN || tok == TOK_LOR_ASSIGN ||
+            tok == TOK_DOUBLE_QUESTION_MARK_ASSIGN ||
+            tok == '[' || tok == '{') {
+            goto invalid_lvalue;
+        }
+        emit_op(s, OP_throw_error);
+        emit_u32(s, JS_ATOM_NULL);
+        emit_u8(s, JS_THROW_ERROR_INVALID_LVALUE_CALL);
+        opcode = OP_call;
+        depth = 0;
+        break;
     default:
     invalid_lvalue:
         if (tok == TOK_FOR) {
@@ -26155,9 +26174,11 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
         }
     }
     /* remove the last opcode */
-    fd->byte_code.size = fd->last_opcode_pos;
-    fd->last_opcode_pos = -1;
-
+    if (opcode != OP_call) {
+        fd->byte_code.size = fd->last_opcode_pos;
+        fd->last_opcode_pos = -1;
+    }
+    
     if (keep) {
         /* get the value but keep the object/fields on the stack */
         switch(opcode) {
@@ -26196,6 +26217,8 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
             emit_op(s, OP_dup3);
             emit_op(s, OP_get_super_value);
             break;
+        case OP_call:
+            break;
         default:
             abort();
         }
@@ -26326,6 +26349,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
             abort();
         }
         break;
+    case OP_call:
     default:
         break;
     }
@@ -26354,6 +26378,8 @@ static void put_lvalue(JSParseState *s, int opcode, int scope,
     case OP_get_super_value:
         emit_op(s, OP_put_super_value);
         break;
+    case OP_call:
+        break;
     default:
         abort();
     }
@@ -27578,6 +27604,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
                     }
                     break;
                 }
+                if (call_type == FUNC_CALL_TEMPLATE) {
+                    /* annex B: syntax error if used as lvalue */
+                    s->cur_func->last_opcode_pos = -1;
+                }
             }
             call_type = FUNC_CALL_NORMAL;
         } else if (s->token.val == '.') {
index afeec033008e7a6c314a9ba20f126bab46307252..76593b4820327af44e36b6fdb24d32add91d7366 100644 (file)
@@ -1,10 +1,3 @@
-test262/test/annexB/language/expressions/assignmenttargettype/callexpression-as-for-in-lhs.js:27: SyntaxError: invalid for in/of left hand-side
-test262/test/annexB/language/expressions/assignmenttargettype/callexpression-as-for-of-lhs.js:27: SyntaxError: invalid for in/of left hand-side
-test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-compound-assignment.js:33: SyntaxError: invalid assignment left-hand side
-test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-postfix-update.js:27: SyntaxError: invalid increment/decrement operand
-test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js:27: SyntaxError: invalid increment/decrement operand
-test262/test/annexB/language/expressions/assignmenttargettype/callexpression.js:33: SyntaxError: invalid assignment left-hand side
-test262/test/annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js:20: SyntaxError: invalid assignment left-hand side
 test262/test/built-ins/Promise/try/avoids-wrap-for-subclass.js:10: Test262Error: Expected SameValue(«[object Promise]», «[object Promise]») to be true
 test262/test/built-ins/Promise/try/avoids-wrap.js:10: Test262Error: Expected SameValue(«[object Promise]», «[object Promise]») to be true
 test262/test/language/expressions/assignment/S11.13.1_A6_T1.js:23: Test262Error: #1: innerX === undefined. Actual: 1