From 617d4ea9115ae7b47532db7ae1dd364b40e394b8 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 15 Sep 2026 21:52:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen/assign):=20=E6=A8=A1=E5=9D=97=E7=BA=A7?= =?UTF-8?q?=E4=B8=8E=20nonlocal=20=E5=88=86=E6=94=AF=E8=A1=A5=E5=86=99?= =?UTF-8?q?=E8=B5=8B=E5=80=BC=E6=B3=A8=E8=A7=A3=E4=B8=8A=E4=B8=8B=E6=96=87?= =?UTF-8?q?=E9=80=9A=E9=81=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 模块级 AnnAssign 的 mod_glob 分支与 global 语句分支、以及 nonlocal 分支此前均未写入 trans.CurAssignAnnot/CurAssignNode,导致模块级/闭包内 s: Stack[int] = Stack() 在泛型裸名构造处 fail-fast、x: int = c.Deref(p) 退化为 i8 单字节读取 按主分支既有先例(AssignGenMixin set 在 RHS 翻译前 / clear 在返回前)在三处分支补齐同款 set/clear,并覆盖全部分支的提前 return 与末尾出口,避免通道残留污染后续 c.Deref 读取宽度与泛型构造类型实参推断 影响面: 全仓 模块级/global/nonlocal 的 X: T = c.Deref(...) 与 X: Generic[...] = Ctor(...) 均 0 处,属纯增量 --- App/lib/core/Gen/AssignGenMixin.vp | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 17bab09..dadb4ab 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1487,6 +1487,14 @@ class AssignGenMixin: aa_glob_ty: llvmlite.LLVMType | t.CPtr = None if mod_alloca.Ty is not None: aa_glob_ty = mod_alloca.Ty.Pointee + # 供 c.Deref(i8*) 推断读取宽度 / 裸名泛型构造从注解推断类型实参: + # 与主分支(普通局部变量路径)同一口径——必须在翻译 RHS 之前写入 + # CurAssignAnnot/CurAssignNode。四处(主分支 / 本 global 分支 / + # 下方 mod_glob 分支 / 下方 nonlocal 分支)必须同步,否则 + # `x: int = c.Deref(p)` 的读取宽度与 `s: Stack[int] = Stack()` + # 的类型实参推断都会拿不到注解。 + trans.CurAssignAnnot = aa.annotation + trans.CurAssignNode = aa.value rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( builder, pool, mod, aa.value, None, 0, trans, aa_glob_ty) @@ -1515,6 +1523,10 @@ class AssignGenMixin: builder, stg_ty_aa, rhs_val) if stg_obj_val_aa is not None: llvmlite.build_store(builder, stg_obj_val_aa, stg_ref_aa) + # 清除赋值上下文(防残留):与主分支清空时机同款—— + # 提前 return 前必须清,否则泄漏到后续语句 + trans.CurAssignAnnot = None + trans.CurAssignNode = None return 0 target_ty: llvmlite.LLVMType | t.CPtr = None if mod_alloca.Ty is not None: @@ -1522,6 +1534,12 @@ class AssignGenMixin: if target_ty is not None: rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node, trans) llvmlite.build_store(builder, rhs_val, mod_alloca) + # 清除赋值上下文(防残留):与主分支清空时机同款。四处(主分支 / + # 本 global 分支 / 下方 mod_glob 分支 / 下方 nonlocal 分支)必须同步清除, + # 否则残留注解会让后续 while 条件/比较等处的 c.Deref 被误判读取宽度 + # (i8* 按 i32* 读 4 字节),也会污染裸名泛型构造的类型实参推断 + trans.CurAssignAnnot = None + trans.CurAssignNode = None return 0 # nonlocal 变量:通过闭包 env 写入 @@ -1537,6 +1555,14 @@ class AssignGenMixin: nl_target_ty: llvmlite.LLVMType | t.CPtr = None if nl_ptr is not None and nl_ptr.Ty is not None: nl_target_ty = nl_ptr.Ty.Pointee + # 供 c.Deref(i8*) 推断读取宽度 / 裸名泛型构造从注解推断类型实参: + # 与主分支、上方 global 分支、下方 mod_glob 分支同一口径——必须在 + # 翻译 RHS 之前写入 CurAssignAnnot/CurAssignNode。四处(主分支 / + # global / mod_glob / 本 nonlocal 分支)必须同步,否则 + # `nonlocal x: int = c.Deref(p)` 的读取宽度与 + # `nonlocal s: Stack[int] = Stack()` 的类型实参推断都会拿不到注解。 + trans.CurAssignAnnot = aa.annotation + trans.CurAssignNode = aa.value rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( builder, pool, mod, aa.value, None, 0, trans, nl_target_ty) @@ -1547,10 +1573,20 @@ class AssignGenMixin: VLogger.error( f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", "HandlesAnnAssign") + # 清除赋值上下文(防残留):与主分支清空时机同款—— + # 提前 return 前必须清,否则泄漏到后续语句 + trans.CurAssignAnnot = None + trans.CurAssignNode = None return 0 rhs_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( builder, rhs_val, nl_target_ty, node) llvmlite.build_store(builder, rhs_coerced, nl_ptr) + # 清除赋值上下文(防残留):与主分支清空时机同款。四处(主分支 / + # global / mod_glob / 本 nonlocal 分支)必须同步清除,否则残留注解会让 + # 后续 while 条件/比较等处的 c.Deref 被误判读取宽度(i8* 按 i32* 读 4 + # 字节),也会污染裸名泛型构造的类型实参推断 + trans.CurAssignAnnot = None + trans.CurAssignNode = None return 0 # 模块级全局变量(由 handle_module_level_var 注册到模块作用域) @@ -1572,6 +1608,13 @@ class AssignGenMixin: mg_val_ty: llvmlite.LLVMType | t.CPtr = None if mod_glob.Ty is not None: mg_val_ty = mod_glob.Ty.Pointee + # 供 c.Deref(i8*) 推断读取宽度 / 裸名泛型构造从注解推断类型实参: + # 与主分支、上方 global 分支同一口径——翻译 RHS 前写入 + # CurAssignAnnot/CurAssignNode。模块级 `s: Stack[int] = Stack()` + # 走的就是本分支,四处(主分支 / global / 本 mod_glob 分支 / + # 上方 nonlocal 分支)必须同步。 + trans.CurAssignAnnot = aa.annotation + trans.CurAssignNode = aa.value rhs_val_mg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( builder, pool, mod, aa.value, None, 0, trans, mg_val_ty) @@ -1600,6 +1643,10 @@ class AssignGenMixin: builder, stg_ty_mg, rhs_val_mg) if stg_obj_val_mg is not None: llvmlite.build_store(builder, stg_obj_val_mg, stg_ref_mg) + # 清除赋值上下文(防残留):与主分支清空时机同款, + # 提前 return 前必须清,否则泄漏到后续语句 + trans.CurAssignAnnot = None + trans.CurAssignNode = None return 0 target_ty_mg: llvmlite.LLVMType | t.CPtr = None if mod_glob.Ty is not None: @@ -1607,6 +1654,12 @@ class AssignGenMixin: if target_ty_mg is not None: rhs_val_mg = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) llvmlite.build_store(builder, rhs_val_mg, mod_glob) + # 清除赋值上下文(防残留):与主分支清空时机同款。四处(主分支 / + # 上方 global 分支 / 本 mod_glob 分支 / 上方 nonlocal 分支)必须同步清除, + # 否则残留注解会让后续语句的 c.Deref 被误判读取宽度,并污染裸名泛型 + # 构造的类型实参推断 + trans.CurAssignAnnot = None + trans.CurAssignNode = None return 0 # 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断) @@ -1757,6 +1810,9 @@ class AssignGenMixin: # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32 # CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref # 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。 + # 注意:本主分支(普通局部变量)、上方 global 分支、mod_glob 分支、 + # nonlocal 分支四处的 set/clear 必须同步(模块级 AnnAssign 走 + # mod_glob;闭包内 AnnAssign 走 nonlocal)。 trans.CurAssignAnnot = aa.annotation trans.CurAssignNode = aa.value # P1-A:局部变量 alloca 的 pointee 类型作为 target_ty(同全局分支), @@ -1878,6 +1934,7 @@ class AssignGenMixin: # 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该 # AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的 # c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。 + # 四处(本主分支 / global / mod_glob / nonlocal)必须同步清除。 trans.CurAssignAnnot = None trans.CurAssignNode = None