diff --git a/Libraries/LibJS/Rust/src/bytecode/codegen.rs b/Libraries/LibJS/Rust/src/bytecode/codegen.rs index f9e55c0d2b..43137e13cb 100644 --- a/Libraries/LibJS/Rust/src/bytecode/codegen.rs +++ b/Libraries/LibJS/Rust/src/bytecode/codegen.rs @@ -2884,10 +2884,12 @@ fn emit_resolve_binding_for_identifier_assignment( ) -> Option { let arena = generator.arena.clone(); let ident = &arena.identifiers[id]; - if ident.is_local() || ident.is_global { + if ident.is_local() || (ident.is_global && !generator.strict) { return None; } + // In strict mode, a global-looking identifier may still be unresolvable. Preserve that reference across RHS + // evaluation so PutValue throws even if the RHS creates a global property with the same name. let identifier = generator.intern_identifier_id(ident.name); if generator.environment_coordinate_for_identifier(identifier).is_some() { return None; diff --git a/Tests/LibJS/Bytecode/expected/tagged-template-if-register-order.txt b/Tests/LibJS/Bytecode/expected/tagged-template-if-register-order.txt index 82678c9b06..4d6353fef3 100644 --- a/Tests/LibJS/Bytecode/expected/tagged-template-if-register-order.txt +++ b/Tests/LibJS/Bytecode/expected/tagged-template-if-register-order.txt @@ -1,5 +1,5 @@ -$75ea5b81 tagged-template-if-register-order.js:2:1 - Registers: 10 +$73266a71 tagged-template-if-register-order.js:2:1 + Registers: 11 Blocks: 3 Constants: [0] = String("use strict") @@ -20,11 +20,12 @@ block0: [ c0] JumpFalse condition:reg6, target:block2 block1: - [ d0] GetGlobal dst:reg5, `x` - [ e0] GetById dst:reg9, base:reg5, `toUpperCase` (x.toUpperCase) - [ f8] Call dst:reg7, callee:reg9, this_value:reg5, x.toUpperCase - [ 118] SetGlobal `y`, src:reg7 - [ 128] Mov dst:reg8, src:reg7 + [ d0] ResolveBinding dst:reg7, `y` + [ e0] GetGlobal dst:reg9, `x` + [ f0] GetById dst:reg10, base:reg9, `toUpperCase` (x.toUpperCase) + [ 108] Call dst:reg5, callee:reg10, this_value:reg9, x.toUpperCase + [ 128] SetResolvedBinding environment:reg7, `y`, src:reg5 + [ 138] Mov dst:reg8, src:reg5 block2: - [ 138] End value:reg8 + [ 148] End value:reg8 diff --git a/Tests/LibJS/Runtime/invalid-lhs-in-assignment.js b/Tests/LibJS/Runtime/invalid-lhs-in-assignment.js index 56017629dd..f7ee582250 100644 --- a/Tests/LibJS/Runtime/invalid-lhs-in-assignment.js +++ b/Tests/LibJS/Runtime/invalid-lhs-in-assignment.js @@ -16,6 +16,16 @@ test("assignment to function call in strict mode is a SyntaxError", () => { expect("'use strict'; foo() = 'foo'").not.toEval(); }); +test("strict assignment to unresolvable reference preserves initial reference", () => { + delete globalThis.__test_unresolvable_assignment; + expect(() => { + "use strict"; + __test_unresolvable_assignment = (globalThis.__test_unresolvable_assignment = 5); + }).toThrowWithMessage(ReferenceError, "'__test_unresolvable_assignment' is not defined"); + expect(globalThis.__test_unresolvable_assignment).toBe(5); + delete globalThis.__test_unresolvable_assignment; +}); + test("assignment to inline function call", () => { expect(() => { (function () {})() = "foo";