From a1c43a7b3bfa85f9877f0602bf636a4b46c43faf Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 12:26:05 +0800 Subject: [PATCH] =?UTF-8?q?chore(=E8=AF=8A=E6=96=AD):=20MemberLookupFailFa?= =?UTF-8?q?st=20=E8=A1=A5=E5=8F=96=E8=AF=81=E2=80=94=E2=80=94=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=89=80=E6=9C=89=E8=80=85=E3=80=81=E7=B1=BB=E9=94=AE?= =?UTF-8?q?/=E5=AE=9E=E4=BE=8B=E5=90=8D=E3=80=81=E7=99=BB=E8=AE=B0?= =?UTF-8?q?=E4=B8=BA=E8=AF=A5=E7=B1=BB=E7=9A=84=E5=8F=98=E9=87=8F=E4=B8=8E?= =?UTF-8?q?=E5=AE=9E=E9=99=85=20pointee?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现场: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 通过。 --- lib/core/LLVMCG/FuncGen.py | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index 1d6c502..3da0daa 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -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: