diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 66bd248..0478140 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1562,6 +1562,32 @@ class AssignGenMixin: aa, f"无法为变量 {nm.id} 创建存储", "TypeError") + # [D25 根治] 复用到的 alloca 类型必须与本次注解解析类型一致。 + # get_or_create_sym 只用「名字 + 作用域」复用(ty 不参与判定,见 VarGenMixin), + # 因此可能命中一个**类型不同**的旧 alloca(同名重声明 / 不同路径建出的退化 + # alloca,如裸 list* 对上 list[ast.ASTptr]*)→ alloca 类型与使用点注解类型 + # 分裂 → 方法调用按错误的元素类型特化(list[int].get 返回 i32)→ inttoptr + # 截断指针 → 读垃圾 AST 节点(D21/D25 崩溃族)。 + # 只比较「双方都是指针且 pointee 都是结构体」这一最典型的退化形态: + # 结构体名不同即 fail-fast,直接暴露退化点与变量名(不兜底)。 + if alloca is not None and alloca.Ty is not None and var_ty is not None: + av_pt_d: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if av_pt_d is not None and self.Gen.ExprGenBase.is_ptr_type(av_pt_d) != 0 \ + and self.Gen.ExprGenBase.is_ptr_type(var_ty) != 0: + av_in: llvmlite.LLVMType | t.CPtr = av_pt_d.Pointee + vt_in: llvmlite.LLVMType | t.CPtr = var_ty.Pointee + if av_in is not None and vt_in is not None: + av_nm_d: str = llvmlite.get_struct_name(av_in) + vt_nm_d: str = llvmlite.get_struct_name(vt_in) + if av_nm_d is not None and vt_nm_d is not None \ + and string.strcmp(av_nm_d, vt_nm_d) != 0: + self.Gen.TypeGenErr.fatal_error( + aa, + f"变量 '{nm.id}' 复用到的存储类型为 '{av_nm_d}*',与注解解析类型 " + f"'{vt_nm_d}*' 不一致(同名重声明命中了不同类型的旧 alloca);" + f"禁止静默混用——方法调用会按错误元素类型特化并截断指针", + "TypeError") + # FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储) # 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / char|t.CPtr 不创建。 # a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段,