fix(core): _translate_method_call 沿 MRO 祖先链查返回类型,修复 Module.append
mod.append(Module 继承 AST)中 append 定义在 ast/base.vp(sha1=71b2),
found_func 未命中时 fallback 按 class_name="Module" 查 text.ll/vpi 找不到
(函数名是 {71b2}.AST.append)→ fail-fast。修复:
1. 新增 ret_anc_name/ret_anc_sha1(方法实际定义类),默认 class_name,
MRO fallback 命中祖先类(AST)时更新;
2. text.ll/vpi 均沿 MRO 祖先链用祖先类名 + 祖先类 sha1 重试查询;
3. 调用名也用方法定义类构造({AST_sha1}.AST.append),避免链接 undefined。
This commit is contained in:
1 parent
0a0e6d3bab
commit
f2b33f5e9b
1 file changed
+66
-25
@@ -3729,34 +3729,14 @@ class CallGenMixin:
|
||||
break
|
||||
mi += 1
|
||||
|
||||
# 确定调用名
|
||||
# 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用
|
||||
# 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append,
|
||||
# 函数名为 {AST_sha1}.AST.append)
|
||||
call_name: str = lookup_name
|
||||
if found_func is not None:
|
||||
found_name: str = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
else:
|
||||
# found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名
|
||||
# 沿继承链查找第一个有 SHA1 的类
|
||||
cls_sha1_mc: str = None
|
||||
if mc_entry is not None:
|
||||
cls_sha1_mc = mc_entry.ModuleSha1
|
||||
else:
|
||||
cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name)
|
||||
if cls_sha1_mc is None:
|
||||
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||||
mj: int = 1
|
||||
while mro_p is not None and mro_p[mj] != 0 and cls_sha1_mc is None:
|
||||
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
|
||||
if anc_p is not None:
|
||||
cls_sha1_mc = HandlesStruct.get_struct_sha1(anc_p)
|
||||
mj += 1
|
||||
if cls_sha1_mc is not None:
|
||||
mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2
|
||||
mangled_mc: str = pool.alloc(mangled_len_mc)
|
||||
if mangled_mc is not None:
|
||||
viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name)
|
||||
call_name = mangled_mc
|
||||
|
||||
# 确定返回类型
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
@@ -3771,6 +3751,24 @@ class CallGenMixin:
|
||||
if sp_ty2 is not None:
|
||||
call_ret_ty = sp_ty2
|
||||
else:
|
||||
# 方法实际定义类(跨模块调用名/返回类型来源;Module.append 定义在 AST)
|
||||
# 默认 class_name 自身,MRO fallback 命中祖先类时更新
|
||||
ret_anc_name: str = class_name
|
||||
ret_anc_sha1: str = None
|
||||
if mc_entry is not None:
|
||||
ret_anc_sha1 = mc_entry.ModuleSha1
|
||||
else:
|
||||
ret_anc_sha1 = HandlesStruct.get_struct_sha1(class_name)
|
||||
if ret_anc_sha1 is None:
|
||||
# 沿 MRO 找第一个有 SHA1 的类
|
||||
mro_s0: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||||
mi_s0: int = 1
|
||||
while mro_s0 is not None and mro_s0[mi_s0] != 0 and ret_anc_sha1 is None:
|
||||
anc_s0: str = (str | t.CPtr)(t.CVoid(mro_s0[mi_s0], t.CPtr))
|
||||
if anc_s0 is not None:
|
||||
ret_anc_sha1 = HandlesStruct.get_struct_sha1(anc_s0)
|
||||
mi_s0 += 1
|
||||
|
||||
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
|
||||
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
|
||||
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
|
||||
@@ -3827,18 +3825,61 @@ class CallGenMixin:
|
||||
# 尝试从 text.ll 查找实际返回类型
|
||||
# 避免指针返回值被默认 i32 导致 inttoptr 截断
|
||||
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||
pool, cls_sha1_mc, class_name, method_name)
|
||||
pool, ret_anc_sha1, ret_anc_name, method_name)
|
||||
# 沿 MRO 祖先链重试:方法可能定义在基类(如 Module.append →
|
||||
# AST.append,函数名 {ast_sha1}.AST.append,且基类在另一模块文件
|
||||
# 如 ast/stmts.vp 的 Module vs ast/base.vp 的 AST),按调用类名
|
||||
# 及其 sha1 查不到,需用每个祖先类的类名 + 祖先类所属模块 sha1
|
||||
# 查 text.ll(NewAstTest mod.append 根因)
|
||||
if looked_up_ty is None:
|
||||
mro_t2: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||||
mi_t2: int = 1
|
||||
while mro_t2 is not None and mro_t2[mi_t2] != 0 and looked_up_ty is None:
|
||||
anc_t2: str = (str | t.CPtr)(t.CVoid(mro_t2[mi_t2], t.CPtr))
|
||||
if anc_t2 is not None and string.strcmp(anc_t2, class_name) != 0:
|
||||
anc_sha1_t2: str = HandlesStruct.get_struct_sha1(anc_t2)
|
||||
looked_up_ty = self._LookupMethodRetTyFromTextLL(
|
||||
pool, anc_sha1_t2, anc_t2, method_name)
|
||||
if looked_up_ty is not None:
|
||||
ret_anc_name = anc_t2
|
||||
ret_anc_sha1 = anc_sha1_t2
|
||||
mi_t2 += 1
|
||||
if looked_up_ty is not None:
|
||||
call_ret_ty = looked_up_ty
|
||||
else:
|
||||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||||
pool, cls_sha1_mc, class_name, method_name)
|
||||
pool, ret_anc_sha1, ret_anc_name, method_name)
|
||||
# vpi 同样沿 MRO 祖先链重试(基类方法注解,用祖先类自身 sha1)
|
||||
if vpi_ret_ty is None:
|
||||
mro_v2: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||||
mi_v2: int = 1
|
||||
while mro_v2 is not None and mro_v2[mi_v2] != 0 and vpi_ret_ty is None:
|
||||
anc_v2: str = (str | t.CPtr)(t.CVoid(mro_v2[mi_v2], t.CPtr))
|
||||
if anc_v2 is not None and string.strcmp(anc_v2, class_name) != 0:
|
||||
anc_sha1_v2: str = HandlesStruct.get_struct_sha1(anc_v2)
|
||||
vpi_ret_ty = self._lookup_method_ret_ty_via_vpi(
|
||||
pool, anc_sha1_v2, anc_v2, method_name)
|
||||
if vpi_ret_ty is not None:
|
||||
ret_anc_name = anc_v2
|
||||
ret_anc_sha1 = anc_sha1_v2
|
||||
mi_v2 += 1
|
||||
if vpi_ret_ty is not None:
|
||||
call_ret_ty = vpi_ret_ty
|
||||
else:
|
||||
call_ret_ty = self._fail_method_ret_ty(method_name, cl)
|
||||
|
||||
# found_func 未命中但返回类型已解析:用方法定义类构造跨模块调用名
|
||||
# (Module.append → {AST_sha1}.AST.append,避免链接 undefined reference)
|
||||
if ret_anc_name is not None and ret_anc_sha1 is not None:
|
||||
ml_anc: t.CSizeT = string.strlen(ret_anc_sha1) + string.strlen(ret_anc_name) \
|
||||
+ string.strlen(method_name) + 3
|
||||
mangled_anc: str = pool.alloc(ml_anc)
|
||||
if mangled_anc is not None:
|
||||
viperlib.snprintf(mangled_anc, ml_anc, "%s.%s.%s",
|
||||
ret_anc_sha1, ret_anc_name, method_name)
|
||||
call_name = mangled_anc
|
||||
|
||||
# 翻译调用参数
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
can: t.CSizeT = 0
|
||||
|
||||
Reference in new issue
Block a user