diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index 1dbad87d0e..cfe8583ee7 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -829,7 +829,13 @@ Bytecode::CodeGenerationErrorOr ForStatement::generate_labelled_evaluation if (m_init->is_variable_declaration()) { auto& variable_declaration = verify_cast(*m_init); - if (variable_declaration.is_lexical_declaration()) { + auto has_non_local_variables = false; + MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) { + if (!identifier.is_local()) + has_non_local_variables = true; + })); + + if (variable_declaration.is_lexical_declaration() && has_non_local_variables) { has_lexical_environment = true; // FIXME: Is Block correct? @@ -837,8 +843,10 @@ Bytecode::CodeGenerationErrorOr ForStatement::generate_labelled_evaluation bool is_const = variable_declaration.is_constant_declaration(); // NOTE: Nothing in the callback throws an exception. - MUST(variable_declaration.for_each_bound_name([&](auto const& name) { - auto index = generator.intern_identifier(name); + MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) { + if (identifier.is_local()) + return; + auto index = generator.intern_identifier(identifier.string()); generator.emit(index, Bytecode::Op::EnvironmentMode::Lexical, is_const); })); } @@ -2528,22 +2536,32 @@ static Bytecode::CodeGenerationErrorOr for_in_of_he generator.emit_set_variable(*identifier); } } else { - // 1. Let oldEnv be the running execution context's LexicalEnvironment. - // NOTE: 'uninitializedBoundNames' refers to the lexical bindings (i.e. Const/Let) present in the second and last form. - // 2. If uninitializedBoundNames is not an empty List, then - entered_lexical_scope = true; - // a. Assert: uninitializedBoundNames has no duplicate entries. - // b. Let newEnv be NewDeclarativeEnvironment(oldEnv). - generator.begin_variable_scope(); - // c. For each String name of uninitializedBoundNames, do - // NOTE: Nothing in the callback throws an exception. - MUST(variable_declaration.for_each_bound_name([&](auto const& name) { - // i. Perform ! newEnv.CreateMutableBinding(name, false). - auto identifier = generator.intern_identifier(name); - generator.emit(identifier, Bytecode::Op::EnvironmentMode::Lexical, false); + auto has_non_local_variables = false; + MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) { + if (!identifier.is_local()) + has_non_local_variables = true; })); - // d. Set the running execution context's LexicalEnvironment to newEnv. - // NOTE: Done by CreateLexicalEnvironment. + + if (has_non_local_variables) { + // 1. Let oldEnv be the running execution context's LexicalEnvironment. + // NOTE: 'uninitializedBoundNames' refers to the lexical bindings (i.e. Const/Let) present in the second and last form. + // 2. If uninitializedBoundNames is not an empty List, then + entered_lexical_scope = true; + // a. Assert: uninitializedBoundNames has no duplicate entries. + // b. Let newEnv be NewDeclarativeEnvironment(oldEnv). + generator.begin_variable_scope(); + // c. For each String name of uninitializedBoundNames, do + // NOTE: Nothing in the callback throws an exception. + MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) { + if (identifier.is_local()) + return; + // i. Perform ! newEnv.CreateMutableBinding(name, false). + auto interned_identifier = generator.intern_identifier(identifier.string()); + generator.emit(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false); + })); + // d. Set the running execution context's LexicalEnvironment to newEnv. + // NOTE: Done by CreateLexicalEnvironment. + } } } else { // Runtime Semantics: ForInOfLoopEvaluation, for any of: @@ -2691,17 +2709,19 @@ static Bytecode::CodeGenerationErrorOr for_in_of_body_evaluation(Bytecode: auto& variable_declaration = static_cast(*lhs.get>()); // 2. For each element name of the BoundNames of ForBinding, do // NOTE: Nothing in the callback throws an exception. - MUST(variable_declaration.for_each_bound_name([&](auto const& name) { - auto identifier = generator.intern_identifier(name); + MUST(variable_declaration.for_each_bound_identifier([&](auto const& identifier) { + if (identifier.is_local()) + return; + auto interned_identifier = generator.intern_identifier(identifier.string()); // a. If IsConstantDeclaration of LetOrConst is true, then if (variable_declaration.is_constant_declaration()) { // i. Perform ! environment.CreateImmutableBinding(name, true). - generator.emit(identifier, Bytecode::Op::EnvironmentMode::Lexical, true); + generator.emit(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, true); } // b. Else, else { // i. Perform ! environment.CreateMutableBinding(name, false). - generator.emit(identifier, Bytecode::Op::EnvironmentMode::Lexical, false); + generator.emit(interned_identifier, Bytecode::Op::EnvironmentMode::Lexical, false); } })); // 3. Return unused.