diff options
author | davidot <davidot@serenityos.org> | 2022-11-30 01:45:35 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-11-30 08:05:37 +0100 |
commit | 8319d7ac06256bcfacaeca1ef322dc930fdea963 (patch) | |
tree | 959c9567254bd632b72ac1ca108351cdd4b3b262 /Userland | |
parent | 714f0c3dce22dc7218567b925b4af78e6b0f3928 (diff) | |
download | serenity-8319d7ac06256bcfacaeca1ef322dc930fdea963.zip |
LibJS: Fix that constant declaration in for loop was mutable in body
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/AST.cpp | 18 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/loops/for-in-basic.js | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/loops/for-of-basic.js | 10 |
3 files changed, 34 insertions, 4 deletions
diff --git a/Userland/Libraries/LibJS/AST.cpp b/Userland/Libraries/LibJS/AST.cpp index 313a5d6071..51d37625be 100644 --- a/Userland/Libraries/LibJS/AST.cpp +++ b/Userland/Libraries/LibJS/AST.cpp @@ -921,12 +921,22 @@ struct ForInOfHeadState { else { VERIFY(expression_lhs && is<VariableDeclaration>(*expression_lhs)); iteration_environment = new_declarative_environment(*interpreter.lexical_environment()); + auto& for_declaration = static_cast<VariableDeclaration const&>(*expression_lhs); + + // 14.7.5.4 Runtime Semantics: ForDeclarationBindingInstantiation, https://tc39.es/ecma262/#sec-runtime-semantics-fordeclarationbindinginstantiation + // 1. For each element name of the BoundNames of ForBinding, do for_declaration.for_each_bound_name([&](auto const& name) { - if (for_declaration.declaration_kind() == DeclarationKind::Const) - MUST(iteration_environment->create_immutable_binding(vm, name, false)); - else - MUST(iteration_environment->create_mutable_binding(vm, name, true)); + // a. If IsConstantDeclaration of LetOrConst is true, then + if (for_declaration.is_constant_declaration()) { + // i. Perform ! environment.CreateImmutableBinding(name, true). + MUST(iteration_environment->create_immutable_binding(vm, name, true)); + } + // b. Else, + else { + // i. Perform ! environment.CreateMutableBinding(name, false). + MUST(iteration_environment->create_mutable_binding(vm, name, false)); + } }); interpreter.vm().running_execution_context().lexical_environment = iteration_environment; diff --git a/Userland/Libraries/LibJS/Tests/loops/for-in-basic.js b/Userland/Libraries/LibJS/Tests/loops/for-in-basic.js index f7b018ca38..f25c43725d 100644 --- a/Userland/Libraries/LibJS/Tests/loops/for-in-basic.js +++ b/Userland/Libraries/LibJS/Tests/loops/for-in-basic.js @@ -98,6 +98,16 @@ describe("special left hand sides", () => { eval("for (f() in [0]) { expect().fail() }"); }).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment"); }); + + test("Cannot change constant declaration in body", () => { + const vals = []; + for (const v in [1, 2]) { + expect(() => v++).toThrowWithMessage(TypeError, "Invalid assignment to const variable"); + vals.push(v); + } + + expect(vals).toEqual(["0", "1"]); + }); }); test("remove properties while iterating", () => { diff --git a/Userland/Libraries/LibJS/Tests/loops/for-of-basic.js b/Userland/Libraries/LibJS/Tests/loops/for-of-basic.js index 29fcb5d2b9..b5753d76dc 100644 --- a/Userland/Libraries/LibJS/Tests/loops/for-of-basic.js +++ b/Userland/Libraries/LibJS/Tests/loops/for-of-basic.js @@ -142,4 +142,14 @@ describe("special left hand sides", () => { eval("for (f() of [0]) { expect().fail() }"); }).toThrowWithMessage(ReferenceError, "Invalid left-hand side in assignment"); }); + + test("Cannot change constant declaration in body", () => { + const vals = []; + for (const v of [1, 2]) { + expect(() => v++).toThrowWithMessage(TypeError, "Invalid assignment to const variable"); + vals.push(v); + } + + expect(vals).toEqual([1, 2]); + }); }); |