fix: 块级异步与生成器函数声明不再泄漏全局

This commit is contained in:
2026-09-17 22:08:56 +00:00
parent ed3e8cf372
commit e4b17d2ecf
4 changed files with 182 additions and 7 deletions
@@ -1,5 +1,7 @@
//! try/catch/finally 语句 emit:`emit_try_statement` 生成 TRY_BEGIN 与处理入口。
use std::collections::HashMap;
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
@@ -32,13 +34,21 @@ impl Emitter {
// try block 是独立块作用域:lexical 声明(let/const/class)限定于 try 内,
// 与外层同名绑定互不干扰;块级预声明使声明点前读取编译为 TDZ 抛错。
ctx.push_scope();
// 函数预声明先于 lexical:同名 let 命中已有函数绑定报重复声明错。
self.predeclare_block_function_declarations(&ts.block.body, ctx, false);
// try 块 lexical 声明是局部绑定:不做受限全局名检查(重复声明错在 emit 期报)。
let _ = self.predeclare_lexical_declarations(&ts.block.body, ctx, false);
// 块级函数声明的块入口初始化:声明点前读命中函数对象,声明点复用入口槽。
ctx.block_fn_entry_mats.push(HashMap::new());
for s in &ts.block.body {
self.emit_block_fn_entry_init_stmt(s, ctx)?;
}
for s in &ts.block.body {
if let Some(r) = self.emit_statement(s, ctx)? {
last_try_result = Some(r);
}
}
ctx.block_fn_entry_mats.pop();
ctx.pop_scope();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
@@ -64,14 +74,21 @@ impl Emitter {
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(src_reg), Operand::None, Operand::None));
self.emit_binding_pattern(&param.pattern, src_reg, VariableDeclarationKind::Let, false, false, ctx)?;
}
// catch 块函数预声明先于 lexical,块入口物化与 try/普通块同口径。
self.predeclare_block_function_declarations(&catch.body.body, ctx, false);
// catch 块 lexical 声明同为局部绑定:不做受限全局名检查。
let _ = self.predeclare_lexical_declarations(&catch.body.body, ctx, false);
ctx.block_fn_entry_mats.push(HashMap::new());
for s in &catch.body.body {
self.emit_block_fn_entry_init_stmt(s, ctx)?;
}
let mut last_catch_result: Option<u32> = None;
for s in &catch.body.body {
if let Some(r) = self.emit_statement(s, ctx)? {
last_catch_result = Some(r);
}
}
ctx.block_fn_entry_mats.pop();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
@@ -91,11 +108,18 @@ impl Emitter {
// try/catch 收敛值保持 try 体或 catch 体值,finally 值不渗入。
// finally block 同为独立块作用域,lexical 声明互不泄漏。
ctx.push_scope();
// finally 块函数预声明先于 lexical,块入口物化与 try/普通块同口径。
self.predeclare_block_function_declarations(&ts.finalizer.as_ref().unwrap().body, ctx, false);
// finally 块 lexical 声明同为局部绑定:不做受限全局名检查。
let _ = self.predeclare_lexical_declarations(&ts.finalizer.as_ref().unwrap().body, ctx, false);
ctx.block_fn_entry_mats.push(HashMap::new());
for s in &ts.finalizer.as_ref().unwrap().body {
self.emit_block_fn_entry_init_stmt(s, ctx)?;
}
for s in &ts.finalizer.as_ref().unwrap().body {
self.emit_statement(s, ctx)?;
}
ctx.block_fn_entry_mats.pop();
ctx.pop_scope();
ctx.inst(Inst::new(OpCode::TRY_FINALLY_END, Operand::None, Operand::None, Operand::None));
ctx.pop_open_try_handler();