From d633a5786f66ee8a4e676620597b63eaff0ce80a Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 2 Oct 2026 22:40:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(flow):=20=E5=87=BD=E6=95=B0=E4=BD=93?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=E6=B8=85=E7=A9=BA=20break/continue=20?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E4=B8=8E=20match-case=20=E6=A0=87=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FuncGenDef.translate_function_def:进函数体前保存并清空 _break_bb / _continue_bb / _in_match_case,退出恢复 - FuncGenMixin:嵌套函数体与 lambda 体两处同样处理——原实现下嵌套函数体内的 break/continue 会继承外层函数的跳转目标(跨函数 br,非法 IR) --- App/lib/core/Gen/Func/FuncGenDef.vp | 11 +++++++++++ App/lib/core/Gen/Func/FuncGenMixin.vp | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/App/lib/core/Gen/Func/FuncGenDef.vp b/App/lib/core/Gen/Func/FuncGenDef.vp index 9952933..91cbf3c 100644 --- a/App/lib/core/Gen/Func/FuncGenDef.vp +++ b/App/lib/core/Gen/Func/FuncGenDef.vp @@ -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 diff --git a/App/lib/core/Gen/Func/FuncGenMixin.vp b/App/lib/core/Gen/Func/FuncGenMixin.vp index ff456a4..9a67c4a 100644 --- a/App/lib/core/Gen/Func/FuncGenMixin.vp +++ b/App/lib/core/Gen/Func/FuncGenMixin.vp @@ -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