diff options
author | Luke Wilde <lukew@serenityos.org> | 2022-07-17 19:09:19 +0100 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-07-18 09:00:21 +0100 |
commit | 3a48c7fdafa0d176785d0c3838346d1f6c57d630 (patch) | |
tree | bd2171d4b35b9510ed93f2d4a00bb1698ae2df74 /Userland | |
parent | c55a4c7f30702bf4f1e95b483d91c0346143e33e (diff) | |
download | serenity-3a48c7fdafa0d176785d0c3838346d1f6c57d630.zip |
LibJS/Bytecode: Check for lexical bindings only in current scope
BlockDeclarationInstantiation takes as input the new lexical
environment that was created and checks if there is a binding for the
current name only in this new scope.
This allows shadowing lexical variables and prevents us crashing due to
an already initialized lexical variable in this case:
```js
let x = 1;
{
let x = 1;
}
```
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.h | 9 |
2 files changed, 11 insertions, 2 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index c55caa9e06..8240d330f5 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -45,7 +45,9 @@ Bytecode::CodeGenerationErrorOr<void> ScopeNode::generate_bytecode(Bytecode::Gen auto is_constant_declaration = declaration.is_constant_declaration(); declaration.for_each_bound_name([&](auto const& name) { auto index = generator.intern_identifier(name); - if (is_constant_declaration || !generator.has_binding(index)) { + // NOTE: BlockDeclarationInstantiation takes as input the new lexical environment that was created and checks if there is a binding for the current name only in this new scope. + // For example: `{ let a = 1; { let a = 2; } }`. The second `a` will shadow the first `a` instead of re-initializing or setting it. + if (is_constant_declaration || !generator.has_binding_in_current_scope(index)) { generator.register_binding(index); generator.emit<Bytecode::Op::CreateVariable>(index, Bytecode::Op::EnvironmentMode::Lexical, is_constant_declaration); } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index 6af3c9bfdb..5473e11ca8 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -138,7 +138,7 @@ public: { m_variable_scopes.last_matching([&](auto& x) { return x.mode == BindingMode::Global || x.mode == mode; })->known_bindings.set(identifier); } - bool has_binding(IdentifierTableIndex identifier, Optional<BindingMode> const& specific_binding_mode = {}) + bool has_binding(IdentifierTableIndex identifier, Optional<BindingMode> const& specific_binding_mode = {}) const { for (auto index = m_variable_scopes.size(); index > 0; --index) { auto& scope = m_variable_scopes[index - 1]; @@ -151,6 +151,13 @@ public: } return false; } + bool has_binding_in_current_scope(IdentifierTableIndex identifier) const + { + if (m_variable_scopes.is_empty()) + return false; + + return m_variable_scopes.last().known_bindings.contains(identifier); + } void begin_variable_scope(BindingMode mode = BindingMode::Lexical, SurroundingScopeKind kind = SurroundingScopeKind::Block); void end_variable_scope(); |