From 21b3db548e2b93acfaf2916e024ee2c1a2e0413d Mon Sep 17 00:00:00 2001 From: devgianlu Date: Sun, 6 Apr 2025 19:42:13 +0200 Subject: [PATCH] LibJS: Do not allow CallExpression LHS on assignment The claim to support CallExpression on the LHS seems to be bogus (we don't even handle it properly). There are some tests in test262 that we pass by not allowing it. --- Libraries/LibJS/Parser.cpp | 12 ++--- .../LibJS/Tests/invalid-lhs-in-assignment.js | 51 ++++++++----------- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index ac56ebdaa45..803174b354b 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -1863,9 +1863,9 @@ NonnullRefPtr Parser::parse_regexp_literal() return create_ast_node(move(range), move(parsed_regex), move(parsed_pattern), move(parsed_flags), move(pattern), move(flags)); } -static bool is_simple_assignment_target(Expression const& expression, bool allow_web_reality_call_expression = true) +static bool is_simple_assignment_target(Expression const& expression) { - return is(expression) || is(expression) || (allow_web_reality_call_expression && is(expression)); + return is(expression) || is(expression); } NonnullRefPtr Parser::parse_unary_prefixed_expression() @@ -2617,13 +2617,7 @@ NonnullRefPtr Parser::parse_assignment_expression(As } } - // Note: The web reality is that all but &&=, ||= and ??= do allow left hand side CallExpresions. - // These are the exception as they are newer. - auto has_web_reality_assignment_target_exceptions = assignment_op != AssignmentOp::AndAssignment - && assignment_op != AssignmentOp::OrAssignment - && assignment_op != AssignmentOp::NullishAssignment; - - if (!is_simple_assignment_target(*lhs, has_web_reality_assignment_target_exceptions)) { + if (!is_simple_assignment_target(*lhs)) { syntax_error("Invalid left-hand side in assignment"_string); } else if (m_state.strict_mode && is(*lhs)) { auto const& name = static_cast(*lhs).string(); diff --git a/Libraries/LibJS/Tests/invalid-lhs-in-assignment.js b/Libraries/LibJS/Tests/invalid-lhs-in-assignment.js index 7f753cad144..d518cfb21e3 100644 --- a/Libraries/LibJS/Tests/invalid-lhs-in-assignment.js +++ b/Libraries/LibJS/Tests/invalid-lhs-in-assignment.js @@ -1,25 +1,17 @@ -test.xfail("assignment to function call", () => { - expect(() => { - function foo() {} - foo() = "foo"; - }).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment"); +test("assignment to function call", () => { + expect('function foo() {}; foo() = "foo";').not.toEval(); }); -test.xfail("Postfix operator after function call", () => { - expect(() => { - function foo() {} - foo()++; - }).toThrow(ReferenceError); +test("Postfix operator after function call", () => { + expect('function foo() {}; foo()++;').not.toEval(); }); test("assignment to function call in strict mode", () => { - expect("'use strict'; foo() = 'foo'").toEval(); + expect("'use strict'; foo() = 'foo';").not.toEval(); }); -test.xfail("assignment to inline function call", () => { - expect(() => { - (function () {})() = "foo"; - }).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment"); +test("assignment to inline function call", () => { + expect('(function () {})() = "foo";').not.toEval(); }); test("assignment to invalid LHS is syntax error", () => { @@ -41,21 +33,20 @@ test("assignment to invalid LHS is syntax error", () => { expect("1 ??= 1").not.toEval(); }); -test("assignment to call LHS is only syntax error for new operators", () => { - expect("f() += 1").toEval(); - expect("f() -= 1").toEval(); - expect("f() *= 1").toEval(); - expect("f() /= 1").toEval(); - expect("f() %= 1").toEval(); - expect("f() **= 1").toEval(); - expect("f() &= 1").toEval(); - expect("f() |= 1").toEval(); - expect("f() ^= 1").toEval(); - expect("f() <<= 1").toEval(); - expect("f() >>= 1").toEval(); - expect("f() >>>= 1").toEval(); - expect("f() = 1").toEval(); - +test("assignment to call LHS is syntax error", () => { + expect("f() += 1").not.toEval(); + expect("f() -= 1").not.toEval(); + expect("f() *= 1").not.toEval(); + expect("f() /= 1").not.toEval(); + expect("f() %= 1").not.toEval(); + expect("f() **= 1").not.toEval(); + expect("f() &= 1").not.toEval(); + expect("f() |= 1").not.toEval(); + expect("f() ^= 1").not.toEval(); + expect("f() <<= 1").not.toEval(); + expect("f() >>= 1").not.toEval(); + expect("f() >>>= 1").not.toEval(); + expect("f() = 1").not.toEval(); expect("f() &&= 1").not.toEval(); expect("f() ||= 1").not.toEval(); expect("f() ??= 1").not.toEval();