import lib.core.Gen.GenTypes as GenTypes import t, c from stdint import * import ast import llvmlite import memhub import string import stdio import viperlib import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT import lib.core.CompilerFactory as CompilerFactory from . import ClassGenBase # ============================================================ # ClassGenDef - ClassGenMixin 拆分(阶段 D):translate_class_def 主入口 # # 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。 # 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。 # @t.NoVTable:静态绑定。 # ============================================================ @t.NoVTable class ClassGenDef(ClassGenBase.ClassGenBase): """translate_class_def 主入口""" # ============================================================ # translate_class_def — 翻译 class 定义(簇 D) # ============================================================ def translate_class_def(self, trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: """翻译 class 定义,返回 0""" if node is None or trans is None: return 0 cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node) if cd is None or cd.name is None: return 0 pool: memhub.MemBuddy | t.CPtr = trans.Pool class_name: str = cd.name if trans.ModuleSha1 is None: # fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)—— VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS") self.Gen.TypeGenErr.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError") # 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前, # 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类) self.Gen.StructGen.add_visible_struct(pool, class_name) # 枚举类:交给 HandlesEnum 处理 if self.Gen.ClassGenBase._is_enum_class(cd, trans) == 1: return self.Gen.ClassGenEnum._translate_enum_def(trans, cd) # 联合体类:交给联合体处理 if self.Gen.ClassGenBase._is_union_class(cd, trans) == 1: return self.Gen.ClassGenEnum._translate_union_def(trans, cd) # REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局) if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1: return self.Gen.ClassGenEnum._translate_renum_def(trans, cd) # 泛型类:存储为模板,不发射 IR(等实例化时特化) # 用局部变量接收 cd.type_params,触发类型推断 tp_val: list[str] | t.CPtr = cd.type_params if self.Gen.ClassGenGeneric._is_generic_class(tp_val) == 1: self.Gen.ClassGenGeneric._register_generic_template(pool, cd, trans.ModuleSha1) return 0 # 异常类(try-except):注册编码+继承树,不生成 struct # (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class → # _RegisterExceptionClass → return,异常类不编译为结构体) if self.Gen.ClassGenBase._is_exception_class_def(cd) == 1: return self.Gen.ClassGenBase._register_exception_class_def(trans, cd) # 检查是否已注册(用 SHA1 区分跨模块同名类) existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( class_name, trans.ModuleSha1) # 空类注册不完整检测:existing FieldCount==0 但源类体声明了字段 # (vpi 注入/注册缺陷,win32base SECURITY_ATTRIBUTES / win32file # WIN32_FIND_DATAA 根因)。此前标记 _deps_pending 延迟 → 空 entry 持久 # 存在导致多遍死锁不收敛。改为中和旧 entry(置空 Name + Ty=None,使其 # 不可再被 find_struct_by_module 命中),走下方完整注册路径重建。 needs_rereg: int = 0 if existing is not None: if existing.FieldCount == 0 and trans._declare_only == 0: if self.Gen.ClassGenBase._class_body_has_field(cd) != 0: VLogger.info(f"[DBG-EMP] class={class_name} FC=0 ty={t.CUInt64T(existing.Ty)} 类体有字段,中和重建", "DBG") if existing.Name is not None: existing.Name[0] = '\0' existing.Ty = None existing.FieldCount = 0 needs_rereg = 1 if existing is not None and needs_rereg == 0: # 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法 if existing.Ty is not None: # Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty, # 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1 # 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/ # self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。 # 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。 if trans._declare_only == 0: # 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空, # _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表 # 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType # 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。 ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( CompilerFactory.factory.PermPool, existing.Ty) if ty_deep is not None: existing.Ty = ty_deep old_name: str = llvmlite.get_struct_name(existing.Ty) if old_name is not None: on_len: t.CSizeT = string.strlen(old_name) on_copy: str = CompilerFactory.factory.PermPool.alloc(on_len + 1) if on_copy is not None: string.strcpy(on_copy, old_name) c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct( llvmlite.get_struct_fields(existing.Ty), llvmlite.get_struct_fcount(existing.Ty), on_copy)) # Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行) llvmlite.module_add_named_type(trans.Module, pool, existing.Ty) # Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体 # Phase B(declare_only=0)时全量翻译方法体 if trans._declare_only == 1: self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name, 1) else: self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name) # SHA1 已在 register_struct 时设置,无需再补 return 0 # ============================================================ # 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value]) # 必须在 _detect_vtable_status 和父类字段继承之前调用, # 否则 find_struct_by_module("GSListNode[Value]") 返回 None # ============================================================ self.Gen.ClassGenBase._trigger_base_specialization(trans, cd) # ============================================================ # VTable 检测:判断是否启用虚表 # ============================================================ has_vtable: int = self.Gen.ClassGenBase._detect_vtable_status(cd, trans) parent_name: str = self.Gen.ClassGenBase._get_parent_class(cd, trans) # 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用 parents_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.PARENT_MAX) parents_count: int = 0 if parents_buf is not None: parents_count = self.Gen.ClassGenBase._collect_parents(pool, cd, parents_buf, GenTypes.PARENT_MAX, trans) is_novtable_deco: int = 0 if cd.decorator_list is not None: if self.Gen.ClassGenBase._has_decorator(cd.decorator_list, "NoVTable") == 1: is_novtable_deco = 1 # ============================================================ # PhaseA 预注册延迟检查:父类未注册时延迟注册当前类 # # 根因:AssignHandle(HandlesBase.Mixin) 有自己的字段 _CurrentClass, # 当 Mixin 未注册时(字母序:HandlesAssign.py 在 HandlesBase.py 之前), # field_count=1(不是0),field_count==0 静默返回不触发, # AssignHandle 被注册为只有 _CurrentClass 字段(缺 Trans)。 # 后续遍 existing is not None,不补字段 → attribute ptr is None: self.Trans # # 修复:declare_only==1 且父类未注册时,延迟注册到下一遍。 # 多遍 PhaseA-pre 会在后续遍中重试(父类已注册后完整注册)。 # Phase B(declare_only==0)不延迟,避免死锁。 # ============================================================ if trans._declare_only == 1 and parent_name is not None: parent_check: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( parent_name, trans.ModuleSha1) if parent_check is None: parent_check = self.Gen.StructGen.find_struct(parent_name) if parent_check is None: return 0 # ============================================================ # 1. 遍历 class body,收集字段信息 # ============================================================ # 用 CSizeT 数组存储指针值(64 位系统上 8 字节) field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX) if field_names_buf is None or field_types_buf is None or field_defaults_buf is None: return 0 if field_annot_buf is None: return 0 string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX) string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX) string.memset(field_defaults_buf, 0, 8 * GenTypes.FIELD_MAX) string.memset(field_annot_buf, 0, 8 * GenTypes.FIELD_MAX) field_count: int = 0 # ============================================================ # 1.5 继承父类字段(字段展平) # ============================================================ # # 父类字段排在子类字段之前,结构体布局: # [vtable_ptr?, parent_field1, ..., child_field1, ...] # 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针) # ============================================================ # 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先) if parents_count > 0 and parents_buf is not None: for pi in range(parents_count): pname_addr: t.CSizeT = parents_buf[pi] if pname_addr == 0: continue pname: str = (str | t.CPtr)(t.CVoid(pname_addr, t.CPtr)) if pname is None: continue # 用 SHA1 感知查找父类,规避跨模块同名找错 parent_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module( pname, trans.ModuleSha1) if parent_entry is None: # 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin), # find_struct_by_module 不回退全局查找,此处手动回退到 find_struct, # 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败 parent_entry = self.Gen.StructGen.find_struct(pname) if parent_entry is None: # 父类尚未注册(依赖模块未翻译:Phase A 按文件序,子类模块可能 # 先于父类模块,如 Generator.vp G < TypeGenMixin.vp T)。此时 # **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool # 分配(init_struct_table L136-140),残缺条目跨 pass 存活, # 后续 pass 的 existing 早退(L2995-3006)永远无法修复 → 子类 # __init__ 写父类字段(self.TraceFrames)每遍永久失败。 # 整类 defer(不注册)+ 标记 _deps_pending 下遍重译;模块级 # 变量/函数参数解析失败静默降级 i32(handle_module_level_var # L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。 if trans is not None: trans._deps_pending = 1 # [PHASEADBG] 临时诊断:父类未注册即 pending 的根因(用后移除) stdio.printf("[PHASEADBG] 父类未注册: class=%s parent=%s\n", class_name, pname) return 0 pfc: int = parent_entry.FieldCount for pfi in range(pfc): pfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry( parent_entry, pfi) if pfe is None: continue pfn: str = self.Gen.StructGen.get_field_name_ptr(pfe) if pfn is None: continue # 跳过父类的 vtable 指针字段 if string.strcmp(pfn, "__vtable__") == 0: continue # 多继承去重:字段名已存在跳过(先声明父类优先) if self.Gen.ClassGenBase._field_name_exists(field_names_buf, field_count, pfn) != 0: continue if field_count < GenTypes.FIELD_MAX: pft: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_field_type_ptr(pfe) pfd: ast.AST | t.CPtr = self.Gen.StructGen.get_field_default_ptr(pfe) pfa: str = self.Gen.StructGen.get_field_annot_class_name(pfe) field_names_buf[field_count] = t.CSizeT(pfn) field_types_buf[field_count] = t.CSizeT(pft) if pfd is not None: field_defaults_buf[field_count] = t.CSizeT(pfd) else: field_defaults_buf[field_count] = 0 if pfa is not None: stored_val: t.CSizeT = t.CSizeT(pfa) field_annot_buf[field_count] = stored_val else: field_annot_buf[field_count] = 0 field_count += 1 children: list[ast.AST | t.CPtr] | t.CPtr = cd.children if children is None: return 0 cn: t.CSizeT = len(children) for ci in range(cn): stmt: ast.AST | t.CPtr = children.get(ci) if stmt is None: continue sk: int = stmt.kind() if sk != ast.ASTKind.AnnAssign: continue # AnnAssign(target=Name(id), annotation=type, value=...) aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt) if aa is None or aa.target is None: continue # 获取字段名 if aa.target.kind() != ast.ASTKind.Name: continue tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target) if tgt.id is None: continue # 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。 # 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查 # CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册 # 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。 if self.Gen.AssignGen.is_cdefine_annotation(aa.annotation) != 0: if aa.value is not None: self.Gen.AssignGen._register_cdefine_from_value(pool, tgt.id, aa.value) # CDefine 字段类型固定 i32,直接收集后跳过通用注解解析: # resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef # 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发 # 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。 # 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。 if field_count < GenTypes.FIELD_MAX: cdef_ty_l: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) if cdef_ty_l is not None: field_names_buf[field_count] = t.CSizeT(tgt.id) field_types_buf[field_count] = t.CSizeT(cdef_ty_l) if aa.value is not None: field_defaults_buf[field_count] = t.CSizeT(aa.value) else: field_defaults_buf[field_count] = 0 field_count += 1 continue # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) # 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码 # (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str] # 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。 if string.strcmp(tgt.id, "__provides__") == 0: self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_PROVIDES, class_name, aa.value) continue if string.strcmp(tgt.id, "__requires__") == 0: self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRES, class_name, aa.value) continue if string.strcmp(tgt.id, "__require_must__") == 0: self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRE_MUST, class_name, aa.value) continue # 解析字段类型 field_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0) # 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem] # (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义): # 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**), # for x in self.field 会误走指针迭代(元素非整数 → null 终止符 # 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。 if field_ty is not None: field_ty = self.Gen.AssignGen._infer_static_array_ty_from_literal( pool, aa.annotation, aa.value, field_ty) if field_ty is None: # BUG 5 方案1修改点1:消除 i32 静默回退 # Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍 # Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译 # 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱) # 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8), # 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name # 供 translate_attribute 做后续 bitcast。 is_generic_sub: int = 0 if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Subscript: is_generic_sub = 1 if is_generic_sub != 0: # 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复 field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool)) else: # Phase A-pre(declare_only=1):依赖的类可能尚未注册, # 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功) if trans._declare_only == 1: return 0 # Phase A(declare_only=0,Phase2.vp L573 多遍):依赖模块按 # 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp # H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 标记 # _deps_pending 下遍重译,不在本遍以残缺字段注册结构体。 # 真正的类型错误由 Phase A 收敛检查暴露("Phase A 无法完成 # 翻译: ,请检查依赖模块是否已编译/注册"),不静默掩盖。 if trans is not None: trans._deps_pending = 1 # [PHASEADBG] 临时诊断:字段注解类型未解析即 pending 的根因(用后移除) dbg_ak: t.CInt = -1 if aa.annotation is not None: dbg_ak = aa.annotation.kind() stdio.printf("[PHASEADBG] 字段类型未解析: class=%s field=%s annot_kind=%d\n", class_name, tgt.id, dbg_ak) return 0 # 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时 # 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底) # 存储到数组(指针转 CSizeT) if field_count < GenTypes.FIELD_MAX: diag_name_val: t.CSizeT = t.CSizeT(tgt.id) field_names_buf[field_count] = diag_name_val field_types_buf[field_count] = t.CSizeT(field_ty) # 存储默认值 AST 指针(None=无默认值) if aa.value is not None: field_defaults_buf[field_count] = t.CSizeT(aa.value) else: field_defaults_buf[field_count] = 0 # 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体) # BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]") if aa.annotation is not None: annot_cn: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation( aa.annotation, trans._imported_modules, pool, trans._from_imports) if annot_cn is not None: diag_cn_val: t.CSizeT = t.CSizeT(annot_cn) field_annot_buf[field_count] = diag_cn_val else: field_annot_buf[field_count] = 0 else: field_annot_buf[field_count] = 0 field_count += 1 if field_count == 0: # PhaseA 预注册时,父类可能尚未注册(字母序单遍扫描), # 导致子类无法继承父类字段 → field_count==0。 # 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。 if trans._declare_only == 1 and parent_name is not None: return 0 # 无字段类(接口/标记类):不能整体跳过——类可能只有方法 # (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。 # 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。 # ============================================================ # 2. 创建 LLVM StructType # ============================================================ # 构建 ParamNode 链表 first_node: llvmlite.ParamNode | t.CPtr = None prev_node: llvmlite.ParamNode | t.CPtr = None total_field_count: int = field_count # 如果有虚表,首字段添加 i8* vtable 指针 if has_vtable == 1: i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) if vtable_node is None: VLogger.error(f"failed to alloc vtable node for {class_name}", "CLASS") return 0 string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__()) vtable_node.Ty = i8_ptr_ty first_node = vtable_node prev_node = vtable_node total_field_count = field_count + 1 for fi in range(field_count): fty_addr: t.CSizeT = field_types_buf[fi] if fty_addr == 0: continue fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr, t.CPtr)) # 创建 ParamNode pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__()) if pnode is None: continue string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__()) pnode.Ty = fty if first_node is None: first_node = pnode if prev_node is not None: prev_node.Next = pnode prev_node = pnode # 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName" # 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续 # 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件 # reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。 type_name: str = class_name if trans.ModuleSha1 is not None: name_buf: str = pool.alloc(64) if name_buf is not None: viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name) type_name = name_buf if trans._declare_only == 0 and type_name is not None: tn_len: t.CSizeT = string.strlen(type_name) tn_copy: str = CompilerFactory.factory.PermPool.alloc(tn_len + 1) if tn_copy is not None: string.strcpy(tn_copy, type_name) type_name = tn_copy # 创建 StructType(命名结构体) struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name) if struct_ty is None: VLogger.error(f"failed to create StructType for {class_name}", "CLASS") return 0 # Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件 # 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType # 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树 # 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty # 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。 # StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1) # 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 → # 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields # 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。 if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0: st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType( CompilerFactory.factory.PermPool, struct_ty) if st_copy is not None: struct_ty = st_copy type_name = llvmlite.get_struct_name(struct_ty) # 注册命名结构体到模块(输出 %"name" = type { ... } 定义行) llvmlite.module_add_named_type(trans.Module, pool, struct_ty) # 扫描字段类型,为跨模块结构体引用添加 opaque 声明 # 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque for fi in range(field_count): fty_addr_op: t.CSizeT = field_types_buf[fi] if fty_addr_op == 0: continue fty_op: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr_op, t.CPtr)) llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op) # ============================================================ # 3. 注册到 HandlesStruct # ============================================================ entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct( pool, class_name, struct_ty, trans.ModuleSha1) if entry is None: VLogger.error(f"failed to register {class_name}", "CLASS") return 0 # 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错) if has_vtable == 1: entry.HasVTable = 1 if is_novtable_deco == 1: entry.IsNoVTable = 1 if parent_name is not None: # 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空; # _translate_oop_methods/_detect_vtable_status 会在后续文件 # find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活 if self.Gen.StructGen.get_stdlib_alloc() != 0: pn_len: t.CSizeT = string.strlen(parent_name) pn_buf: str = CompilerFactory.factory.PermPool.alloc(pn_len + 1) if pn_buf is not None: string.strcpy(pn_buf, parent_name) entry.ParentName = pn_buf else: entry.ParentName = parent_name # 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活) if parents_count > 0 and parents_buf is not None: self.Gen.StructGen.set_parent_names(pool, class_name, parents_buf, parents_count) # 添加字段信息 # 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始 if has_vtable == 1: i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) self.Gen.StructGen.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None) for fi in range(field_count): fname_addr: t.CSizeT = field_names_buf[fi] if fname_addr == 0: continue fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr)) fty_addr2: t.CSizeT = field_types_buf[fi] if fty_addr2 == 0: continue fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr2, t.CPtr)) # 恢复默认值 AST 指针 fdef_addr: t.CSizeT = field_defaults_buf[fi] fdef: ast.AST | t.CPtr = None if fdef_addr != 0: fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr)) # 恢复注解类名指针 fannot_addr: t.CSizeT = field_annot_buf[fi] fannot: str = None if fannot_addr != 0: fannot = (str)(t.CVoid(fannot_addr, t.CPtr)) if fname is not None and fty2 is not None: self.Gen.StructGen.add_field(pool, entry, fname, fty2, fdef, fannot) # Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体 if trans._declare_only == 1: self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name, 1) return 0 # ============================================================ # 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__ # ============================================================ self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name) return 0