import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Type.TypeSpec as TSpec 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 import lib.core.Gen.GenApi as GenApi import lib.core.Gen.DebugInfoGen as DebugInfoGen # 方法元数据 flag:TLS(@t.TLS 装饰器,对齐 ClassGenBase 本地常量;本地副本避免跨模块 CDefine 查找) define META_TLS = 32 # 虚表方法数上限 define VTBL_METHOD_MAX = 32 define SCOPE_FUNCTION = 1 # ============================================================ # ClassGenVTable - ClassGenMixin 拆分(阶段 D):vtable 收集/生成/方法翻译 # ============================================================ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase): """vtable 收集/生成/方法翻译""" # ============================================================ # _vtable_strcat — 将 src 追加到 dst 末尾 # ============================================================ def _vtable_strcat(self, dst: str, dst_size: sizet, src: str): """将 src 追加到 dst 末尾""" if dst is None or src is None: return dlen: sizet = string.strlen(dst) slen: sizet = string.strlen(src) remain: sizet = dst_size - dlen if remain <= 0: return i: sizet = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 dst[dlen + i] = '\0' # ============================================================ # _vtable_name_needs_quote — 检查 LLVM 标识符是否需要引号 # ============================================================ def _vtable_name_needs_quote(self, name: str) -> int: """检查 LLVM 标识符是否需要引号(以数字开头或含 '.')""" if name is None: return 0 if '0' <= name[0] <= '9': return 1 for i in name: if i == '.': return 1 return 0 # ============================================================ # _collect_vtable_methods — 收集类的虚方法信息 # # 1. 继承父类虚方法(父类方法排在子类方法之前,保持槽位顺序一致) # 2. 收集当前类虚方法(跳过已继承的) # # 结果存入 self.VtFullNames/VtMethodNames/VtParentSha1s/VtMethodCount # (原模块级 _g_vt_*),并设置 entry.VTableMethodCount / # VTableMethods(stdlib 分配,供虚分派跨模块查询)。 # # 返回 1=有虚方法 / 0=无方法或失败 # ============================================================ def _collect_vtable_methods(self, trans: HT.Translator*, cd: ast.ClassDef*, class_name: str) -> int: """收集虚方法信息,设置 entry.VTableMethods/VTableMethodCount""" if trans is None or cd is None or class_name is None: return 0 pool: memhub.MemBuddy* = trans.Pool mod: llvmlite.LLVMModule* = trans.Module children: list[ast.AST*]* = cd.children if children is None: return 0 cn: sizet = len(children) # 1. 收集虚方法信息 # stdlib 分配:method_names_buf 存到 StructEntry.VTableMethods(跨文件永久存活), # 必须迁出 mb 池 reset 区间,否则 1b 每文件 reset_to(mark1) 会回收导致悬空。 full_names_buf: sizet* = CompilerFactory.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) method_names_buf: sizet* = CompilerFactory.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) # 记录每个方法的父类 SHA1(非 0=继承方法用父模块 SHA1 mangling,0=当前类方法) method_parent_sha1s: sizet* = CompilerFactory.factory.PermPool.alloc(8 * VTBL_METHOD_MAX) if full_names_buf is None or method_names_buf is None or method_parent_sha1s is None: return 0 string.memset(full_names_buf, 0, 8 * VTBL_METHOD_MAX) string.memset(method_names_buf, 0, 8 * VTBL_METHOD_MAX) string.memset(method_parent_sha1s, 0, 8 * VTBL_METHOD_MAX) method_count: int = 0 # ============================================================ # 1.5 继承父类虚方法 # # 父类虚方法排在子类虚方法之前,保持 vtable 槽位顺序一致。 # 如果子类覆盖了方法,full_name 用子类的;否则用父类的。 # 用 SHA1 感知查找,规避跨模块同名 find_struct 找错 # ============================================================ vt_self_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1) # 多继承:遍历所有父类(声明顺序),vtable 方法合并(短名去重,先声明父类优先) parent_count: int = self.Gen.StructGen.get_parent_count(class_name) if parent_count > 0: for pi in range(parent_count): pname: str = self.Gen.StructGen.get_parent_name_at(class_name, pi) if pname is None: continue # 查找父类 entry(优先同模块 SHA1 匹配) vt_parent_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(pname, trans.ModuleSha1) if vt_parent_entry is None: # 跨模块继承: 父类在不同模块定义(SHA1 不同),回退到按类名查找 vt_parent_entry = self.Gen.StructGen.find_struct(pname) parent_vt_count: int = 0 if vt_parent_entry is not None: parent_vt_count = vt_parent_entry.VTableMethodCount if parent_vt_count > 0: for pvi in range(parent_vt_count): if method_count >= VTBL_METHOD_MAX: break pmethod_name: str = None if vt_parent_entry is not None: pmethod_name = self.Gen.StructGen.get_vtable_method_name(pname, pvi) if pmethod_name is None: continue # 多继承 vtable 去重:方法短名已存在跳过(先声明父类优先) if self.Gen.ClassGenBase._field_name_exists(method_names_buf, method_count, pmethod_name) != 0: continue # 检查子类是否覆盖了该方法,以及是否标记 @t.NoVTable child_overrides: int = 0 child_nvt: int = 0 for ci2 in range(cn): stmt2: ast.AST* = children.get(ci2) if stmt2 is None: continue if stmt2.kind() != ast.ASTKind.FunctionDef: continue fd2: ast.FunctionDef* = ast.FunctionDef*(stmt2) if fd2 is not None and fd2.name is not None: if string.strcmp(fd2.name, pmethod_name) == 0: child_overrides = 1 # 检查子类覆盖方法是否标记 @t.NoVTable if fd2.decorator_list is not None: if self.Gen.ClassGenBase._has_decorator(fd2.decorator_list, "NoVTable") == 1: child_nvt = 1 break # 构造 full_name # 子类覆盖且未标记 NoVTable → 用子类实现 # 子类未覆盖 或 子类覆盖但标记 NoVTable → 用实际定义类实现(保持 vtable 槽位) # # 多层继承修复: 直接父类可能只是继承而非定义该方法 # (如 ElectricCar 继承 Car 的 is_running 实际定义在 Vehicle), # 沿父类链向上用 find_func_global("类名.方法名") 探测实际定义类, # 避免生成 "Car.is_running" 这类找不到函数的 full_name → vtable 槽变 null。 def_class: str = class_name if child_overrides == 1 and child_nvt == 0: def_class = class_name else: def_class = pname # 多继承:沿 pname 的 MRO 祖先链探测实际定义类(跳过自身,先声明父类优先) mro_ptr: sizet* = self.Gen.StructGen.get_mro_chain(pool, pname) mro_i: int = 1 while mro_ptr is not None and mro_ptr[mro_i] != 0: anc: str = rawptr(mro_ptr[mro_i]) if anc is not None: probe_buf: str = pool.alloc(128) if probe_buf is not None: viperlib.snprintf(probe_buf, 128, "%s.%s", anc, pmethod_name) if self.Gen.CallGenLeafKit.find_func_global(probe_buf) is not None: def_class = anc break mro_i += 1 pfname_buf: str = CompilerFactory.factory.PermPool.alloc(128) if pfname_buf is not None: viperlib.snprintf(pfname_buf, 128, "%s.%s", def_class, pmethod_name) full_names_buf[method_count] = sizet(pfname_buf) # 复制方法名(短名) pmname_len: sizet = string.strlen(pmethod_name) pmname_buf: str = CompilerFactory.factory.PermPool.alloc(pmname_len + 1) if pmname_buf is not None: string.strcpy(pmname_buf, pmethod_name) method_names_buf[method_count] = sizet(pmname_buf) # 记录 mangling 用的 SHA1(继承未覆盖的方法用实际定义类的模块 SHA1) if child_overrides == 1 and child_nvt == 0: # 子类覆盖: 用当前模块 SHA1(保持 0) method_parent_sha1s[method_count] = 0 else: # 继承未覆盖: 用实际定义类的模块 SHA1(跨模块继承时 mangling 正确) def_entry2: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(def_class) if def_entry2 is not None and def_entry2.ModuleSha1 is not None: method_parent_sha1s[method_count] = sizet(def_entry2.ModuleSha1) else: method_parent_sha1s[method_count] = 0 method_count += 1 # 2. 收集当前类的虚方法(跳过已从父类继承的) for ci in range(cn): stmt: ast.AST* = children.get(ci) if stmt is None: continue if stmt.kind() != ast.ASTKind.FunctionDef: continue fd: ast.FunctionDef* = ast.FunctionDef*(stmt) if fd is None or fd.name is None: continue if method_count >= VTBL_METHOD_MAX: break mname: str = fd.name # 跳过构造函数和特殊方法(不应放入虚表) if string.strcmp(mname, "__init__") == 0: continue if string.strcmp(mname, "__before_init__") == 0: continue if string.strcmp(mname, "__new__") == 0: continue # 函数级装饰器过滤:判断方法是否应该进入虚表 if self.Gen.ClassGenBase._should_method_be_virtual(cd, fd, trans) == 0: continue # 检查是否已从父类继承(避免重复) already_in_vt: int = 0 for mi in range(method_count): exist_addr: sizet = method_names_buf[mi] if exist_addr != 0: exist_name: str = rawptr(exist_addr) if exist_name is not None and string.strcmp(exist_name, mname) == 0: already_in_vt = 1 break if already_in_vt == 1: continue # 构造 full_name = "ClassName.method_name" # 内容必须落在 perm_pool:1a(mark_only=1)收集的 VTableMethods 被 # Phase 1b 依赖模块翻译跨文件读取,1a 每文件 reset 后 pool 裸字符串悬空 fname_buf: str = CompilerFactory.factory.PermPool.alloc(128) if fname_buf is not None: viperlib.snprintf(fname_buf, 128, "%s.%s", class_name, mname) full_names_buf[method_count] = sizet(fname_buf) # 复制方法名 mname_len: sizet = string.strlen(mname) mname_buf: str = CompilerFactory.factory.PermPool.alloc(mname_len + 1) if mname_buf is not None: string.strcpy(mname_buf, mname) method_names_buf[method_count] = sizet(mname_buf) method_count += 1 # 暂存结果(_generate_vtable 复用) self.VtFullNames = full_names_buf self.VtMethodNames = method_names_buf self.VtParentSha1s = method_parent_sha1s self.VtMethodCount = method_count # 设置 entry 元数据(虚分派查询用;必须在本类方法体翻译前就绪, # 否则方法体内 self.虚方法 调用无法虚分派) if vt_self_entry is not None and method_count > 0: vt_self_entry.VTableMethodCount = method_count vt_self_entry.VTableMethods = method_names_buf if method_count == 0: return 0 return 1 # ============================================================ # _generate_vtable — 生成 VTable 全局变量 # # 1. 收集 class body 中所有 FunctionDef 作为虚方法 # 2. 构造 VTable 类型 { i8*, i8*, ... } # 3. 构造初始化字符串 { i8* bitcast (...), ... } # 4. 创建全局变量 @"SHA1.ClassName.vtable" # 5. 存储虚方法名列表到 StructEntry # ============================================================ def _generate_vtable(self, trans: HT.Translator*, cd: ast.ClassDef*, class_name: str) -> int: """生成 VTable 全局变量""" if trans is None or cd is None or class_name is None: return 0 pool: memhub.MemBuddy* = trans.Pool mod: llvmlite.LLVMModule* = trans.Module # 收集虚方法信息(继承父类 + 自身,结果存 self.VtFullNames 等暂存区) # 同时设置 entry.VTableMethodCount/VTableMethods(虚分派查询用) if self._collect_vtable_methods(trans, cd, class_name) == 0: return 0 full_names_buf: sizet* = self.VtFullNames method_names_buf: sizet* = self.VtMethodNames method_parent_sha1s: sizet* = self.VtParentSha1s method_count: int = self.VtMethodCount # 重新获取 entry(后续存储 VTableMethods 用) vt_self_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1) # 2. 构造 VTable 类型: { i8*, i8*, ..., i8* } i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool) i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty) first_node: llvmlite.ParamNode* = None tail_node: llvmlite.ParamNode* = None for i in range(method_count): pnode: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8_ptr_ty) if pnode is None: continue tail_node = llvmlite.param_list_append(first_node, tail_node, pnode) if first_node is None: first_node = tail_node vtable_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, first_node, method_count, None) if vtable_ty is None: return 0 # 3. 构造初始化字符串 # 大 vtable(如 MemBuddy 28+ 方法)每个方法 bitcast 约 100+ 字节, # 4096 可能写满导致截断/strlen 越界,用 16384 预留足够空间。 init_buf: str = pool.alloc(16384) if init_buf is None: return 0 init_buf[0] = '\0' self._vtable_strcat(init_buf, 16384, "{ ") for i in range(method_count): if i > 0: self._vtable_strcat(init_buf, 16384, ", ") full_name_addr: sizet = full_names_buf[i] if full_name_addr == 0: self._vtable_strcat(init_buf, 16384, "i8* null") continue full_name: str = rawptr(full_name_addr) # 检查是否是继承方法(method_parent_sha1s 非 0 表示用父模块 SHA1 mangling) parent_sha1_addr: sizet = method_parent_sha1s[i] if parent_sha1_addr != 0: # 继承方法: 用父类模块 SHA1 做 mangling parent_sha1: str = rawptr(parent_sha1_addr) mangled_name: str = self.Gen.FuncGenBase._mangle_name_with_sha1(parent_sha1, full_name) else: # 当前类方法: 用当前模块 SHA1 mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) # 统一从全局表 entry.Spec 用 SpecToLLVMText 派生函数类型文本。 # 全局表 entry.Spec 在方法 add_param 完成后由 update_global_func_spec 填 # (PermPool 驻留,跨 1b reset 安全),故不再解引用 func(func 可能已被 # reset_to(mark1) 回收悬空)。 ge: GenTypes.FuncEntry* = self.Gen.CallGenLeafKit.find_func_entry_global(full_name) func_ty_buf: str = pool.alloc(1024) if func_ty_buf is None: self._vtable_strcat(init_buf, 16384, "i8* null") continue func_ty_buf[0] = '\0' if ge is None or ge.Spec is None or TSpec.SpecToLLVMText(ge.Spec, func_ty_buf, 1024) != 0: self.Gen.TypeGenErr.fatal_error(cd, f"vtable 方法 '{full_name}' 找不到函数类型", "InternalCompilerError") continue # 构造 bitcast 字符串: i8* bitcast (func_ty* @mangled to i8*) self._vtable_strcat(init_buf, 16384, "i8* bitcast (") self._vtable_strcat(init_buf, 16384, func_ty_buf) self._vtable_strcat(init_buf, 16384, "* @") if self._vtable_name_needs_quote(mangled_name) != 0: self._vtable_strcat(init_buf, 16384, "\"") self._vtable_strcat(init_buf, 16384, mangled_name) self._vtable_strcat(init_buf, 16384, "\"") else: self._vtable_strcat(init_buf, 16384, mangled_name) self._vtable_strcat(init_buf, 16384, " to i8*)") self._vtable_strcat(init_buf, 16384, " }") # 4. 构造 VTable 全局变量名 vtable_name_buf: str = pool.alloc(128) if vtable_name_buf is None: return 0 viperlib.snprintf(vtable_name_buf, 128, "%s.vtable", class_name) vtable_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vtable_name_buf) # 5. 创建全局变量 gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, vtable_mangled, vtable_ty) if gv is None: return 0 gv.Initializer = init_buf gv.IsConstant = 1 # 默认 linkage(external,2026-08-10):isinstance 内建函数需要跨模块 # 引用其他模块类的 vtable 符号({模块sha1}.Class.vtable),internal 不对外 # 导出会导致链接失败。vtable 名含模块 sha1 前缀全局唯一,外部可见不冲突。 # llvmlite 打印规则:Initializer 非空 + external 时不打印 external 关键字, # 输出 @name = constant {...}(合法外部强定义)。 # 添加到模块 llvmlite.module_add_global(mod, gv) # 6. 存储虚方法名列表到 StructEntry(直接用 entry,规避跨模块同名 find_struct 找错) if vt_self_entry is not None: vt_self_entry.VTableMethods = method_names_buf vt_self_entry.VTableMethodCount = method_count return 0 # ============================================================ # _translate_oop_methods — 扫描 class body 中的方法并翻译 # # 遍历 ClassDef.children,对每个 FunctionDef: # - 标记 OOP(mark_as_oop) # - 如果是 __init__,标记 has_init # - 翻译方法(生成 SHA1.ClassName.method_name 函数) # 翻译完所有方法后,生成 __before_init__ 函数 # ============================================================ def _translate_oop_methods(self, trans: HT.Translator*, cd: ast.ClassDef*, struct_ty: llvmlite.LLVMType*, class_name: str, mark_only: int = 0, reemit: int = 0) -> int: """扫描 class body 中的方法并翻译,生成 __before_init__ mark_only: 0=全量翻译(默认),1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体) reemit: 1=补译模式(_specialize_generic_class Phase B 补译分支调用)。 补译分支为防重入已提前置 MethodsEmitted=1,但方法体尚未发射, 必须跳过下方 MethodsEmitted==1 的防重复检查强制发射,否则补译 被自身拦截 → 特化方法只有 call 无 define → 链接 undefined symbol。 """ if trans is None or cd is None or struct_ty is None or class_name is None: return 0 children: list[ast.AST*]* = cd.children if children is None: return 0 cn: sizet = len(children) has_method: int = 0 has_init: int = 0 has_new: int = 0 # 提前用类型指针定位 entry(规避跨模块同名类 find_struct 找错) oop_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty) # 第一遍:检测是否有方法,标记 OOP,并注册装饰器元数据 for ci in range(cn): stmt: ast.AST* = children.get(ci) if stmt is None: continue if stmt.kind() == ast.ASTKind.FunctionDef: has_method = 1 fd_check: ast.FunctionDef* = ast.FunctionDef*(stmt) if fd_check is not None and fd_check.name is not None: if string.strcmp(fd_check.name, "__init__") == 0: has_init = 1 if string.strcmp(fd_check.name, "__new__") == 0: has_new = 1 # 注册装饰器元数据(@property/@staticmethod/@classmethod/@x.setter 等)。 # 此处(含 mark_only=1 的 struct 预注册阶段)注册, # 确保其他模块在 App 文件翻译时能识别属性访问。 fd_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd_check.decorator_list) if fd_meta != 0: self.Gen.ClassGenBase.register_method_meta(class_name, fd_check.name, fd_meta) if has_method == 0: # 子类没有自己的方法,但可能继承了父类的虚方法 # 用 oop_entry 直接获取 ParentName,规避 find_struct 按名查找找错 parent_name: str = None if oop_entry is not None: parent_name = oop_entry.ParentName if parent_name is not None: parent_vt_count: int = self.Gen.StructGen.get_vtable_method_count(parent_name) if parent_vt_count > 0: has_method = 1 # 标记为有方法(继承的虚方法) if has_method == 0: return 0 # 标记为 OOP 结构体 if oop_entry is not None: oop_entry.IsOOP = 1 if has_init != 0: oop_entry.HasInit = 1 if has_new != 0: oop_entry.HasNew = 1 # mark_only 模式:只设置标志,不翻译方法体 if mark_only != 0: # Phase 1a 预注册也收集 vtable 元数据(VTableMethods/VTableMethodCount): # 若 1b 中依赖模块先于其依赖类全量翻译,调用方会查到 HasVTable=1 但 # VTableMethods=None → 虚分派条件不成立 → 方法被静态绑定到基类实现(返回 # None)→ __new__ 返回 null → 崩溃。短名顺序与 Phase 1b 全量收集一致 # (父类方法在前 + 本类方法);多遍重复收集用新缓冲区覆盖(幂等)。 mk_has_vt: int = 0 if oop_entry is not None: mk_has_vt = oop_entry.HasVTable if mk_has_vt == 1: self._collect_vtable_methods(trans, cd, class_name) return 0 # 防重复生成:MethodsEmitted==1 说明方法体/__before_init__ 已生成过。 # 场景:_specialize_generic_class 的 Phase B 补译分支(MethodsEmitted==0 # 时补译方法体并置 1)之后,同一特化类又经 translate_class_def 全量 # 翻译进入本方法 → 重复生成 __before_init__ → ld.lld duplicate symbol。 # 已生成过则直接跳过(方法+__before_init__ 都产出过,跳过安全)。 # reemit=1(补译模式)时跳过本检查:补译分支为防重入已提前置 # MethodsEmitted=1,但方法体尚未发射,必须强制发射。 if oop_entry is not None and oop_entry.MethodsEmitted == 1 and reemit == 0: return 0 # 防重入:方法体翻译前先标记 MethodsEmitted=1。 # 根因:若等全部方法译完再标记,翻译 __iter__(返回 list[T]|t.CPtr)时, # 返回类型注解会再次触发 _specialize_generic_class,此时 MethodsEmitted # 仍为 0,走补译分支把同一特化类方法全部重发 → invalid redefinition。 if oop_entry is not None: oop_entry.MethodsEmitted = 1 # 第二遍:翻译每个方法 # 翻译方法体前先预注册 vtable 元数据(VTableMethods/VTableMethodCount)。 # 根因:方法体翻译先于 _generate_vtable,若不预注册,方法体内的 # self.虚方法 调用(如 MemManager.calloc 里的 self.alloc)读不到 # VTableMethods,虚分派失败,被静态绑定到本类实现(基类 alloc 返回 # None),导致 calloc 永远返回 NULL。 oop_has_vt_pre: int = 0 if oop_entry is not None: oop_has_vt_pre = oop_entry.HasVTable if oop_has_vt_pre == 1: self._collect_vtable_methods(trans, cd, class_name) # 先声明后定义:翻译方法体之前,先为本类**全部方法**建立前向声明 # (declare + 参数 + 函数表登记),使方法查找(find_func_in_module)不再 # 依赖方法在类体中的书写顺序。与 FuncGenDef.forward_declare_functions # 对模块级函数做的事完全同构。缺此步的现场:includes/w32/fileio.vp 的 # FileW.__init__(源 304 行)调 self.seek(...),而 FileW.seek 定义在源 # 403 行 → 查不到 → 被同名方法扫描误绑到 File.seek → 指针规则以 # FileW* → File* 报 CastError(旧 IR 靠 bitcast 静默掩盖)。 for ci_pd in range(cn): stmt_pd: ast.AST* = children.get(ci_pd) if stmt_pd is None: continue if stmt_pd.kind() == ast.ASTKind.FunctionDef: fd_pd: ast.FunctionDef* = ast.FunctionDef*(stmt_pd) if fd_pd is not None and fd_pd.name is not None: self._translate_method(trans, fd_pd, struct_ty, class_name, 1) for ci in range(cn): stmt: ast.AST* = children.get(ci) if stmt is None: continue if stmt.kind() == ast.ASTKind.FunctionDef: fd: ast.FunctionDef* = ast.FunctionDef*(stmt) if fd is not None and fd.name is not None: self._translate_method(trans, fd, struct_ty, class_name) # 如果有虚表,先生成 VTable 全局变量(设置 VTableMethodCount) # 必须在 __before_init__ 之前,否则 __before_init__ 读不到 VTableMethodCount # 用 oop_entry 直接检查,规避跨模块同名 find_struct 找错 has_vt_flag: int = 0 if oop_entry is not None: has_vt_flag = oop_entry.HasVTable if has_vt_flag == 1: self._generate_vtable(trans, cd, class_name) # 生成 __before_init__ 函数(零值填充 + 默认值赋值 + vtable 指针设置) self._generate_before_init(trans, struct_ty, class_name) return 0 # ============================================================ # _translate_method — 翻译单个方法 # # 生成: define @SHA1.ClassName.method_name(Ptr(StructTy) %self, ...) # # self 参数处理: # - 类型 Ptr(struct_ty),直接注册为 SSA 值(不创建 alloca) # - 使 self.field 能通过 GEP 直接访问原始结构体 # ============================================================ def _translate_method(self, trans: HT.Translator*, fd: ast.FunctionDef*, struct_ty: llvmlite.LLVMType*, class_name: str, sig_only: int = 0) -> int: """翻译单个方法,返回 0 sig_only: 1=只建前向声明(declare + 参数 + 函数表登记),不发射函数体。 _translate_oop_methods 在翻译方法体之前对本类**全部方法**先跑一遍 sig_only=1(与 FuncGenDef.forward_declare_functions 对模块级函数做的事 完全同构),使方法查找(find_func_in_module)不再依赖方法在类体中的 书写顺序。反例:includes/w32/fileio.vp 的 FileW.__init__(源 304 行) 调用 self.seek(...),而 FileW.seek 定义在源 403 行——没有预声明时 查不到 FileW.seek,会落到"同名方法扫描"并误绑 File.seek,再被指针 规则以 FileW* → File* 报 CastError。 """ if trans is None or fd is None or struct_ty is None or class_name is None: return 0 pool: memhub.MemBuddy* = trans.Pool mod: llvmlite.LLVMModule* = trans.Module imported_modules: str = trans._imported_modules from_imports: str = trans._from_imports funcs_ptr: GenTypes.FuncEntry* = trans._funcs func_count: int = trans._func_count i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool) self_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, struct_ty) method_name: str = fd.name if method_name is None: # fail-fast:方法名缺失(解析器不可能产出无名 def)——静默打印 VLogger.error("方法名缺失(fd.name is None)", "OOP") self.Gen.TypeGenErr.fatal_error(fd, "方法名缺失(fd.name is None)", "TypeError") # 提取装饰器元数据(@property/@staticmethod/@classmethod/@x.setter/@x.deleter) func_meta: int = self.Gen.ClassGenBase._extract_func_meta(fd.decorator_list) # property setter/deleter 函数名带 $set/$del 后缀,避免与 getter 冲突 method_name_buf: str = pool.alloc(128) if method_name_buf is None: return 0 viperlib.snprintf(method_name_buf, 128, "%s", fd.name) if func_meta & GenTypes.META_PROP_SETTER != 0: # 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿 mn_len2: sizet = string.strlen(method_name_buf) if mn_len2 + 5 < 128: string.strcat(method_name_buf, "$set") elif func_meta & GenTypes.META_PROP_DELETER != 0: mn_len2: sizet = string.strlen(method_name_buf) if mn_len2 + 5 < 128: string.strcat(method_name_buf, "$del") method_name = method_name_buf is_static_m: int = 0 is_class_m: int = 0 is_tls_m: int = 0 if func_meta & GenTypes.META_STATIC != 0: is_static_m = 1 if func_meta & GenTypes.META_CLASS != 0: is_class_m = 1 if func_meta & META_TLS != 0: is_tls_m = 1 # 构建方法全名: ClassName.method_name full_name_buf: str = pool.alloc(128) if full_name_buf is None: return 0 viperlib.snprintf(full_name_buf, 128, "%s.%s", class_name, method_name) full_name: str = full_name_buf # SHA1 命名空间混淆 mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) # 推断返回类型 ret_ty: llvmlite.LLVMType* = None if fd.returns is not None: ret_ty = self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imported_modules, from_imports, trans, 0) if ret_ty is None and fd.returns is not None: # 存储类标记(t.State / t.CExport / t.CExtern)语义为 Void:这类注解 # 不携带真实返回类型(extern/export 语法写成 "<原类型> | t.<标记>", # 原类型已解析成功时不会走到这里,此处只处理标记本身/解析后仍为 None)。 if self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) != 0 \ or self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport", 0) != 0 \ or self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExtern", 0) != 0: ret_ty = llvmlite.Void(pool) else: # [S4 fail-fast] 有返回注解但解析失败 → 不再退回 infer_return_type() # (推断可能给出与真实注解不符的类型,静默错到运行期才暴露) self.Gen.TypeGenErr.fatal_error(fd, f"方法 '{class_name}.{method_name}' 返回类型注解解析失败", "NameError") return 0 if ret_ty is None: # __init__ 和 __before_init__ 返回 void if string.strcmp(method_name, "__init__") == 0: ret_ty = llvmlite.Void(pool) # __new__ 返回 Ptr(struct_ty)(结构体指针作为存储空间) elif string.strcmp(method_name, "__new__") == 0: ret_ty = llvmlite.Ptr(pool, struct_ty) else: param_types_str: str = self.Gen.TypeGenErr.build_param_types_str(pool, fd.args) ret_ty = self.Gen.TypeGenErr.infer_return_type(pool, fd.children, param_types_str) # 创建/复用 LLVM 函数。 # 复用场景:本类的"先声明后定义"预扫描(sig_only=1)已用 create_declare 建好 # 同名前向声明(IsDeclared=1),此处跳过参数创建与函数表登记(声明期已完成), # 只把 IsDeclared 清零转 define——与 FuncGenDef.forward_declare_functions # (FuncGenDef.vp:25-30)→ translate_function_def(FuncGenDef.vp:544-545)的 # 模块级函数前向声明机制同构。 func: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, mangled_name) decl_reuse: int = 0 if func is not None: if func.IsDeclared == 0: # 同名函数体已发射:禁止重复发射(duplicate symbol) return 0 decl_reuse = 1 else: func = llvmlite.create_declare(pool, mod, mangled_name, ret_ty) if func is None: return 0 if sig_only != 0: # 前向声明模式:已声明过直接返回;否则下方登记完参数/函数表后返回。 if decl_reuse != 0: return 0 else: # 发射函数体前必须把 IsDeclared 清零,否则打印端按 IsDeclared 输出 # declare、函数体整体丢失(对齐 FuncGenDef.vp:544-545)。 func.IsDeclared = 0 # 形参表:下方"函数体段"(形参建 alloca + 登记符号)与参数创建块都要用, # 必须声明在 decl_reuse 分支之外——复用前向声明时不再走参数创建块, # 但函数体段仍要遍历形参,否则实参名不进符号表(NameError: 未定义名称)。 args_node: ast.Arguments* = fd.args if decl_reuse == 0: # 提取默认参数信息(普通方法 args[0] 是 self,不含在 param_count 中; # @staticmethod 无 self,param_count 为完整参数数) # 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(), # 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错 md_defaults: t.CPtr = None md_default_count: int = 0 md_param_count: int = 0 md_args_node: ast.Arguments* = fd.args if md_args_node is not None: md_ags: ast.Arguments* = ast.Arguments*(md_args_node) if md_ags.args is not None: md_alist: list[ast.AST*]* = md_ags.args if is_static_m != 0: md_param_count = len(md_alist) else: md_param_count = len(md_alist) - 1 if md_ags.defaults is not None: md_dlist: list[ast.AST*]* = md_ags.defaults md_defaults = md_dlist md_default_count = len(md_dlist) # 注册到函数表(用 ClassName.method_name 作为查找名,支持后缀匹配) max_funcs: int = 1024 if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, md_defaults, md_default_count, md_param_count, pool) == 0: trans._func_count = func_count + 1 # 添加 self/cls 参数(Ptr(struct_ty));@staticmethod 无 self,跳过 # @classmethod 的 cls 也用 Ptr(struct_ty),首参名取 args[0](如 cls) if is_static_m == 0: first_pname: str = "self" if is_class_m != 0 and fd.args is not None: fd_ags: ast.Arguments* = ast.Arguments*(fd.args) if fd_ags.args is not None and len(fd_ags.args) > 0: fd_first_arg: ast.Arg* = ast.Arg*(fd_ags.args.get(0)) if fd_first_arg is not None and fd_first_arg.arg is not None: first_pname = fd_first_arg.arg first_pname_buf: str = pool.alloc(32) if first_pname_buf is not None: viperlib.snprintf(first_pname_buf, 32, "%%%s", first_pname) llvmlite.add_param(pool, func, self_ptr_ty, first_pname_buf) # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) # args_node 已在 decl_reuse 分支之外声明(函数体段同样要用) if args_node is not None: ags: ast.Arguments* = ast.Arguments*(args_node) if ags.args is not None: alist: list[ast.AST*]* = ags.args an: sizet = len(alist) start_idx: int = 0 if is_static_m == 0: start_idx = 1 for ai in range(start_idx, an): arg: ast.Arg* = ast.Arg*(alist.get(ai)) if arg is not None and arg.arg is not None: param_ty: llvmlite.LLVMType* = i32_ty if arg.annotation is not None: resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, imported_modules, from_imports, trans, 0) if resolved is None: # [S4 fail-fast] 有注解但解析失败:不再静默用 i32 # (方法签名与调用点/实现体三方不一致) self.Gen.TypeGenErr.fatal_error(arg, f"方法 '{class_name}.{method_name}' 形参 '{arg.arg}' 类型注解解析失败", "NameError") return 0 # 裸类形参 → Ptr(struct):按"对象即指针"引用传参。 # 若按 struct 值传参,self.Head = node 会取局部拷贝地址 # (append 返回后悬垂,G5 Test4 head.Value 读到垃圾)。 # CArray 形参 → 元素指针 ty*(数组衰减,C 语义,与函数形参一致)。 match resolved: case llvmlite.LLVMType.Void(): # void 不是合法形参类型(用户 2026-10-01:void 只能用于 # `void*` 与 `typedef 不透明结构体 = void`);`void*` 已在上游 # 归并为 i8*,不会命中此分支。放任会按 LLVM void 建形参 ⇒ # 非法 IR 拖到 llc 才暴露,改编译期 fail-fast。 self.Gen.TypeGenErr.fatal_error(arg, f"方法 '{class_name}.{method_name}' 形参 '{arg.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError") return 0 case llvmlite.LLVMType.Struct(_, _, _): param_ty = llvmlite.Ptr(pool, resolved) case llvmlite.LLVMType.Array(aelem_ty, _): param_ty = llvmlite.Ptr(pool, aelem_ty) case _: param_ty = resolved pname: str = pool.alloc(32) if pname is not None: viperlib.snprintf(pname, 32, "%%%s", arg.arg) llvmlite.add_param(pool, func, param_ty, pname) # OOP iter 协议:__next__ 方法注入隐藏参数 __stop_iter_flag__(i1*)。 # raise StopIteration 时置 1(对齐 TPC HandlesFunctions.py L703-705)。 # 该参数不计入 md_param_count(逻辑参数),调用侧(for 循环)显式传。 if string.strcmp(method_name, "__next__") == 0: i1_ty_si: llvmlite.LLVMType* = llvmlite.Int1(pool) if i1_ty_si is not None: i1_ptr_ty_si: llvmlite.LLVMType* = llvmlite.Ptr(pool, i1_ty_si) if i1_ptr_ty_si is not None: llvmlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__") # 参数添加完成,补全全局函数表的 Spec(供 vtable 在 func 被 reset 后派生类型文本) self.Gen.CallGenLeafKit.update_global_func_spec(full_name, func) # 前向声明模式:签名与函数表登记已完成,不发射函数体 if sig_only != 0: return 0 # 创建 entry 块 entry_blk: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "entry") if entry_blk is None: return 0 # 创建方法专属 builder func_builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, func) if func_builder is None: return 0 llvmlite.position_at_end(func_builder, entry_blk) # --traceback: attach a DISubprogram to this method define (same as the # module-level function path). No-op when DI is disabled. dbg_pushed: int = DebugInfoGen.PushFunction(pool, func_builder, func, fd.lineno, fd.col_offset + 1) # @t.TLS 一次性初始化守卫(对齐 TPC HandlesFunctions.py L1763-1792; # 与 FuncGenMixin.translate_function_def 同一实现,类方法同样支持) if is_tls_m != 0: tls_m_flag_name: str = pool.alloc(128) if tls_m_flag_name is not None: viperlib.snprintf(tls_m_flag_name, 128, "__tls_init_done_%s", method_name) tls_m_gv: llvmlite.GlobalVariable* = llvmlite.create_global_int(pool, mod, tls_m_flag_name, 1, 0) if tls_m_gv is not None: i1_ty_m: llvmlite.LLVMType* = llvmlite.Int1(pool) if i1_ty_m is not None: # GlobalVariable 非 Value 子类:构造 Value 视图后再 load/store tls_m_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i1_ty_m) tls_m_rn: str = pool.alloc(64) if tls_m_rn is not None: viperlib.snprintf(tls_m_rn, 64, "@%s", tls_m_flag_name) tls_m_ref: llvmlite.Value* = llvmlite.SSAValue(pool, tls_m_ptr_ty, tls_m_rn) if tls_m_ref is not None: tls_m_ld: llvmlite.Value* = llvmlite.build_load(func_builder, i1_ty_m, tls_m_ref) lc_m: int = trans._label_counter trans._label_counter = lc_m + 1 tls_m_buf: str = pool.alloc(64) if tls_m_buf is not None: viperlib.snprintf(tls_m_buf, 64, "tls.skip.%d", lc_m) tls_m_skip: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, tls_m_buf) viperlib.snprintf(tls_m_buf, 64, "tls.cont.%d", lc_m) tls_m_cont: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, tls_m_buf) if tls_m_skip is not None and tls_m_cont is not None: llvmlite.build_cond_br(func_builder, tls_m_ld, tls_m_skip, tls_m_cont) llvmlite.position_at_end(func_builder, tls_m_skip) match ret_ty: case llvmlite.LLVMType.Void(): llvmlite.build_ret_void(func_builder) case llvmlite.LLVMType.Int(_): tlm0: llvmlite.Value* = llvmlite.ConstInt(pool, ret_ty, 0, "0") if tlm0 is not None: llvmlite.build_ret(func_builder, tlm0) case llvmlite.LLVMType.Float(_): tlmf: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty, 0.0) if tlmf is not None: llvmlite.build_ret(func_builder, tlmf) case _: tlmn: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty, "null") if tlmn is not None: llvmlite.build_ret(func_builder, tlmn) llvmlite.position_at_end(func_builder, tls_m_cont) tlmo: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty_m, 1, "1") if tlmo is not None: llvmlite.build_store(func_builder, tlmo, tls_m_ref) # 进入函数作用域 self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_FUNCTION) # 为 self/cls 创建 alloca 并 store(与其他参数一致);@staticmethod 无 self,跳过。 # self 必须走 alloca:注册为 SSA 值会让 translate_name_value 多 load 一次, # 把 Ptr(struct_ty) 变成 struct 值 → 变参函数 ABI 不匹配崩溃。 if is_static_m == 0: self_alloca: llvmlite.Value* = llvmlite.build_alloca(func_builder, self_ptr_ty) if self_alloca is not None: self_var_name: str = "self" self_ssa_name: str = "%self" if is_class_m != 0 and args_node is not None: cags: ast.Arguments* = ast.Arguments*(args_node) if cags.args is not None and len(cags.args) > 0: cfirst: ast.Arg* = ast.Arg*(cags.args.get(0)) if cfirst is not None and cfirst.arg is not None: self_var_name = cfirst.arg self_ssa_name_buf: str = pool.alloc(32) if self_ssa_name_buf is not None: viperlib.snprintf(self_ssa_name_buf, 32, "%%%s", cfirst.arg) self_ssa_name = self_ssa_name_buf self.Gen.VarGen.define_var(trans.SymTab, self_var_name, self_alloca) # 设置 self/cls 的类型注解类名(属性访问 lookup_field 回退查找用) self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, self_var_name, class_name) self_val: llvmlite.Value* = llvmlite.SSAValue(pool, self_ptr_ty, self_ssa_name) llvmlite.build_store(func_builder, self_val, self_alloca) # 为其他参数创建 alloca 并 store(与普通函数一致; # @staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls 参数) if args_node is not None: ags2: ast.Arguments* = ast.Arguments*(args_node) if ags2.args is not None: alist2: list[ast.AST*]* = ags2.args an2: sizet = len(alist2) start_idx2: int = 0 if is_static_m == 0: start_idx2 = 1 for ai2 in range(start_idx2, an2): arg2: ast.Arg* = ast.Arg*(alist2.get(ai2)) if arg2 is not None and arg2.arg is not None: param_ty2: llvmlite.LLVMType* = i32_ty if arg2.annotation is not None: resolved2: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg2.annotation, imported_modules, from_imports, trans, 0) if resolved2 is None: # fail-fast:参数有注解但类型解析失败,不再静默保持 i32 self.Gen.TypeGenErr.fatal_error(arg2, f"方法 '{class_name}.{method_name}' 参数 '{arg2.arg}' 类型解析失败", "NameError") resolved2 = i32_ty # 不可达(fatal_error 已退出) if resolved2 is not None: # 与 add_param 保持一致:裸类形参 → Ptr(struct)(对象即指针) # CArray 形参 → 元素指针 ty*(数组衰减,与 add_param 一致) match resolved2: case llvmlite.LLVMType.Void(): # void 不是合法形参类型(用户 2026-10-01,见上方同款判据) self.Gen.TypeGenErr.fatal_error(arg2, f"方法 '{class_name}.{method_name}' 形参 '{arg2.arg}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError") return 0 case llvmlite.LLVMType.Struct(_, _, _): param_ty2 = llvmlite.Ptr(pool, resolved2) case llvmlite.LLVMType.Array(aelem_ty2, _): param_ty2 = llvmlite.Ptr(pool, aelem_ty2) case _: param_ty2 = resolved2 alloca: llvmlite.Value* = llvmlite.build_alloca(func_builder, param_ty2) if alloca is not None: self.Gen.VarGen.define_var(trans.SymTab, arg2.arg, alloca) # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) # 传 pool:泛型 Subscript 返回 mangled name(对齐 HandlesAnnAssign 修复) if arg2.annotation is not None: cls_nm_oc: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(arg2.annotation, imported_modules, pool, trans._from_imports) if cls_nm_oc is not None: self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, arg2.arg, cls_nm_oc) pname2: str = pool.alloc(32) if pname2 is not None: viperlib.snprintf(pname2, 32, "%%%s", arg2.arg) param_val: llvmlite.Value* = llvmlite.SSAValue(pool, param_ty2, pname2) llvmlite.build_store(func_builder, param_val, alloca) # OOP iter 协议:__next__ 的 stop-flag 参数初始化(store 0)并保存 # 指针到 trans,供 translate_raise 的 raise StopIteration 写 1。 # 参数名必须与上面 add_param 的 "%__stop_iter_flag__" 一致。 if string.strcmp(method_name, "__next__") == 0: i1_ty_sf: llvmlite.LLVMType* = llvmlite.Int1(pool) if i1_ty_sf is not None: i1_ptr_ty_sf: llvmlite.LLVMType* = llvmlite.Ptr(pool, i1_ty_sf) if i1_ptr_ty_sf is not None: flag_ref_sf: llvmlite.Value* = llvmlite.SSAValue(pool, i1_ptr_ty_sf, "%__stop_iter_flag__") if flag_ref_sf is not None: trans._stop_iter_flag_ptr = flag_ref_sf zero_i1_sf: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty_sf, 0, "0") if zero_i1_sf is not None: llvmlite.build_store(func_builder, zero_i1_sf, flag_ref_sf) # 保存模块级作用域状态 old_func: llvmlite.Function* = trans._cur_func old_builder: llvmlite.IRBuilder* = trans._cur_builder old_global_count: int = trans._global_name_count old_nonlocal_count: int = trans._nonlocal_name_count old_env_count: int = trans._closure_env_count old_stop_iter_flag: llvmlite.Value* = trans._stop_iter_flag_ptr trans._cur_func = func trans._cur_builder = func_builder GenApi.clear_scope_names(trans) # 预扫描方法体:为局部变量提前创建 alloca # 必须先预扫描 Global/Nonlocal 声明(对齐 FuncGenDef 模块级函数路径), # 否则 `global BootInfo` 未注册时 prescan 把 BootInfo 当局部创建 alloca, # 后续翻译 is_global_name 为真又写全局 → 局部 alloca 永不写入 → 读全 0 # (main.vp __init__ BootInfo memmap 全 0 根因)。 body: list[ast.AST*]* = fd.children if body is not None: bn: sizet = len(body) for bi in range(bn): stmt: ast.AST* = body.get(bi) if stmt is not None: self.Gen.StmtGenDecl.pre_scan_scope_decls(trans, stmt) for bi in range(bn): stmt: ast.AST* = body.get(bi) if stmt is not None: self.Gen.StmtGenDecl.pre_scan_allocas(trans, stmt) # 翻译方法体 if body is not None: bn2: sizet = len(body) for bi2 in range(bn2): stmt2: ast.AST* = body.get(bi2) if stmt2 is not None: self.Gen.StmtGen.translate_stmt(trans, stmt2) # 方法末尾收尾与模块级函数(FuncGenMixin.translate_function_def)同语义—— # 编译器不替代码发明返回值,三种合法收尾: # ① void 方法掉出末尾 → ret void(无值可发明,Python 语义) # ② 末句是控制流语句(match/if 全分支 return)→ merge 块结构性不可达 → # build_unreachable(GCC/Clang 对 fall-through 视为 UB 同语义) # ③ 无返回类型注解的方法 → 视为无返回值过程,ConstZero 兜底 # 有 -> 注解且末句普通语句掉出末尾 → fail-fast;不做 noreturn 函数名白名单 # (错误终止路径也必须在源码层面保证块收尾)。返回类型按实际 ret_ty 构造 # (硬编码 ret i32 0 会对 i64 返回方法报 llc 结果类型不匹配)。 last_is_return: int = 0 # 追加89:bn3 提前初始化,避免 body is None 时下方引用未定义变量 bn3: sizet = 0 if body is not None: bn3 = len(body) if bn3 > 0: last_stmt_m: ast.AST* = body.get(bn3 - 1) if last_stmt_m is not None and last_stmt_m.kind() == ast.ASTKind.Return: last_is_return = 1 if last_is_return == 0: if llvmlite.builder_cur_block_is_terminated(func_builder) == 0: last_is_ctrl: int = 0 if bn3 > 0: last_stmt3_m: ast.AST* = body.get(bn3 - 1) if last_stmt3_m is not None: k3m: int = last_stmt3_m.kind() if k3m == ast.ASTKind.If or k3m == ast.ASTKind.While or \ k3m == ast.ASTKind.For or k3m == ast.ASTKind.Try or \ k3m == ast.ASTKind.With or k3m == ast.ASTKind.Match: last_is_ctrl = 1 _is_void: int = 0 if ret_ty is not None: match ret_ty: case llvmlite.LLVMType.Void(): _is_void = 1 case _: pass # 追加91:返回注解层面的"无返回值"判据(与模块级函数 # FuncGenDef.vp「_is_void 双保险」同款、同语义,追加89 的 # 方法/函数同步约定)。void 方法无需显式 return,掉出末尾合法; # 报文里的"(返回类型 void)"来自 TypePrint 的 `case _` 兜底亦可 # 打印 void,不能当作已识别依据,故补注解判据。 # ① t.CVoiX / ② 裸名 CVoid:经既有判据 # TypeGenResolve._is_cvoid_marker(TypeGenResolve.vp:1484) # ③ -> None(CONST_NONE):解析即 Void(TypeGenResolve.vp:1996-1999) if _is_void == 0 and fd.returns is not None: if self.Gen.TypeGenResolve._is_cvoid_marker(fd.returns, imported_modules) != 0: _is_void = 1 elif fd.returns.kind() == ast.ASTKind.Constant: ret_none_cn_m: ast.Constant* = (ast.Constant*)(fd.returns) if ret_none_cn_m.const_kind == ast.CONST_NONE: _is_void = 1 if _is_void != 0: llvmlite.build_ret_void(func_builder) elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: # 非 void 方法末句是控制流且 merge 块**结构性**不可达(全分支 return,无 br # 到 merge)→ LLVM 语义 unreachable。merge 可达时须正常收尾(下方 # ConstZero / fail-fast):可达块的 unreachable 是 UB,llc 不生成指令 ⇒ # 执行掉进布局紧随其后的块(同 FuncGenDef 模块级函数口径;实测反例见该处 # 注释里的 _TypePrintDepth 用 snprintf 返回值当 tag 走进 switch 跳转表)。 llvmlite.build_unreachable(func_builder) elif fd.returns is None: # 无返回类型注解 → 无返回值过程方法,默认零值返回 if ret_ty is not None: _m_zero_val: llvmlite.Value* = llvmlite.ConstZero(pool, ret_ty) if _m_zero_val is not None: llvmlite.build_ret(func_builder, _m_zero_val) else: self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") else: self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") else: # fail-fast:有 -> 注解但流程真实掉出末尾(traceback 风格) if ret_ty is not None: rt_name_m: str = pool.alloc(64) if rt_name_m is not None: llvmlite.TypePrint(rt_name_m, 64, ret_ty, pool) if rt_name_m[0] == '\0': rt_name_m = "?" err_fn_m: str = pool.alloc(256) if err_fn_m is not None: viperlib.snprintf(err_fn_m, 256, "方法 '%s' 流程掉出末尾但未显式 return(返回类型 %s),请补显式 return(如 return 0 / return null)", method_name, rt_name_m) self.Gen.TypeGenErr.fatal_error(fd, err_fn_m, "TypeError") self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") else: self.Gen.TypeGenErr.fatal_error(fd, "方法流程掉出末尾但未显式 return", "TypeError") # 恢复模块级作用域 self.Gen.VarGen.exit_scope(trans.SymTab) trans._cur_func = old_func trans._cur_builder = old_builder trans._global_name_count = old_global_count trans._nonlocal_name_count = old_nonlocal_count trans._closure_env_count = old_env_count trans._stop_iter_flag_ptr = old_stop_iter_flag if dbg_pushed != 0: DebugInfoGen.PopFunction(func_builder) return 0 # ============================================================ # _generate_before_init — 生成 __before_init__ 函数 # # 生成: define void @SHA1.ClassName.__before_init__(Ptr(StructTy) %self) # # 执行: # 1. store zeroinitializer 到 %self(零值填充) # 2. 逐字段 store 默认值(如有) # 3. ret void # ============================================================ def _generate_before_init(self, trans: HT.Translator*, struct_ty: llvmlite.LLVMType*, class_name: str) -> int: """生成 __before_init__ 函数,返回 0""" if trans is None or struct_ty is None or class_name is None: return 0 pool: memhub.MemBuddy* = trans.Pool mod: llvmlite.LLVMModule* = trans.Module funcs_ptr: GenTypes.FuncEntry* = trans._funcs func_count: int = trans._func_count self_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, struct_ty) void_ty: llvmlite.LLVMType* = llvmlite.Void(pool) # 构建函数名: ClassName.__before_init__ full_name_buf: str = pool.alloc(128) if full_name_buf is None: return 0 viperlib.snprintf(full_name_buf, 128, "%s.__before_init__", class_name) full_name: str = full_name_buf mangled_name: str = self.Gen.FuncGenBase._mangle_name(trans, full_name) # 创建函数 func: llvmlite.Function* = llvmlite.create_function(pool, mod, mangled_name, void_ty) if func is None: return 0 # 注册到函数表 max_funcs: int = 1024 rc_add: int = self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, full_name, func, max_funcs, None, 0, 0, pool) if rc_add == 0: trans._func_count = func_count + 1 # 添加 self 参数 llvmlite.add_param(pool, func, self_ptr_ty, "%self") # 参数添加完成,补全全局函数表的 Spec rc_ut: int = self.Gen.CallGenLeafKit.update_global_func_spec(full_name, func) # 创建 entry 块 + builder entry_blk: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, "entry") if entry_blk is None: return 0 func_builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, func) if func_builder is None: return 0 llvmlite.position_at_end(func_builder, entry_blk) # 注册 self 为 SSA 值 self_val: llvmlite.Value* = llvmlite.SSAValue(pool, self_ptr_ty, "%self") # 1. 零值填充: store zeroinitializer, Ptr(struct_ty)* %self # 空 struct({})在 LLVM 中不允许 zeroinitializer(invalid type for null constant), # 无字段类(接口/标记类,如多继承的 Vec2Extra)跳过零值填充; # @t.CVTable 类必有 vtable 指针字段(非空),不受影响。 struct_fcount_zi: int = llvmlite.get_struct_fcount(struct_ty) if struct_fcount_zi > 0: zero: llvmlite.Value* = llvmlite.ConstZero(pool, struct_ty) if zero is not None: llvmlite.build_store(func_builder, zero, self_val) # 1.5 如果有虚表,store vtable 全局地址到 __vtable__ 字段(索引 0) # 用 find_struct_by_type 定位 entry,规避跨模块同名 find_struct 找错 bi_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(struct_ty) bi_has_vt: int = 0 if bi_entry is not None: bi_has_vt = bi_entry.HasVTable if bi_has_vt == 1: vt_method_count: int = 0 if bi_entry is not None: vt_method_count = bi_entry.VTableMethodCount if vt_method_count > 0: # 构造 vtable 类型 { i8*, i8*, ..., i8* } vt_i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool) vt_i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, vt_i8_ty) vt_first_node: llvmlite.ParamNode* = None vt_prev_node: llvmlite.ParamNode* = None for vti in range(vt_method_count): vtnode: llvmlite.ParamNode* = llvmlite.new_param_node(pool, vt_i8_ptr_ty) if vtnode is None: continue if vt_first_node is None: vt_first_node = vtnode if vt_prev_node is not None: llvmlite.paramnode_set_next(vt_prev_node, vtnode) vt_prev_node = vtnode vt_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, vt_first_node, vt_method_count, None) vt_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, vt_ty) # 构造 vtable 全局变量名 vt_name_buf: str = pool.alloc(128) if vt_name_buf is not None: viperlib.snprintf(vt_name_buf, 128, "%s.vtable", class_name) vt_full_name: str = vt_name_buf vt_mangled: str = self.Gen.FuncGenBase._mangle_name(trans, vt_full_name) # GEP 到 __vtable__ 字段(索引 0) vt_slot: llvmlite.Value* = llvmlite.build_gep_struct(func_builder, struct_ty, vt_i8_ptr_ty, self_val, 0) if vt_slot is not None: # 创建全局变量引用 Value vt_ref: llvmlite.Value* = llvmlite.new_value(pool) if vt_ref is not None: llvmlite.value_set_ty(vt_ref, vt_ptr_ty) llvmlite.value_set_isconst(vt_ref, 1) # Name 格式: @"mangled" 或 @mangled vt_ref_name: str = pool.alloc(256) if vt_ref_name is not None: vt_ref_name[0] = '\0' if self._vtable_name_needs_quote(vt_mangled) != 0: viperlib.snprintf(vt_ref_name, 256, "@\"%s\"", vt_mangled) else: viperlib.snprintf(vt_ref_name, 256, "@%s", vt_mangled) llvmlite.value_set_name(vt_ref, vt_ref_name) # bitcast 到 i8* vt_as_i8: llvmlite.Value* = llvmlite.build_bitcast(func_builder, vt_ref, vt_i8_ptr_ty) if vt_as_i8 is not None: llvmlite.build_store(func_builder, vt_as_i8, vt_slot) # 2. 逐字段 store 默认值(用 bi_entry 直接访问,规避跨模块同名 find_struct 找错) if bi_entry is not None: for fi in range(bi_entry.FieldCount): fe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(bi_entry, fi) if fe is None or fe.DefaultVal is None: continue # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store # (与局部 AnnAssign 数组初始化一致;translate_value 会把列表字面量 # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 # 单参 CArray 字段(如 t.CArray[str] = [...])经类体字段收集 # 推断为静态数组,此处保证 __before_init__ 填充真实字符串指针。 if fe.Ty is not None and self.Gen.ExprGenBase.is_array_type(fe.Ty) != 0 \ and fe.DefaultVal.kind() == ast.ASTKind.List: field_ptr_arr: llvmlite.Value* = llvmlite.build_gep_struct(func_builder, struct_ty, fe.Ty, self_val, fe.Index) if field_ptr_arr is not None: zero_arr_f: llvmlite.Value* = llvmlite.ConstZero(pool, fe.Ty) if zero_arr_f is not None: llvmlite.build_store(func_builder, zero_arr_f, field_ptr_arr) # Mixin 静态绑定:self._xxx 只沿本类查找,跨 Mixin 方法 # (AssignGenMixin._init_global_array_from_list)会生成不存在 # 符号 → 必须走 HandlesAnnAssign 模块级委托(延迟 import Gen)。 # owner_ctx 只服务空元素 fail-fast 报文(类名 + 字段名 + 下标)。 arr_ctx: str = pool.alloc(192) if arr_ctx is not None: fname_dbg_v: str = fe.Name if fname_dbg_v is None: fname_dbg_v = "?" viperlib.snprintf(arr_ctx, 192, "类 %s 字段 %s:", class_name, fname_dbg_v) self.Gen.AssignGen._init_global_array_from_list(func_builder, pool, mod, field_ptr_arr, fe.DefaultVal, trans, arr_ctx) continue # 翻译默认值表达式 default_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(func_builder, pool, mod, fe.DefaultVal, None, 0, trans) if default_val is None: continue # GEP 到字段 field_ptr: llvmlite.Value* = llvmlite.build_gep_struct(func_builder, struct_ty, fe.Ty, self_val, fe.Index) if field_ptr is None: continue # 类型转换并 store default_val = self.Gen.ExprGenBase.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) llvmlite.build_store(func_builder, default_val, field_ptr) # 3. ret void llvmlite.build_ret_void(func_builder) return 0