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:
1 parent
43853bc455
commit
a1c43a7b3b
1 file changed
+41
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user