fix(flow): 函数体入口清空 break/continue 目标与 match-case 标记

- FuncGenDef.translate_function_def:进函数体前保存并清空 _break_bb / _continue_bb /
  _in_match_case,退出恢复
- FuncGenMixin:嵌套函数体与 lambda 体两处同样处理——原实现下嵌套函数体内的
  break/continue 会继承外层函数的跳转目标(跨函数 br,非法 IR)
This commit is contained in:
TermiNexus committed 2026-10-02 22:40:04 +08:00
1 parent fb4175736f
commit d633a5786f
2 files changed
+33

No files matched your search

+11
View File
@@ -892,10 +892,18 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
# 返回注解上下文([C①] 裸名泛型构造的类型实参回退来源之一):
# 进入函数体前记录本函数返回注解,退出时恢复外层函数的值
old_ret_annot: ast.AST* = trans.CurFuncRetAnnot
# break/continue 目标与 match-case 标记:新函数作用域必须清空(见下方赋值),
# 否则嵌套函数体内的 break/continue 会继承外层函数(甚至跨函数)的 br 目标
old_break_bb: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue_bb: rawptr[llvmlite.BasicBlock] = trans._continue_bb
old_inmc: int = trans._in_match_case
trans._cur_func = func
trans._cur_builder = func_builder
trans.CurFuncRetAnnot = fd.returns
trans._break_bb = None
trans._continue_bb = None
trans._in_match_case = 0
# 清空 global/nonlocal 名称集合(新函数作用域)
GenApi.clear_scope_names(trans)
# 重置链内 nonlocal 堆预建标志(每函数只建一次;多嵌套函数定义
@@ -1040,6 +1048,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
self.Gen.VarGen.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
trans._break_bb = old_break_bb
trans._continue_bb = old_continue_bb
trans._in_match_case = old_inmc
trans._global_name_count = old_global_count
trans._nonlocal_name_count = old_nonlocal_count
trans._closure_env_count = old_env_count
+22
View File
@@ -181,6 +181,11 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
old_global_count: int = trans._global_name_count
old_nonlocal_count: int = trans._nonlocal_name_count
old_env_count: int = trans._closure_env_count
# break/continue 目标与 match-case 标记:新函数作用域必须清空(见下方赋值),
# 否则嵌套函数体内的 break/continue 会继承外层函数的跳转目标(跨函数 br)
old_break_bb: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue_bb: rawptr[llvmlite.BasicBlock] = trans._continue_bb
old_inmc: int = trans._in_match_case
# nonlocal 集合独立缓冲:嵌套函数注册 nonlocal 写入共享缓冲 [0] 会
# 覆盖父函数集合(ClosureTest2 Test 7 不同变量场景:level2 的 b 覆盖
# level1 的 a → level1 env[0] 存错)。嵌套函数用独立缓冲,翻译完恢复。
@@ -192,6 +197,9 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
trans._cur_builder = func_builder
trans._cur_func_name = func_name
GenApi.clear_scope_names(trans)
trans._break_bb = None
trans._continue_bb = None
trans._in_match_case = 0
# 嵌套函数独立 nonlocal 缓冲(避免覆盖父函数集合)
trans._nonlocal_names = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8)
trans._nonlocal_types = stdlib.malloc(HT.MAX_GLOBAL_NAMES * 8)
@@ -254,6 +262,9 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
self.Gen.VarGen.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
trans._break_bb = old_break_bb
trans._continue_bb = old_continue_bb
trans._in_match_case = old_inmc
if dbg_pushed_n != 0:
DebugInfoGen.PopFunction(func_builder)
# NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值
@@ -1148,10 +1159,18 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
old_global_count: int = trans._global_name_count
old_nonlocal_count: int = trans._nonlocal_name_count
old_env_count: int = trans._closure_env_count
# break/continue 目标与 match-case 标记:新函数作用域必须清空(见下方赋值),
# 否则 lambda 体内的 break/continue 会继承外层函数的跳转目标(跨函数 br)
old_break_bb: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue_bb: rawptr[llvmlite.BasicBlock] = trans._continue_bb
old_inmc: int = trans._in_match_case
trans._cur_func = func
trans._cur_builder = func_builder
trans._cur_func_name = mangled_promoted
GenApi.clear_scope_names(trans)
trans._break_bb = None
trans._continue_bb = None
trans._in_match_case = 0
# 9. 捕获变量:从 env 堆槽加载值到局部 alloca
for ci in range(cap_count):
@@ -1216,6 +1235,9 @@ novirtual class FuncGenMixin(CallGenBase.CallGenBase):
self.Gen.VarGen.exit_scope(trans.SymTab)
trans._cur_func = old_func
trans._cur_builder = old_builder
trans._break_bb = old_break_bb
trans._continue_bb = old_continue_bb
trans._in_match_case = old_inmc
trans._cur_func_name = old_func_name
trans._global_name_count = old_global_count
trans._nonlocal_name_count = old_nonlocal_count