chore(诊断): MemberLookupFailFast 补取证——字段所有者、类键/实例名、登记为该类的变量与实际 pointee

现场:CallGenDispatch.vp:787 `len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee`
报 "[fast-fail] 属性 'Pointee' 在类 'ParamNode' 中找不到(class_members=2 个:
['Next','Ty'])"。'Pointee' 实际属 LLVMType 的 REnum 变体镜像字段(LLVMType.Ptr.Pointee),
而 ParamNode 只有 Next/Ty ⇒ 说明**读取时的接收者类名被判成了 ParamNode**
(`len_val` 的注解与 RHS 都写的是 `llvmlite.Value*`,Value.Ty 才是 rawptr[LLVMType];
ParamNode.Ty 是裸 rawptr = i8*)。

本轮只补取证、不改行为,让下一轮能一次定位"是谁把接收者记成了 ParamNode":
  ① 本类键 → struct 实例 IR 名(键/实例名不一致 ⇒ 同一类名两份实例);
  ② 其它**声明了该字段**的类键列表(唯一者即"本该用的类");
  ③ var_struct_class 中登记为**本类**的变量(封顶 6 个)及其实际 pointee IR 名
     —— 记录类名与实际 IR 类型不一致时,直接圈定记录点。

验证:py_compile 通过。
This commit is contained in:
TermiNexus committed 2026-09-30 12:26:05 +08:00
1 parent 43853bc455
commit a1c43a7b3b
1 file changed
+41
+41
View File
@@ -975,12 +975,53 @@ class FuncGenMixin:
if isinstance(_st_diag, ir.IdentifiedStructType):
_struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque'
_member_names_diag: list = [n for n, _ in _members_diag][:16]
# ---- 取证(只读,不改变行为,2026-09-30)----
# 现场:CallGenDispatch.vp:787 `len_val.Ty.Pointee` 里 `.Pointee` 被判成在类
# 'ParamNode'(2 字段 Next/Ty)里找 —— 而 'Pointee' 本属 LLVMType 的 REnum
# 变体镜像字段。要一次定位"是谁把接收者记成了 ParamNode",报文需给出:
# ① 本类键 → struct 实例 IR 名(键/实例名不一致即"同名两份实例");
# ② **真正声明了该字段**的类键(唯一者即"本该用的类");
# ③ var_struct_class 里被登记为**本类**的变量(封顶 6 个)及其实际 pointee
# IR 名 —— 两者不一致即"记录类名与实际 IR 类型不符",直接圈定记录点。
_extra_diag: str = ''
try:
_st_key = self.structs.get(ClassName) if ClassName else None
if isinstance(_st_key, ir.IdentifiedStructType):
_extra_diag += (f"\n 本类键 '{ClassName}' → struct 实例 IR 名 "
f"'{getattr(_st_key, 'name', '?')}'")
_owners: list = []
for _ck2, _cm2 in self.class_members.items():
if _ck2 == ClassName:
continue
if any(_n2 == field_name for _n2, _ in (_cm2 or [])):
_owners.append(_ck2)
_extra_diag += (f"\n 声明了 '{field_name}' 的其它类键({len(_owners)} 个): "
f"{_owners[:8]}{' …' if len(_owners) > 8 else ''}")
_vsc: dict = getattr(self, 'var_struct_class', {}) or {}
_vars_here: list = [v for v, cn in _vsc.items() if cn == ClassName]
if _vars_here:
_vdesc: list = []
for _v2 in _vars_here[:6]:
_pointee_desc: str = '?'
for _src3 in (getattr(self, 'variables', {}) or {},
getattr(self, '_reg_values', {}) or {},
getattr(self, '_direct_values', {}) or {}):
_val3 = _src3.get(_v2)
if _val3 is not None and isinstance(getattr(_val3, 'type', None), ir.PointerType):
_pointee_desc = str(_val3.type.pointee)
break
_vdesc.append(f"{_v2}(pointee={_pointee_desc})")
_extra_diag += (f"\n var_struct_class 登记为 '{ClassName}' 的变量("
f"{len(_vars_here)} 个,示前 6): {_vdesc}")
except Exception as _e_diag:
_extra_diag += f"\n (取证附加信息生成失败: {type(_e_diag).__name__}: {_e_diag})"
# 异常类型:MemberLookupFailFast(KeyError 子类 + 裸消息 __str__)——
# 既保留 `except KeyError` 兜底点,又让报文不再被 repr 成"带引号 + \n 转义"
# 的不可读形式(原有 traceback.print_stack 调试转储一并移除,保持输出干净)。
raise MemberLookupFailFast(
f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到"
f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})"
f"{_extra_diag}"
)
def _resolve_class_for_var(self, var_name: str) -> str | None: