From 60deee1d1746127a4a076430bbc1c59dc7f5e492 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 1 Sep 2026 20:26:14 +0800 Subject: [PATCH] =?UTF-8?q?fix(call):=20=5Flookup=5Freexport=5Ffrom=5Fvpi?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81=20star=20import=20=E5=86=8D=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=AE=9A=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - from X import * 的 re-export(如 fltk/__init__ 再导出 _cfl 全部 extern FFI)此前无法定位定义模块 - fltk.Fl_init_all 被误加 SHA1 前缀走 mangled 精确解析 → extern def 无 define → fail-fast - 命中后由 is_cexport_func/_is_state_func_from_vpi 二次校验裸名 --- App/lib/core/Gen/Call/CallGenBase.vp | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/App/lib/core/Gen/Call/CallGenBase.vp b/App/lib/core/Gen/Call/CallGenBase.vp index 807da19..47aa99a 100644 --- a/App/lib/core/Gen/Call/CallGenBase.vp +++ b/App/lib/core/Gen/Call/CallGenBase.vp @@ -231,6 +231,44 @@ class CallGenBase: mod_end: t.CSizeT = imp_pos # 名称列表从 "import " 之后(逗号分隔,含 "A as B" 取原名 A) nm_start: t.CSizeT = imp_pos + 8 + # star import 支持:from X import * → 任意函数都属 X 模块。 + # fltk/__init__.vp 用 "from fltk._cfl import *" 再导出全部 extern + # FFI,跨模块调用 fltk.Fl_init_all 若无法定位定义模块 → 误加 SHA1 + # 前缀走 mangled 精确解析 → extern def 无 define → fail-fast。 + # 命中后由调用方 is_cexport_func/_is_state_func_from_vpi 二次校验。 + if nm_start < ls + ll and buf[nm_start] == '*': + star_dot: int = 0 + if buf[mod_start] == '.': + star_dot = 1 + star_buf: str = pool.alloc(mod_end - mod_start + 1) + if star_buf is None: + stdlib.free(buf) + return None + si2: t.CSizeT = 0 + while mod_start + si2 < mod_end: + star_buf[si2] = buf[mod_start + si2] + si2 += 1 + star_buf[si2] = '\0' + while star_buf[0] == '.': + star_buf = star_buf + 1 + if string.strlen(star_buf) == 0: + stdlib.free(buf) + return None + if star_dot != 0: + spkg: str = self._module_package_from_sha1(pool, mod_sha1) + if spkg is None: + stdlib.free(buf) + return None + srl: t.CSizeT = string.strlen(spkg) + string.strlen(star_buf) + 2 + sres: str = pool.alloc(srl) + if sres is None: + stdlib.free(buf) + return None + viperlib.snprintf(sres, srl, "%s.%s", spkg, star_buf) + stdlib.free(buf) + return sres + stdlib.free(buf) + return star_buf scan: t.CSizeT = nm_start while scan < ls + ll: while scan < ls + ll and (buf[scan] == ' ' or buf[scan] == ','): @@ -554,6 +592,19 @@ class CallGenBase: pi2 += 1 return existing = existing.Next + # 裸名 C 库函数(如 string.memset → @memset、stdlib.memcpy → @memcpy): + # call_name 无 sha1 前缀 → 无法提取定义侧模块查 vpi 参数注解 → + # 此前用实参类型建 declare(字面量 0=i32 把定义 t.CSizeT(i64) 固化窄, + # VKernel process.vp string.memset 声明 @memset(i8*,i32,i32) vs 定义 + # @memset(i8*,i32,i64),跨模块 ABI 宽度不一致,优化路径读高位垃圾 + # 写穿内存)。已知 C 库函数直接按标准签名建 declare(与 CallGenLib + # _ensure_c_lib_declare 白名单一致:memset/memcpy/memmove/memcmp/ + # strcmp/strncmp/strcpy/strncpy/strcat/strlen/puts/atoi/atol/abs/labs)。 + if call_name is not None and string.strchr(call_name, 46) is None: + std_lib_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenLib._ensure_c_lib_declare( + pool, mod, call_name) + if std_lib_fn is not None: + return # 创建函数声明 func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty) if func is None: @@ -1108,6 +1159,45 @@ class CallGenBase: stdlib.free(path_buf) return exists + # ============================================================ + # _AppendPhaseAPending - 追加 Phase A MRO/VPI pending 明细到诊断文件 + # + # 跨模块方法返回类型解析(mro_ret / mro_anc)在依赖模块 text.ll 未生成 + # 时置 _deps_pending。此信息此前只走滚动 DEPDBG(刷屏易被淹没),此处 + # 持久化到 {TempDir}/_phaseA_pending.log(tab 分隔),供 Phase2 收敛失败 + # 时按调用方 sha1 过滤,输出"MRO/VPI 类似依赖图"的最终诊断。 + # 行格式: {owner_sha1}\t{kind}\t{cls}\t{method}\t{dep_sha1}\t{extra}\n + # ============================================================ + def _AppendPhaseAPending(self, owner_sha1: str, kind: str, + cls_name: str, method_name: str, + dep_sha1: str, extra: str) -> None: + """追加一行 MRO/VPI pending 明细到诊断文件(文件不存在则创建)""" + td: str = self.Gen.CallGenBase.TempDir + td_len: t.CSizeT = self.Gen.CallGenBase.TempDirLen + if td is None or td_len == 0 or owner_sha1 is None or kind is None: + return + path_len: t.CSizeT = td_len + 24 + path_buf: bytes = stdlib.malloc(path_len) + if path_buf is None: + return + viperlib.snprintf(path_buf, path_len, "%s/_phaseA_pending.log", td) + pf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.A) + stdlib.free(path_buf) + if pf.closed: + return + line: bytes = stdlib.malloc(512) + if line is not None: + viperlib.snprintf(line, 512, "%s\t%s\t%s\t%s\t%s\t%s\n", + owner_sha1, kind, + cls_name if cls_name is not None else "-", + method_name if method_name is not None else "-", + dep_sha1 if dep_sha1 is not None else "-", + extra if extra is not None else "-") + ln: t.CSizeT = string.strlen(line) + pf.write(line, ln) + stdlib.free(line) + pf.close() + # ============================================================ # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 #