fix(tpv): 兄弟 Mixin 兜底支持跨模块——修复自身 text.ll 永久 pending 死锁 - ClassGenVTable._mangle_name 定义在 FuncGenBase(跨模块 Mixin,调用类不继承它),兄弟 Mixin 兜底只在本地 IR 找 define 未命中 → ret_anc_sha1 停在调用类自身 sha1 → _dep_text_ll_exists(自身) 恒 0(Phase A 翻译中自身 text.ll 未生成)→ _deps_pending=1 死锁,Phase A 永不收敛 - 修复:兜底遍历已注册 struct 时增加跨模块查找(get_struct_sha1 + _LookupMethodRetTyFromTextLL 查该模块 text.ll),命中即锁定定义类(ret_anc_sha1/ret_anc_name/返回类型),跳过 text.ll/vpi/pending 重查段,按 {定义类sha1}.{定义类}.{方法} 构造调用名

This commit is contained in:
TermiNexus committed 2026-08-23 14:50:48 +08:00
1 parent 27f2a53c15
commit 146b9a9652
1 file changed
+36 -2
+36 -2
View File
@@ -640,10 +640,17 @@ class CallGenCall(CallGenBase.CallGenBase):
# 普通方法调用在 found_func 未命中时会误绑定到 list 特化函数,
# this 按 list 布局前移 sizeof(list) → 运行期读 -1 崩溃
# (Config.vp Load_project_config root.__getitem__ 根因)。
# 跨模块兄弟 Mixin 兜底命中记录:方法定义类在另一文件(如
# FuncGenBase._mangle_name——调用类 ClassGenVTable 不继承它),
# 本地 IR 无 define,需经候选类模块 sha1 查 text.ll 返回类型。
mixin_hit: int = 0
mixin_ret_ty: llvmlite.LLVMType | t.CPtr = None
mixin_anc_name: str = None
mixin_anc_sha1: str = None
if found_func is None:
sc_i: int = 0
sc_n: int = self.Gen.StructGen.get_struct_count()
while sc_i < sc_n and found_func is None:
while sc_i < sc_n and found_func is None and mixin_hit == 0:
cand_entry: GenTypes.StructEntry | t.CPtr = 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
@@ -661,6 +668,24 @@ class CallGenCall(CallGenBase.CallGenBase):
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 | t.CPtr = 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
# 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用
@@ -725,6 +750,13 @@ 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: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
@@ -810,7 +842,9 @@ class CallGenCall(CallGenBase.CallGenBase):
call_ret_ty = frt_g
found_func = spec_found_g
gen_done = 1
if gen_done == 0:
# mixin_hit:跨模块 Mixin 兜底已锁定定义类与返回类型,跳过
# text.ll/vpi/pending 重查段,直接构造 {sha1}.{class}.{method} 调用名
if gen_done == 0 and mixin_hit == 0:
# 尝试从 text.ll 查找实际返回类型
# 避免指针返回值被默认 i32 导致 inttoptr 截断
looked_up_ty = self._LookupMethodRetTyFromTextLL(