diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 570b096..e35fdaf 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -760,13 +760,15 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # _LookupMethodRetTyFromTextLL 的 strlen(0x1) 零页崩溃 # (llvmlite/__init__.vp CreateGlobalInt 翻译时 0xC0000005 根因)。 mod_ret_sha1: str = None + # [MODSHA1] 诊断用:模块名(cl.func 为 Attribute 时赋值,否则保持 None)。 + # 声明在 if 外,使下方裸名兜底分支也能安全读取(读未声明的局部 = 栈垃圾)。 + mod_path_ret: str = None if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: at_ret: ast.Attribute* = ast.Attribute*(cl.func) # 解析调用模块路径:单层(stdlib.free,value 是 Name)与多层 # (w32.win32file.CreatePipe,value 是嵌套 Attribute)都支持。 # 缺失多层路径 → mod_ret_sha1=None → 误走裸名外部函数路径, # fail-fast 误杀可收敛的模块限定调用(CreatePipe 根因)。 - mod_path_ret: str = None if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: mod_ret_nm: ast.Name* = ast.Name*(at_ret.value) mod_path_ret = mod_ret_nm.id @@ -783,6 +785,20 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): if trans is not None: fi_from_rt = trans._from_imports mod_ret_sha1 = self.Gen.StructGen._resolve_module_sha1(mod_path_ret, fi_from_rt) + # [MODSHA1] 临时诊断(定位后删除):模块限定调用的模块名 → SHA1 + # 解析失败时,打印本模块名与对照模块名(stdint,必在 includes) + # 的精确/后缀查询结果,区分「store 整体为空」与「store 有内容但 + # 缺该模块」。devfs.vp 的 string.split 报错即经此分支。 + if mod_ret_sha1 is None: + dg_ex: str = self.Gen.CallGenBase._lookup_module_sha1(mod_path_ret) + dg_sf: str = self.Gen.CallGenBase._lookup_module_sha1_suffix(mod_path_ret) + dg_ctrl: str = self.Gen.CallGenBase._lookup_module_sha1("stdint") + if dg_ex is None: dg_ex = "-" + if dg_sf is None: dg_sf = "-" + if dg_ctrl is None: dg_ctrl = "-" + stdio.printf("[MODSHA1] mod='%s' fn='%s' exact=%s suffix=%s ctrl_stdint=%s line=%d\n", + mod_path_ret, func_name, dg_ex, dg_sf, dg_ctrl, cl.lineno) + stdio.fflush(None) if mod_ret_sha1 is not None: # 函数内懒 import:VpiReader imports HandlesExprCall, # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) @@ -837,6 +853,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # 本遍仅临时占位。 call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name, node, 0) else: + # [MODSHA1] 临时诊断(定位后删除):走到裸名兜底 ⇒ mod_ret_sha1 为 + # None。仅当 cl.func 仍是模块限定形态(Attribute)时打印——这正是 + # "模块限定却解析不出模块"的异常组合(此时 mod_path_ret 为 None + # 说明 value 段不是 Name/Attribute;非 None 说明模块名查不到 SHA1)。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + stdio.printf("[MODSHA1-D] mod='%s' fn='%s' line=%d\n", + mod_path_ret, func_name, cl.lineno) + stdio.fflush(None) # 裸名调用(cl.func 是 Name,mod_ret_sha1=None)两类来源:from-import 的函数(后续解析模块归属构造 mangled call_name 并经 text.ll/vpi 精确解析返回类型,可收敛)→ fatal_if_unknown=0 仅临时占位,不 fail-fast;纯外部 C 函数(无登记、无模块归属,白名单未命中)→ fail-fast(fatal_if_unknown=1)。闭包变量与持有函数指针/闭包的局部变量同样按可解析占位——返回类型由 translate_closure_call/lookup_var 路径固定处理,不依赖外部返回类型推断,否则被 fail-fast 误杀 bare_resolvable: int = 0 if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0: