diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index 77ebd36..781b974 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -807,72 +807,16 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): break mi += 1 - # 兄弟 Mixin 兜底(与 TPC HandlesExprCall 一致):方法不在本类 MRO 链时遍历已注册 struct 表找定义类方法,this 由下方 _adjust_this_for_inherited_method 按组合布局前移 sizeof(定义类)。仅对普通类名兜底——泛型特化类名(list[X]/dict[K,V])必须过滤,否则普通方法在 found_func 未命中时会误绑到 list 特化函数,this 前移错位导致运行期崩溃 - # 跨模块兄弟 Mixin 兜底命中(定义类在另一文件、本地 IR 无 define)需经候选类模块 sha1 查 text.ll 返回类型。 - mixin_hit: int = 0 - mixin_ret_ty: llvmlite.LLVMType* = None - mixin_anc_name: str = None - mixin_anc_sha1: str = None - if found_func is None: - # 兄弟 Mixin 兜底仅对"接收者类属于当前模块"的场景适用:self 调用兄弟 - # Mixin 方法时接收者是本类(与候选兄弟类同模块)。接收者类是跨模块类 - # (如 self.Gen.TypeGenResolve 的 TypeGenResolve,定义在另一模块)时, - # 其方法必须经该类自身模块(text.ll/vpi)解析——若本模块恰好定义了 - # 同名方法 {Cand}.{method},本兜底会误绑定:最坏情况绑定到正在编译的 - # 函数自身 → ImportsGenMixin.set_current_file 内 self.Gen.TypeGenResolve. - # set_current_file(...) 被编译成自调用 → 无限递归 stack-overflow - # (二代编 FuncTest 崩溃根因)。接收者类模块无法确定时保持原行为。 - sib_recv_local: int = 1 - if trans is not None and trans.ModuleSha1 is not None: - sib_recv_sha1: str = None - if mc_entry is not None and mc_entry.ModuleSha1 is not None: - sib_recv_sha1 = mc_entry.ModuleSha1 - else: - sib_recv_sha1 = self.Gen.StructGen.get_struct_sha1(class_name) - if sib_recv_sha1 is not None: - if string.strcmp(sib_recv_sha1, trans.ModuleSha1) != 0: - sib_recv_local = 0 - if sib_recv_local != 0: - sc_i: int = 0 - sc_n: int = self.Gen.StructGen.get_struct_count() - # 【守卫】这是按序号(0..StructCount-1)的全量遍历,非按名查找, - # 不走 StructNameIdx 索引:兄弟 Mixin 候选是"名字不等 class_name - # 且本模块存在同名方法"的任意条目,需逐条枚举探测,不可改为按名 - # find_struct(会退化为单条精确查找、漏掉全部兄弟候选)。 - while sc_i < sc_n and found_func is None and mixin_hit == 0: - cand_entry: GenTypes.StructEntry* = self.Gen.StructGen._get_struct_entry(sc_i) - if cand_entry is not None and cand_entry.Name is not None: - cand_name: str = cand_entry.Name - if string.strcmp(cand_name, class_name) != 0: - # 泛型特化类名含 '['(list[...]/dict[...]):跳过, - # 不是兄弟 Mixin 候选(见上方注释) - if string.strchr(cand_name, '[') is not None: - sc_i += 1 - continue - cand_lookup: str = pool.alloc(128) - if cand_lookup is not None: - viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name) - cand_func: llvmlite.Function* = self.find_func_in_module(mod, cand_lookup) - if cand_func is not None: - found_func = cand_func - mc_anc = cand_name - else: - # 跨模块 Mixin(定义类在另一文件,本地 IR 无 define): - # 用候选类模块 sha1 查 text.ll 返回类型,命中即锁定定义类, - # 后续 ret_anc_* 据此构造 {sha1}.{class}.{method} 调用名。 - # 否则 ret_anc_sha1 停在调用类自身 sha1,_dep_text_ll_exists - # 查自身 text.ll(Phase A 翻译中未生成)→ 永久 pending 死锁 - # (ClassGenVTable._mangle_name → 7871cc1aabebfc33 根因)。 - if mixin_hit == 0: - cand_sha1_cx: str = self.Gen.StructGen.get_struct_sha1(cand_name) - if cand_sha1_cx is not None and self._dep_text_ll_exists(pool, cand_sha1_cx) != 0: - cand_ret_cx: llvmlite.LLVMType* = self._LookupMethodRetTyFromTextLL(pool, cand_sha1_cx, cand_name, method_name) - if cand_ret_cx is not None: - mixin_hit = 1 - mixin_ret_ty = cand_ret_cx - mixin_anc_name = cand_name - mixin_anc_sha1 = cand_sha1_cx - sc_i += 1 + # 【已删除:兄弟 Mixin 兜底(2026-10-01,用户决定"不兜底、fail-fast")】 + # 原实现:found_func 未命中时遍历全部已注册 struct,取"本模块存在同名方法"的 + # 第一个候选类并绑定(this 再按组合布局前移)。该扫描的候选判据里**没有** + # "接收类自身是否声明了该方法"这一条(TPC 侧 HandlesExprCall.py:3877-3914 有), + # 因而会把同类的方法误绑到无关类:includes/w32/fileio.vp 的 FileW.__init__ + # 调用 self.seek(...) 时(FileW.seek 尚未发射)被绑成 File.seek——旧 IR 靠 + # `bitcast %"…FileW"* to %"…File"*` 静默掩盖,指针规则收紧后以 CastError 报出。 + # 根因已由"先声明后定义"消除(ClassGenVTable._translate_oop_methods 在翻译 + # 方法体前对本类全部方法跑 sig_only=1 建前向声明):方法查找不再依赖类体 + # 书写顺序,未命中即为真未定义,落下方 fail-fast,不再猜候选类。 # 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用 # 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append, @@ -938,13 +882,6 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): ret_anc_sha1 = mc_entry.ModuleSha1 else: ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name) - # 跨模块兄弟 Mixin 兜底命中:定义类锁定为候选类(如 FuncGenBase), - # 返回类型与调用名前缀以其模块 sha1 为准,避免 ret_anc_sha1 停在 - # 调用类自身 sha1 → 查自身 text.ll(未生成)→ 永久 pending 死锁 - if mixin_hit != 0: - ret_anc_name = mixin_anc_name - ret_anc_sha1 = mixin_anc_sha1 - call_ret_ty = mixin_ret_ty if ret_anc_sha1 is None: # 沿 MRO 找第一个有 SHA1 的类 mro_s0: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name) @@ -1022,9 +959,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): call_ret_ty = frt_g found_func = spec_found_g gen_done = 1 - # mixin_hit:跨模块 Mixin 兜底已锁定定义类与返回类型,跳过 - # text.ll/vpi/pending 重查段,直接构造 {sha1}.{class}.{method} 调用名 - if gen_done == 0 and mixin_hit == 0: + if gen_done == 0: # ============================================================ # is_local_mod 豁免(对齐 CallGenMixin L1336-1343 的 is_local_mod): # 方法定义在当前正在翻译的模块(ret_anc_sha1 == trans.ModuleSha1) diff --git a/App/lib/core/Gen/Class/ClassGenVTable.vp b/App/lib/core/Gen/Class/ClassGenVTable.vp index 17cfa51..dfb43d2 100644 --- a/App/lib/core/Gen/Class/ClassGenVTable.vp +++ b/App/lib/core/Gen/Class/ClassGenVTable.vp @@ -527,6 +527,23 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase): 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: @@ -561,8 +578,19 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase): def _translate_method(self, trans: HT.Translator*, fd: ast.FunctionDef*, struct_ty: llvmlite.LLVMType*, - class_name: str) -> int: - """翻译单个方法,返回 0""" + 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 @@ -649,104 +677,131 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase): 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 函数 - func: llvmlite.Function* = llvmlite.create_function(pool, mod, mangled_name, ret_ty) - if func is None: - return 0 + # 创建/复用 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 - # 提取默认参数信息(普通方法 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) + if sig_only != 0: + # 前向声明模式:已声明过直接返回;否则下方登记完参数/函数表后返回。 + if decl_reuse != 0: + return 0 + else: + # 发射函数体前必须把 IsDeclared 清零,否则打印端按 IsDeclared 输出 + # declare、函数体整体丢失(对齐 FuncGenDef.vp:544-545)。 + func.IsDeclared = 0 - # 注册到函数表(用 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 + 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) - # 添加 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) + # 注册到函数表(用 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 - # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) - args_node: ast.Arguments* = fd.args - 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.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) + # 添加 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) - # 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__") + # 添加其他参数(支持类型注解;@staticmethod 从索引 0 开始,其余跳过索引 0 的 self/cls) + args_node: ast.Arguments* = fd.args + 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.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: