From c27a1ba3475f66a1fa23ecb171f96d53f37d2b04 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 13 Aug 2026 19:10:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20lambda=20=E6=8D=95=E8=8E=B7=20str?= =?UTF-8?q?=20=E6=8C=87=E9=92=88=E5=81=8F=E7=A7=BB=20+=20=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E6=8E=A5=E6=94=B6=E8=80=85=E7=AD=89=E4=BA=94?= =?UTF-8?q?=E7=BB=84=E5=9B=9E=E5=BD=92=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - lambda 捕获 cap_slot 改 cap_names + ci*64:TPV 将 (str)(整数) 编译为 itoa,define_var 键名变数字串,lambda body lookup 穿透父函数作用域产生跨函数误读 - StructGenMixin 递归解 Ptr 到 Struct / CallGenMixin self coerce + 表达式接收者方法调用:修 sub Vec3**、ld.lld undefined dot/cross - TranslatorGenMixin/HandlesAnnAssign 跳过 CTypedef 全局符号:修 duplicate float64_t - ClassGenMixin 枚举/联合/REnum 基类别名经 lookup_from_import_original 解析:修 Color.Green NameError - 重载路径 1 对 Ptr(Ptr(Struct)) 先 load 对象指针:修 MultiInheritTest self 误读 - TypeGenMixin 泛型 T 先 resolve_generic_type_name:修 NoVTableTest T 未注册 --- App/lib/core/Gen/CallGenMixin.vp | 46 +++-- App/lib/core/Gen/ClassGenMixin.vp | 74 ++++++-- App/lib/core/Gen/ExprGenMixin.vp | 215 ++++++++++++++++++++++- App/lib/core/Gen/FuncGenMixin.vp | 10 +- App/lib/core/Gen/StructGenMixin.vp | 28 +-- App/lib/core/Gen/TranslatorGenMixin.vp | 7 + App/lib/core/Gen/TypeGenMixin.vp | 19 +- App/lib/core/Handles/HandlesAnnAssign.vp | 15 ++ 8 files changed, 362 insertions(+), 52 deletions(-) diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index dd8137b..a96147d 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -2746,19 +2746,18 @@ class CallGenMixin: total_count += 1 param_node = llvmlite.param_get_next(param_node) - # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0) + # 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(含 self)。 # 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT), # 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾, # 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。 + # self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时 + # 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast), + # 否则 call 参数类型与声明不一致 llc 报错。 if found_func is not None and head is not None: pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - # 跳过 self 参数(索引 0) - if pc_param is not None: - pc_param = llvmlite.param_get_next(pc_param) - pc_node: llvmlite.Value | t.CPtr = head.Next - new_tail: llvmlite.Value | t.CPtr = head - if head is not None: - head.Next = None + pc_node: llvmlite.Value | t.CPtr = head + new_head_pc: llvmlite.Value | t.CPtr = head + prev_pc: llvmlite.Value | t.CPtr = None while pc_node is not None: pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next coerced_pc: llvmlite.Value | t.CPtr = pc_node @@ -2771,9 +2770,13 @@ class CallGenMixin: coerced_pc = c_pc pc_param = llvmlite.param_get_next(pc_param) coerced_pc.Next = None - new_tail.Next = coerced_pc - new_tail = coerced_pc + if prev_pc is None: + new_head_pc = coerced_pc + else: + prev_pc.Next = coerced_pc + prev_pc = coerced_pc pc_node = pc_next_save + head = new_head_pc # 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用 # 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错) @@ -5749,10 +5752,25 @@ class CallGenMixin: builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) if expr_obj is not None and expr_obj.Ty is not None: expr_cls_nm: str = None - match expr_obj.Ty: - case llvmlite.LLVMType.Ptr(expr_struct_ty): - expr_cls_nm = HandlesStruct.get_class_name_by_type( - pool, expr_struct_ty) + # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) + # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 + # 调用被当裸函数 @dot 解析 → 链接 undefined symbol + expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ + HandlesStruct.get_struct_type_from_value(expr_obj) + if expr_struct_ty is not None: + expr_cls_nm = HandlesStruct.get_class_name_by_type( + pool, expr_struct_ty) + # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, + # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) + # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) + # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 + if expr_cls_nm is None: + import lib.core.Gen.Generator as Generator + g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g3 is not None: + expr_cls_nm = g3.infer_expr_class( + pool, mod, expr_method_at.value, trans) if expr_cls_nm is not None: return self._translate_method_call( pool, builder, mod, expr_cls_nm, func_name, diff --git a/App/lib/core/Gen/ClassGenMixin.vp b/App/lib/core/Gen/ClassGenMixin.vp index 0bbf8c7..4bd8994 100644 --- a/App/lib/core/Gen/ClassGenMixin.vp +++ b/App/lib/core/Gen/ClassGenMixin.vp @@ -14,6 +14,7 @@ import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesImports as HandlesImports import lib.core.StubMerger as StubMerger @@ -136,7 +137,8 @@ class ClassGenMixin: # 本模块函数调用改 self.,外部模块调用保留模块前缀) # ============================================================ - def _is_cenum_base(self, base_node: ast.AST | t.CPtr) -> int: + def _is_cenum_base(self, base_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: """检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否""" if base_node is None: return 0 @@ -144,8 +146,21 @@ class ClassGenMixin: # Name('CEnum') 形式(from t import CEnum) if k == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - if nm.id is not None and string.strcmp(nm.id, "CEnum") == 0: + if nm.id is None: + return 0 + if string.strcmp(nm.id, "CEnum") == 0: return 1 + # 别名形式: from t import CEnum as en; class Color(en) + # 解析别名原始名(en → CEnum)再比较 + if trans is not None and trans._from_imports is not None: + alias_orig: str = HandlesImports.lookup_from_import_original( + trans._from_imports, nm.id) + if alias_orig is not None: + og_len_ce: t.CSizeT = 0 + while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0': + og_len_ce += 1 + if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 0: + return 1 return 0 # Attribute(t.CEnum) 形式 if k == ast.ASTKind.Attribute: @@ -155,7 +170,8 @@ class ClassGenMixin: return 0 return 0 - def _is_enum_class(self, cd: ast.ClassDef | t.CPtr) -> int: + def _is_enum_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: """检查 ClassDef 是否为 CEnum:继承自 t.CEnum 或 @t.CEnum 装饰器形式""" if cd is None: return 0 @@ -173,11 +189,12 @@ class ClassGenMixin: base_node: ast.AST | t.CPtr = bases.get(bi) if base_node is None: continue - if self._is_cenum_base(base_node) == 1: + if self._is_cenum_base(base_node, trans) == 1: return 1 return 0 - def _is_cunion_base(self, base_node: ast.AST | t.CPtr) -> int: + def _is_cunion_base(self, base_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: """检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否""" if base_node is None: return 0 @@ -185,8 +202,20 @@ class ClassGenMixin: # Name('CUnion') 形式(from t import CUnion) if k == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - if nm.id is not None and string.strcmp(nm.id, "CUnion") == 0: + if nm.id is None: + return 0 + if string.strcmp(nm.id, "CUnion") == 0: return 1 + # 别名形式: from t import CUnion as un; class Data(un) + if trans is not None and trans._from_imports is not None: + alias_orig: str = HandlesImports.lookup_from_import_original( + trans._from_imports, nm.id) + if alias_orig is not None: + og_len_cu: t.CSizeT = 0 + while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0': + og_len_cu += 1 + if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 0: + return 1 return 0 # Attribute(t.CUnion) 形式 if k == ast.ASTKind.Attribute: @@ -196,7 +225,8 @@ class ClassGenMixin: return 0 return 0 - def _is_union_class(self, cd: ast.ClassDef | t.CPtr) -> int: + def _is_union_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: """检查 ClassDef 是否为 CUnion:继承自 t.CUnion 或 @t.CUnion 装饰器形式""" if cd is None: return 0 @@ -214,11 +244,12 @@ class ClassGenMixin: base_node: ast.AST | t.CPtr = bases.get(bi) if base_node is None: continue - if self._is_cunion_base(base_node) == 1: + if self._is_cunion_base(base_node, trans) == 1: return 1 return 0 - def _is_crenum_base(self, base_node: ast.AST | t.CPtr) -> int: + def _is_crenum_base(self, base_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: """检查 base 节点是否为 t.REnum,返回 1=是 / 0=否""" if base_node is None: return 0 @@ -226,8 +257,20 @@ class ClassGenMixin: # Name('REnum') 形式(from t import REnum) if k == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node) - if nm.id is not None and string.strcmp(nm.id, "REnum") == 0: + if nm.id is None: + return 0 + if string.strcmp(nm.id, "REnum") == 0: return 1 + # 别名形式: from t import REnum as ren; class Opt(ren) + if trans is not None and trans._from_imports is not None: + alias_orig: str = HandlesImports.lookup_from_import_original( + trans._from_imports, nm.id) + if alias_orig is not None: + og_len_cr: t.CSizeT = 0 + while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0': + og_len_cr += 1 + if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 0: + return 1 return 0 # Attribute(t.REnum) 形式 if k == ast.ASTKind.Attribute: @@ -237,7 +280,8 @@ class ClassGenMixin: return 0 return 0 - def _is_renum_class(self, cd: ast.ClassDef | t.CPtr) -> int: + def _is_renum_class(self, cd: ast.ClassDef | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: """检查 ClassDef 是否为 REnum:继承自 t.REnum 或 @t.REnum 装饰器形式""" if cd is None: return 0 @@ -255,7 +299,7 @@ class ClassGenMixin: base_node: ast.AST | t.CPtr = bases.get(bi) if base_node is None: continue - if self._is_crenum_base(base_node) == 1: + if self._is_crenum_base(base_node, trans) == 1: return 1 return 0 @@ -2392,15 +2436,15 @@ class ClassGenMixin: HandlesStruct.add_visible_struct(pool, class_name) # 枚举类:交给 HandlesEnum 处理 - if self._is_enum_class(cd) == 1: + if self._is_enum_class(cd, trans) == 1: return self._translate_enum_def(trans, cd) # 联合体类:交给联合体处理 - if self._is_union_class(cd) == 1: + if self._is_union_class(cd, trans) == 1: return self._translate_union_def(trans, cd) # REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局) - if self._is_renum_class(cd) == 1: + if self._is_renum_class(cd, trans) == 1: return self._translate_renum_def(trans, cd) # 泛型类:存储为模板,不发射 IR(等实例化时特化) diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp index d3451f5..569f379 100644 --- a/App/lib/core/Gen/ExprGenMixin.vp +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -1776,8 +1776,17 @@ class ExprGenMixin: trans.SymTab, nm.id) if lhs_alloca is not None: if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0: + ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca + # Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self + # (与 translate_binop 路径 1 一致,避免槽地址当对象地址) + if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ + and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: + load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, lhs_alloca.Ty.Pointee, lhs_alloca) + if load_self1 is not None: + ovl_self1 = load_self1 ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, lhs_alloca, rhs, op, trans, 1) + pool, builder, mod, ovl_self1, rhs, op, trans, 1) if ovl_result is not None: return ovl_result @@ -4947,6 +4956,196 @@ class ExprGenMixin: # P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算) # ============================================================ + # ============================================================ + # infer_expr_class - 从表达式推断结构体类名(共享推断) + # + # 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用: + # 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断: + # Call → 类实例化(func 为已注册结构体名);func 为 Attribute + # 时是方法调用,经 vpi 返回注解缓存解析返回类名 + # Name → 源变量的 AnnotClassName + # BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象) + # Attribute → 字段注解类名(_resolve_attr_field_class) + # 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。 + # ============================================================ + def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> str: + """从表达式推断结构体类名,无法推断返回 None""" + if node is None or trans is None: + return None + k: int = node.kind() + # Call: 类实例化 / 方法调用 + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None or cl.func is None: + return None + if cl.func.kind() == ast.ASTKind.Name: + cand: str = ((ast.Name | t.CPtr)(cl.func)).id + if cand is None: + return None + if HandlesStruct.find_struct(cand) is not None: + return cand + return None + if cl.func.kind() == ast.ASTKind.Attribute: + # 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名 + # (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。 + ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ca is None or ca.attr is None or ca.value is None: + return None + obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans) + if obj_cls is None: + return None + if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: + return None + cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls) + if cls_sha1 is None and trans.ModuleSha1 is not None: + cls_sha1 = trans.ModuleSha1 + ret_cls: str = None + if cls_sha1 is not None: + import lib.StubGen.VpiReader as VpiReader + temp_dir: str = None + # 跨 Mixin 不能 self 访问 Generator 的 TempDir 字段(字段按 + # 声明类隔离),经全局单例获取(同 HandlesAssign 模式) + import lib.core.Gen.Generator as Generator + g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g2 is not None and g2.TempDir is not None: + temp_dir = g2.TempDir + if temp_dir is not None: + VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) + annot_ret: str = VpiReader._lookup_vpi_ret_annot( + cls_sha1, obj_cls, ca.attr) + if annot_ret is not None: + ret_cls = self._extract_annot_class_name(pool, annot_ret) + return ret_cls + return None + # Name: 源变量注解 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None or nm.id is None: + return None + ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if ve is None: + return None + return ve.AnnotClassName + # BinOp/UnaryOp: 运算符重载返回同类对象 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop is None or bop.left is None: + return None + dunder: str = self._binop_to_dunder(bop.op) + if dunder is None: + return None + lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans) + if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: + return None + return lhs_cls + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop is None or uop.operand is None: + return None + dunder: str = self._unaryop_to_dunder(uop.op) + if dunder is None: + return None + opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans) + if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: + return None + return opr_cls + # Attribute: 字段注解类名(属性链递归,如 p = r.origin) + if k == ast.ASTKind.Attribute: + return self._resolve_attr_field_class(pool, trans, node) + return None + + # ============================================================ + # _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法 + # + # 与 try_operator_overload 的查找一致:当前模块内定义或跨模块类有 + # SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名, + # 避免把原生运算误标为类类型。 + # ============================================================ + def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, dunder: str) -> int: + """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" + if class_name is None or dunder is None or mod is None: + return 0 + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return 0 + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + if HandlesExprCall.find_func_in_module(mod, lookup_name) is not None: + return 1 + # 继承链祖先查找 + mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + anc_lookup: str = pool.alloc(128) + if anc_lookup is not None: + viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) + if HandlesExprCall.find_func_in_module(mod, anc_lookup) is not None: + return 1 + mi += 1 + # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 + if HandlesStruct.get_struct_sha1(class_name) is not None: + return 1 + return 0 + + # ============================================================ + # _extract_annot_class_name - 从返回注解文本提取结构体类名 + # + # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 + # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ + # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 + # 多候选时取首个命中段。 + # ============================================================ + def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, + annot: str) -> str: + """从返回注解文本提取已注册结构体类名,无命中返回 None""" + if pool is None or annot is None: + return None + alen: t.CSizeT = string.strlen(annot) + if alen == 0: + return None + seg: str = pool.alloc(256) + if seg is None: + return None + start: t.CSizeT = 0 + i: t.CSizeT + for i in range(alen): + if annot[i] == '|': + s: t.CSizeT = start + e: t.CSizeT = i + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen: t.CSizeT = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + if HandlesStruct.find_struct(seg) is not None: + return seg + start = i + 1 + # 最后一段(无 '|' 后缀) + s: t.CSizeT = start + e: t.CSizeT = alen + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen: t.CSizeT = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + if HandlesStruct.find_struct(seg) is not None: + return seg + return None + # ============================================================ # BinOp 运算符 → dunder 方法名 # ============================================================ @@ -5221,8 +5420,20 @@ class ExprGenMixin: lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( trans.SymTab, nm.id) if lhs_alloca is not None: + ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca + # alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时, + # load 出对象指针作为 self——若把槽地址当 self,dunder 内 + # load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest + # Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value + # 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义) + if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \ + and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0: + load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, lhs_alloca.Ty.Pointee, lhs_alloca) + if load_self1 is not None: + ovl_self1 = load_self1 ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( - pool, builder, mod, lhs_alloca, rhs, op, trans, 0) + pool, builder, mod, ovl_self1, rhs, op, trans, 0) if ovl_result is not None: return ovl_result diff --git a/App/lib/core/Gen/FuncGenMixin.vp b/App/lib/core/Gen/FuncGenMixin.vp index 77fa486..4b18f8f 100644 --- a/App/lib/core/Gen/FuncGenMixin.vp +++ b/App/lib/core/Gen/FuncGenMixin.vp @@ -1709,8 +1709,10 @@ class FuncGenMixin: # 9. 捕获变量:从 env 堆槽加载值到局部 alloca for ci in range(cap_count): - cap_addr: t.CUInt64T = t.CUInt64T(cap_names) + ci * 64 - cap_slot: str = (str)(cap_addr) + # 直接 str 指针偏移取捕获名(与 param_names + pi*32 一致)。 + # 注意:不能用 (str)(cap_addr) 整数转换——TPV 将其编译为 itoa(整数转字符串), + # 会把 cap_slot 变成数字串,define_var 键名错乱,lambda body lookup 无法命中。 + cap_slot: str = cap_names + ci * 64 if cap_slot[0] == '\0': continue ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8 @@ -1798,8 +1800,8 @@ class FuncGenMixin: builder, "malloc", env_size_val, 1, i8_ptr_ty, 0) if env_ptr is not None: for ci3 in range(cap_count): - cap_addr3: t.CUInt64T = t.CUInt64T(cap_names) + ci3 * 64 - cap_slot3: str = (str)(cap_addr3) + # 与步骤 9 一致:str 指针偏移判空,避免整数转换 itoa 语义 + cap_slot3: str = cap_names + ci3 * 64 if cap_slot3[0] == '\0': continue al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8 diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index d60c18c..2e146cd 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -660,19 +660,25 @@ class StructGenMixin: return 0 def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """从 Value 的类型推断结构体类型""" + """从 Value 的类型推断结构体类型 + + 递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针 + (如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload + 重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid + operand type for instruction)。 + """ if val is None or val.Ty is None: return None - # 嵌套 match:先匹配 Ptr,再在 case 块内匹配 pointee 是否为 Struct - match val.Ty: - case llvmlite.LLVMType.Ptr(pointee): - match pointee: - case llvmlite.LLVMType.Struct(fields, fcount, name): - return pointee - case _: - return None - case _: - return None + ty: llvmlite.LLVMType | t.CPtr = val.Ty + while ty is not None: + match ty: + case llvmlite.LLVMType.Ptr(pointee): + ty = pointee + case llvmlite.LLVMType.Struct(fields, fcount, name): + return ty + case _: + return None + return None def mark_as_union(self, name: str) -> int: """标记已注册的结构体为联合体,返回 1=成功 / 0=失败""" diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index a08a267..5d81696 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -346,6 +346,13 @@ class TranslatorGenMixin: HandlesAnnAssign._register_cdefine_from_value( pool, nm_cd.id, aa_cd.value) return 0 + # CTypedef 注解(如 stdint.vp float64_t: t.CTypedef = t.CFloat64T): + # 类型别名已由 ScanCTypedefDeclarations 注册到 CTypedef 表, + # 不创建全局变量——否则每个包含 stdint 的模块生成 + # @float64_t 全局 → 链接 duplicate symbol warning + # (跨 Mixin 经 HandlesAnnAssign 模块委托调用) + if HandlesAnnAssign.is_ctypedef_annotation(aa_cd.annotation) != 0: + return 0 # _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量 # CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过 diff --git a/App/lib/core/Gen/TypeGenMixin.vp b/App/lib/core/Gen/TypeGenMixin.vp index f7e138c..318dc18 100644 --- a/App/lib/core/Gen/TypeGenMixin.vp +++ b/App/lib/core/Gen/TypeGenMixin.vp @@ -1505,18 +1505,25 @@ class TypeGenMixin: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) if nm.id is None: return None + # 泛型特化上下文:T → 具体类型(特化方法体内局部变量注解 + # 如 `cur: T | t.CPtr` 未被 _clone_classdef_for_spec 克隆替换, + # 依赖此处在翻译时经上下文解析;否则 cur.annot="T", + # 属性访问 cur.Next → lookup_field_by_class("T") 未注册报错) + resolved_id: str = self.resolve_generic_type_name(nm.id) + if resolved_id is None: + return None # 跳过内置类型名 - if string.strcmp(nm.id, "str") == 0: + if string.strcmp(resolved_id, "str") == 0: return None - if string.strcmp(nm.id, "bytes") == 0: + if string.strcmp(resolved_id, "bytes") == 0: return None - if string.strcmp(nm.id, "bool") == 0: + if string.strcmp(resolved_id, "bool") == 0: return None - if string.strcmp(nm.id, "float") == 0: + if string.strcmp(resolved_id, "float") == 0: return None - if string.strcmp(nm.id, "double") == 0: + if string.strcmp(resolved_id, "double") == 0: return None - return nm.id + return resolved_id # Attribute 节点: memhub.MemBuddy → "memhub.MemBuddy"(模块限定名) if k == ast.ASTKind.Attribute: diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp index 6d450e0..d7c5e11 100644 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ b/App/lib/core/Handles/HandlesAnnAssign.vp @@ -59,6 +59,15 @@ def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int: return 0 +def is_ctypedef_annotation(annot: ast.AST | t.CPtr) -> int: + """检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否(委托到 gen._is_ctypedef_annotation)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_ctypedef_annotation(annot) + return 0 + + # ============================================================ # extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数) # @@ -310,6 +319,12 @@ class AnnAssignHandle(HandlesBase.Mixin): _register_cdefine_from_value(pool_ps, nm.id, aa.value) return 0 + # CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表), + # 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T + # 等生成 @float64_t 符号,链接 duplicate symbol warning + if is_ctypedef_annotation(aa.annotation) != 0: + return 0 + # global/nonlocal 变量不需要局部 alloca if HT.is_global_name(self.Trans, nm.id) != 0: return 0