fix(compiler): 方法返回类型三级来源重构(移除 _infer_method_ret_ty 按名推断)

方法返回类型改为:当前模块函数 → text.ll define → vpi stub 返回注解缓存,全部未命中 fail-fast 终止(无白名单、无 hook 编译器)。

1. VpiReader 文本提取缓存 + 按需加载 + 动态扩容 + 无注解默认 i32
2. 类名解析修复(继承括号不入类名、模块级函数清空类名)
3. SetTempDir 提前到 Phase1(json 在 Phase1 翻译,Phase2 太晚)
4. 内置方法 __before_init__/__init__/__new__ 固定返回类型
5. 泛型归一化匹配 + _subst_template_arg 模板参数替换
6. 调试插桩 VPI_DEBUG_ENABLE 开关(默认关闭)
This commit is contained in:
TermiNexus committed 2026-08-08 09:43:15 +08:00
1 parent a9ebb20790
commit ea8bb0b3a4
3 files changed
+289 -13

No files matched your search

+180 -11
View File
@@ -2,6 +2,7 @@ import t, c
from stdint import *
import ast
import string
import stdio
import stdlib
import sys
import memhub
@@ -29,6 +30,13 @@ import lib.core.Handles.HandlesTranslator as HT
# 按 sha1.类名.方法名 查表并用 _resolve_vpi_ret_annot_str 纯字符串
# 解析为 LLVMType,返回类型始终来自方法定义处,无白名单/无硬编码。
# ============================================================
# ============================================================
# VPI_DEBUG_ENABLE - vpi 返回注解缓存调试输出开关
# 0=关闭(默认),1=开启(打印全部 [VPI-*] 调试插桩)。
# 排查"方法返回类型无法精确获取"问题时临时改为 1,解决后改回 0。
# ============================================================
VPI_DEBUG_ENABLE: t.CDefine = 0
VPI_RET_MAX: t.CDefine = 4096
VPI_KEY_LEN: t.CDefine = 224
VPI_RET_LEN: t.CDefine = 224
@@ -50,6 +58,8 @@ _g_vpi_ret_cap: int = 0
# ============================================================
def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
"""从 vpi_buf 文本提取方法返回注解字符串(stdlib 持久)"""
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CACHE] in sha1=%s\n", src_sha1)
global _g_vpi_ret_keys, _g_vpi_ret_strs, _g_vpi_ret_count, _g_vpi_ret_cap
if vpi_buf is None or src_sha1 is None:
return 0
@@ -81,7 +91,9 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
if line_len >= 6 and string.strncmp(vpi_buf + i, "class ", 6) == 0:
cstart: t.CSizeT = i + 6
cend: t.CSizeT = cstart
while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ':
# 类名提取:到 ':' / ' ' / '(' 前停止(继承基类括号不入类名,
# 如 "class MemBuddy(MemManager):" → "MemBuddy",与调用方短名一致)
while cend < le and vpi_buf[cend] != ':' and vpi_buf[cend] != ' ' and vpi_buf[cend] != '(':
cend += 1
if cend > cstart:
if cur_cls is not None:
@@ -92,6 +104,11 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
cur_cls[cend - cstart] = '\0'
# def name(...) -> Ret:
elif line_len >= 4 and string.strncmp(vpi_buf + i, "def ", 4) == 0:
# 模块级函数(行首无缩进):清空类名上下文,避免类结束后残留
# (如 json 的 null/int_val 等模块级函数被误存为 JsonValue.null)
if i == ls and cur_cls is not None:
stdlib.free(cur_cls)
cur_cls = None
dstart: t.CSizeT = i + 4
dend: t.CSizeT = dstart
while dend < le and vpi_buf[dend] != '(':
@@ -105,18 +122,30 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
arrow_pos = rpos
break
rpos += 1
if arrow_pos < le and dend > dstart:
if dend > dstart:
# 返回类型:有 "-> Ret" 提取注解;无注解的非特殊方法默认 "i32"
# (与 HandlesType.infer_return_type 无 return 语句时的默认行为一致,
# 如 json._append_child / __setitem__ 无注解实际编译为 i32)。
ret_src: str = None
rtype_len: t.CSizeT = 0
if arrow_pos < le:
# 返回类型 = arrow_pos+2 跳过空格 到 ':' 前
rstart: t.CSizeT = arrow_pos + 2
while rstart < le and vpi_buf[rstart] == ' ':
rstart += 1
rend: t.CSizeT = rstart
while rend < le and vpi_buf[rend] != ':':
rend += 1
if rend > rstart:
rstart2: t.CSizeT = arrow_pos + 2
while rstart2 < le and vpi_buf[rstart2] == ' ':
rstart2 += 1
rend2: t.CSizeT = rstart2
while rend2 < le and vpi_buf[rend2] != ':':
rend2 += 1
if rend2 > rstart2:
rtype_len = rend2 - rstart2
ret_src = vpi_buf + rstart2
else:
# 无返回注解:默认 i32(特殊方法除外,见下方过滤)
rtype_len = 3
ret_src = "i32"
if ret_src is not None:
# 构造 key 和 ret_str,存入缓存
mname_len: t.CSizeT = dend - dstart
rtype_len: t.CSizeT = rend - rstart
cls_len2: t.CSizeT = 0
if cur_cls is not None:
cls_len2 = string.strlen(cur_cls)
@@ -127,6 +156,18 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
if mname_buf is not None:
string.strncpy(mname_buf, vpi_buf + dstart, mname_len)
mname_buf[mname_len] = '\0'
# 无注解的特殊方法(构造/析构)跳过:它们有专门调用路径
skip_def: int = 0
if arrow_pos >= le:
if string.strcmp(mname_buf, "__init__") == 0 or \
string.strcmp(mname_buf, "__new__") == 0 or \
string.strcmp(mname_buf, "__before_init__") == 0 or \
string.strcmp(mname_buf, "__after_init__") == 0:
skip_def = 1
else:
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-DEF] sha1=%s cls=%s m=%s\n", src_sha1, cur_cls, mname_buf)
if skip_def == 0:
key_buf: bytes = stdlib.malloc(key_len + 1)
if key_buf is not None:
if cur_cls is not None:
@@ -147,7 +188,7 @@ def _cache_vpi_return_annots_text(vpi_buf: bytes, src_sha1: str) -> int:
if grow_ok != 0:
string.strcpy(_g_vpi_ret_keys + _g_vpi_ret_count * VPI_KEY_LEN, key_buf)
string.strncpy(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN,
vpi_buf + rstart, rtype_len)
ret_src, rtype_len)
(_g_vpi_ret_strs + _g_vpi_ret_count * VPI_RET_LEN)[rtype_len] = '\0'
_g_vpi_ret_count += 1
stdlib.free(key_buf)
@@ -201,6 +242,8 @@ def _grow_vpi_ret_cache() -> int:
# ============================================================
def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
"""按需加载模块 vpi stub 的返回注解缓存,返回 1=已就绪 / 0=失败"""
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-ENSURE] in sha1=%s temp=%s\n", src_sha1, temp_dir)
if src_sha1 is None or temp_dir is None:
return 0
sha1_len: t.CSizeT = string.strlen(src_sha1)
@@ -212,6 +255,8 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
for pre_i in range(_g_vpi_ret_count):
pre_key: bytes = _g_vpi_ret_keys + pre_i * VPI_KEY_LEN
if string.strncmp(pre_key, src_sha1, sha1_len) == 0 and pre_key[sha1_len] == '.':
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-ENSURE] prefix-hit key=%s count=%d\n", pre_key, _g_vpi_ret_count)
return 1
# 构造路径 {temp_dir}/{sha1[0:2]}/{sha1}.vpi(逐字符拼接,避免 %c 格式化问题)
td_len: t.CSizeT = string.strlen(temp_dir)
@@ -226,8 +271,12 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
vpi_path[td_len + 3] = '/'
string.strcpy(vpi_path + td_len + 4, src_sha1)
string.strcpy(vpi_path + td_len + 4 + sha1_len, ".vpi")
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-ENSURE] path=%s\n", vpi_path)
f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R)
if f.closed:
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-ENSURE] open-fail\n")
stdlib.free(vpi_path)
return 0
vpi_buf: bytes = stdlib.malloc(VPI_READ_BUF_SIZE)
@@ -243,17 +292,74 @@ def _ensure_vpi_ret_annot_loaded(src_sha1: str, temp_dir: str) -> int:
else:
vpi_buf[VPI_READ_BUF_SIZE - 1] = 0
_cache_vpi_return_annots_text(vpi_buf, src_sha1)
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-ENSURE] read=%d after-count=%d\n", bytes_read, _g_vpi_ret_count)
stdlib.free(vpi_buf)
stdlib.free(vpi_path)
return 1
# ============================================================
# _subst_template_arg - 替换注解字符串中独立的模板参数 token
#
# 泛型模板返回注解(如 list[T].get -> T)中的类型参数名(T)
# 需替换为实际特化实参(AST|t.CPtr)后才能解析。仅替换前后
# 非字母数字下划线边界的独立 token(避免误替换 t.CSizeT 等)。
# 返回 stdlib 新分配字符串(调用者负责 free);失败返回 None。
# ============================================================
def _subst_template_arg(annot: str, tparam: str, targ: str) -> str:
"""替换 annot 中独立的 tparam token 为 targ"""
if annot is None or tparam is None or targ is None:
return None
alen: t.CSizeT = string.strlen(annot)
tplen: t.CSizeT = string.strlen(tparam)
tglen: t.CSizeT = string.strlen(targ)
if tplen == 0 or tplen > alen:
return annot
out: bytes = stdlib.malloc(alen + tglen * 8 + 16)
if out is None:
return None
opos: t.CSizeT = 0
p: t.CSizeT = 0
while p < alen:
matched: int = 0
if annot[p] == tparam[0] and p + tplen <= alen:
if string.strncmp(annot + p, tparam, tplen) == 0:
prev_ch: int = 0
next_ch: int = 0
if p > 0:
prev_ch = annot[p - 1]
if p + tplen < alen:
next_ch = annot[p + tplen]
prev_ok: int = 1
if (prev_ch >= 'a' and prev_ch <= 'z') or (prev_ch >= 'A' and prev_ch <= 'Z') or \
(prev_ch >= '0' and prev_ch <= '9') or prev_ch == '_':
prev_ok = 0
next_ok: int = 1
if (next_ch >= 'a' and next_ch <= 'z') or (next_ch >= 'A' and next_ch <= 'Z') or \
(next_ch >= '0' and next_ch <= '9') or next_ch == '_':
next_ok = 0
if prev_ok != 0 and next_ok != 0:
string.strncpy(out + opos, targ, tglen)
opos += tglen
p += tplen
matched = 1
if matched == 0:
out[opos] = annot[p]
opos += 1
p += 1
out[opos] = '\0'
return out
# ============================================================
# _lookup_vpi_ret_annot - 查找缓存的方法返回注解字符串
# ============================================================
def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str:
"""查找缓存的方法返回注解字符串,未找到返回 None"""
if _g_vpi_ret_keys is None or _g_vpi_ret_count == 0:
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-LOOKUP] empty count=%d\n", _g_vpi_ret_count)
return None
if src_sha1 is None or method_name is None:
return None
@@ -270,11 +376,74 @@ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str
viperlib.snprintf(key_buf, key_len + 1, "%s.%s.%s", src_sha1, cls_name, method_name)
else:
viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name)
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-LOOKUP] key=%s count=%d\n", key_buf, _g_vpi_ret_count)
i: int
for i in range(_g_vpi_ret_count):
if string.strcmp(_g_vpi_ret_keys + i * VPI_KEY_LEN, key_buf) == 0:
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-LOOKUP] hit\n")
stdlib.free(key_buf)
return _g_vpi_ret_strs + i * VPI_RET_LEN
# 未命中:打印同 sha1 前缀的所有缓存条目(调试定位 key 形式差异)
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-MISS] key=%s\n", key_buf)
mi: int
for mi in range(_g_vpi_ret_count):
mk: bytes = _g_vpi_ret_keys + mi * VPI_KEY_LEN
if string.strncmp(mk, src_sha1, sha1_len) == 0:
if VPI_DEBUG_ENABLE != 0:
stdio.printf(" [VPI-ENTRY] %s\n", mk)
# 泛型特化归一化匹配:list[AST|t.CPtr].get → list[T].get 模板缓存。
# 命中后把模板注解中的类型参数名(如 T)替换为实参(AST|t.CPtr)再返回。
# 不依赖模板类已注册/特化已发生(base.vp 可能先于 list 模块翻译)。
if cls_name is not None:
lbkt_v: str = string.strchr(cls_name, '[')
if lbkt_v is not None:
rbkt_v: str = string.strrchr(cls_name, ']')
if rbkt_v is not None and rbkt_v > lbkt_v:
base_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_v) - t.CUInt64T(cls_name))
param_len_v: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_v) - t.CUInt64T(lbkt_v) - 1)
if base_len_v > 0 and param_len_v > 0:
base_v: str = stdlib.malloc(base_len_v + 1)
param_v: str = stdlib.malloc(param_len_v + 1)
if base_v is not None and param_v is not None:
string.strncpy(base_v, cls_name, base_len_v)
base_v[base_len_v] = '\0'
string.strncpy(param_v, lbkt_v + 1, param_len_v)
param_v[param_len_v] = '\0'
# 遍历缓存找 {sha1}.{base}[xxx].{method}
gi: int
for gi in range(_g_vpi_ret_count):
gk: bytes = _g_vpi_ret_keys + gi * VPI_KEY_LEN
if string.strncmp(gk, src_sha1, sha1_len) == 0 and \
gk[sha1_len] == '.' and \
string.strncmp(gk + sha1_len + 1, base_v, base_len_v) == 0 and \
gk[sha1_len + 1 + base_len_v] == '[':
gklb: str = string.strchr(gk + sha1_len + 1 + base_len_v, ']')
if gklb is not None:
tparam_len_v: t.CSizeT = t.CSizeT(
t.CUInt64T(gklb) - t.CUInt64T(gk + sha1_len + 1 + base_len_v) - 1)
if tparam_len_v > 0:
meth_start_v: str = gklb + 2 # 跳过 ']' 和 '.'
if string.strcmp(meth_start_v, method_name) == 0:
tparam_v: str = stdlib.malloc(tparam_len_v + 1)
if tparam_v is not None:
string.strncpy(tparam_v, gk + sha1_len + 1 + base_len_v + 1, tparam_len_v)
tparam_v[tparam_len_v] = '\0'
new_annot_v: str = _subst_template_arg(
_g_vpi_ret_strs + gi * VPI_RET_LEN, tparam_v, param_v)
if VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-GEN] base=%s tparam=%s arg=%s annot=%s\n",
base_v, tparam_v, param_v,
_g_vpi_ret_strs + gi * VPI_RET_LEN)
stdlib.free(tparam_v)
stdlib.free(base_v)
stdlib.free(param_v)
stdlib.free(key_buf)
return new_annot_v
stdlib.free(base_v)
stdlib.free(param_v)
stdlib.free(key_buf)
return None
+104 -2
View File
@@ -4,6 +4,7 @@ import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
@@ -3082,6 +3083,9 @@ def _lookup_method_ret_ty_via_vpi(pool: memhub.MemBuddy | t.CPtr,
cls_name: str,
method_name: str) -> llvmlite.LLVMType | t.CPtr:
"""从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None"""
if VpiReader.VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CALL] lookup sha1=%s cls=%s m=%s tdlen=%d\n",
cls_sha1, cls_name, method_name, _g_temp_dir_len)
if pool is None or cls_sha1 is None or method_name is None:
return None
# 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环
@@ -3094,10 +3098,43 @@ def _lookup_method_ret_ty_via_vpi(pool: memhub.MemBuddy | t.CPtr,
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, _g_temp_dir)
annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
if annot is None:
if VpiReader.VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CALL] annot=NONE\n")
return None
if VpiReader.VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CALL] annot=%s\n", annot)
return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty)
# ============================================================
# _special_method_ret_ty - 编译器内置特殊方法的固定返回类型
#
# __before_init__ / __init__:编译器生成/约定返回 void
# __new__:返回 Ptr(StructTy)(存储空间指针)
#
# 这些方法不存在于源码(vpi stub 无条目),跨模块调用时
# found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器
# 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致),
# 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。
# ============================================================
def _special_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
class_name: str,
method_name: str) -> llvmlite.LLVMType | t.CPtr:
"""编译器内置特殊方法的固定返回类型;非特殊返回 None"""
if pool is None or method_name is None:
return None
if string.strcmp(method_name, "__before_init__") == 0 or \
string.strcmp(method_name, "__init__") == 0:
return llvmlite.Void(pool)
if string.strcmp(method_name, "__new__") == 0:
if class_name is not None:
sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
if sp_struct_ty is not None:
return llvmlite.Ptr(pool, sp_struct_ty)
return None
return None
# ============================================================
# _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast
#
@@ -3440,6 +3477,10 @@ def _translate_property_call(pool: memhub.MemBuddy | t.CPtr,
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
else:
sp_ty1: llvmlite.LLVMType | t.CPtr = _special_method_ret_ty(pool, class_name, method_name)
if sp_ty1 is not None:
call_ret_ty = sp_ty1
else:
cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name)
looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
@@ -3779,7 +3820,65 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
if frt is not None:
call_ret_ty = frt
else:
# found_func 为 None(stub 未注入):尝试从 text.ll 查找实际返回类型
# found_func 为 None(stub 未注入):先处理编译器内置特殊方法
sp_ty2: llvmlite.LLVMType | t.CPtr = _special_method_ret_ty(pool, class_name, method_name)
if sp_ty2 is not None:
call_ret_ty = sp_ty2
else:
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
gen_done: int = 0
if class_name is not None:
lbkt_g: str = string.strchr(class_name, '[')
if lbkt_g is not None:
rbkt_g: str = string.strrchr(class_name, ']')
if rbkt_g is not None and rbkt_g > lbkt_g:
base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name))
arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1)
if base_len_g > 0 and arg_len_g > 0:
base_buf_g: str = pool.alloc(base_len_g + 1)
arg_buf_g: str = pool.alloc(arg_len_g + 1)
if base_buf_g is not None and arg_buf_g is not None:
string.strncpy(base_buf_g, class_name, base_len_g)
base_buf_g[base_len_g] = '\0'
string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g)
arg_buf_g[arg_len_g] = '\0'
ta_list_g: list[str] | t.CPtr = list[str](pool, 4)
if ta_list_g is not None:
# 逗号分隔多类型实参(list[X] / dict[K, V])
cur_arg_g: str = arg_buf_g
while cur_arg_g is not None:
comma_g: str = string.strchr(cur_arg_g, ',')
if comma_g is None:
ta_list_g.append(cur_arg_g)
break
seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g))
seg_buf_g: str = pool.alloc(seg_len_g + 1)
if seg_buf_g is not None:
string.strncpy(seg_buf_g, cur_arg_g, seg_len_g)
seg_buf_g[seg_len_g] = '\0'
ta_list_g.append(seg_buf_g)
cur_arg_g = comma_g + 1
spec_name_g: str = HandlesClassDef._specialize_generic_class(
trans, base_buf_g, ta_list_g)
if spec_name_g is not None:
# 特化后重新查找特化函数(特化名 = 调用点类名)
spec_lk_g: str = pool.alloc(
string.strlen(class_name) + string.strlen(method_name) + 2)
if spec_lk_g is not None:
viperlib.snprintf(spec_lk_g,
string.strlen(class_name) + string.strlen(method_name) + 2,
"%s.%s", class_name, method_name)
spec_found_g: llvmlite.Function | t.CPtr = find_func_in_module(mod, spec_lk_g)
if spec_found_g is not None:
frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g)
if frt_g is not None:
call_ret_ty = frt_g
found_func = spec_found_g
gen_done = 1
if gen_done == 0:
# 尝试从 text.ll 查找实际返回类型
# 避免指针返回值被默认 i32 导致 inttoptr 截断
looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
pool, cls_sha1_mc, class_name, method_name)
@@ -4993,7 +5092,10 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
llvmlite.value_set_next(tail3, arg_val3)
tail3 = arg_val3
total3: int = 1 + can
ret_ty3: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
ret_ty3: llvmlite.LLVMType | t.CPtr = _special_method_ret_ty(
pool, cls_nm2, func_name)
if ret_ty3 is None:
ret_ty3 = _LookupMethodRetTyFromTextLL(
pool, sha1_fc, cls_nm2, func_name)
if ret_ty3 is None:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
+5
View File
@@ -500,6 +500,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 设置全局 temp_dir(供跨模块 CDefine 查找使用)
HandlesType.set_temp_dir(temp_dir)
# 同步设置 HandlesExprCall 的 temp_dir(供 vpi stub 返回注解缓存按需加载)。
# 必须在 includes 翻译前设置:Phase1 翻译 json 等 includes 时,"同模块方法
# 调用(定义在后)"(如 json.__setitem__ 调 _pool_alloc)需要读
# {temp_dir}/{sha1[0:2]}/{sha1}.vpi 兜底,而 Phase2 的 SetTempDir 太晚。
HandlesExprCall.SetTempDir(temp_dir)
# 确保 temp 目录存在(build_dir/temp 可能尚未创建)
BuildPipeline.ensure_dir(temp_dir)