fix(tpc): fail-fast 报文补「属性基址取证事实」,属性读返回 None 不再靠反推
类别:a(编译器缺陷 —— fail-fast 报文缺取证事实,无法一眼定位根因)
现象:HandlesBase._RaiseUnresolvedExpr 与 HandlesExprCall._RequireArgValue 在
「属性读取值失败」时只报 Node 形态(Attribute),报错点与真因相隔数层调用,
需要人工从 Gen.var_struct_class / Gen.structs / Gen.class_members 反推。
改动:
1. HandlesBase 抽出公开方法 _DescribeAttrBase(Gen, Node) -> str(原 _RaiseUnresolvedExpr
内联代码抽出,行为不变),对两类基座给事实:
- Name 基座:var_struct_class / global_struct_class / alloca 类型 / 是否命中
Gen.structs / class_members 字段数与字段名单(前 12)。
- Call(func=BinOp(BitOr)) 强转基座:联合基类名 + 短名是否命中 Gen.structs +
字段数,并显式标注「强转基座本应走 _FailFastAttrCallBase 详细报文,此处仍是本条
⇒ 那条 fail-fast 未触发」,把「另一处缺口」这一事实直接写进报文。
2. _RaiseUnresolvedExpr 改调 _DescribeAttrBase(删除内联重复代码)。
3. HandlesExprCall._RequireArgValue 在实参是 Attribute 时追加同一份基址诊断
(与 HandlesBase 共用,保证两处口径逐字一致)。
不改变任何判定逻辑,仅补取证事实。
This commit is contained in:
1 parent
b3bc94f99f
commit
0392ccdea0
2 files changed
+62
-41
No files matched your search
@@ -555,6 +555,55 @@ class BaseHandle:
|
||||
return f"Subscript({BaseHandle._ExprShape(Node.value, Depth + 1)})"
|
||||
return type(Node).__name__
|
||||
|
||||
def _DescribeAttrBase(self, Gen: Any, Node: ast.Attribute) -> str:
|
||||
"""属性读返回 None 时的**基址事实**(供 fail-fast 报文取证,不改变任何判定)。
|
||||
|
||||
两类根因:① 类名登记退化(var_struct_class 存 'rawptr' / 'rawptr[X]' / 折叠态,
|
||||
或压根没登记);② 登记名与 Gen.structs / class_members 的键不同源(短名 vs
|
||||
sha1 全名)。另有一条**必须验伪**的可能:基座是强转调用 `(T*(x)).attr`
|
||||
(parser 统一产成 Call(func=BinOp(BitOr)))时,HandlesExprAttr 的
|
||||
`_handle_attr_call_result` 自带 `_FailFastAttrCallBase` 详细 fail-fast
|
||||
(FailFastError 全仓无 except,必上抛)——若仍走到本诊断,即说明那条
|
||||
fail-fast 未被走到,属**另一处缺口**,故显式标注该事实。
|
||||
"""
|
||||
_base: ast.AST = Node.value
|
||||
_parts: list[str] = [f"基座形态={BaseHandle._ExprShape(_base)}"]
|
||||
if isinstance(_base, ast.Name):
|
||||
_bn: str = _base.id
|
||||
_vc: str | None = None
|
||||
_alloc: Any = None
|
||||
try:
|
||||
_vc = (getattr(Gen, 'var_struct_class', None) or {}).get(_bn)
|
||||
if not _vc:
|
||||
_vc = (getattr(Gen, 'global_struct_class', None) or {}).get(_bn)
|
||||
_alloc = (getattr(Gen, 'variables', None) or {}).get(_bn)
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
_parts.append(f"'{_bn}' 的 var_struct_class={_vc!r}")
|
||||
_parts.append(f"alloca 类型={getattr(_alloc, 'type', None)}")
|
||||
_parts.append("该名在 Gen.structs="
|
||||
+ ('是' if _vc and _vc in Gen.structs else ('否' if _vc else '—')))
|
||||
_parts.append("class_members="
|
||||
+ (f"{len(Gen.class_members.get(_vc) or [])} 个字段"
|
||||
if _vc and _vc in Gen.class_members else '无该键'))
|
||||
if _vc and _vc in Gen.class_members:
|
||||
_parts.append(f"字段名单={[m[0] for m in Gen.class_members[_vc]][:12]}")
|
||||
elif (isinstance(_base, ast.Call) and isinstance(_base.func, ast.BinOp)
|
||||
and isinstance(_base.func.op, ast.BitOr)):
|
||||
_cls: str | None = None
|
||||
try:
|
||||
_cls = self.Trans.ExprAttrHandle._extract_union_base_class(_base.func)
|
||||
except Exception: # noqa: BLE001
|
||||
_cls = None
|
||||
_parts.append(f"联合基类名={_cls!r}")
|
||||
_parts.append(f"短名 in structs={'是' if _cls and _cls in Gen.structs else '否'}")
|
||||
_parts.append("class_members="
|
||||
+ (f"{len(Gen.class_members.get(_cls) or [])} 个字段"
|
||||
if _cls in Gen.class_members else '无该键'))
|
||||
_parts.append("注: 强转基座形态本应走 _FailFastAttrCallBase 详细报文,"
|
||||
"此处仍是本条 ⇒ 那条 fail-fast 未触发")
|
||||
return ";".join(_parts)
|
||||
|
||||
@staticmethod
|
||||
def _ExprText(Node: ast.AST) -> str:
|
||||
"""把表达式节点渲染成源码文本(如 func.Blocks.Head、list[X*] * uint64(v)),供错误信息使用"""
|
||||
@@ -684,48 +733,10 @@ class BaseHandle:
|
||||
f"{(',注解 ' + ann_text) if ann_text else ''}。位置 {loc}"
|
||||
f"{(',源码: ' + code_line) if code_line else ''}")
|
||||
# 【基址诊断】属性读返回 None 时报出**基座真实形态 + 类名登记事实**,不再从
|
||||
# "求值为空"反推。两类根因:① 类名登记退化(var_struct_class 存 'rawptr' /
|
||||
# 'rawptr[X]' / 折叠态,或压根没登记);② 登记名与 Gen.structs / class_members
|
||||
# 的键不同源(短名 vs sha1 全名)。另有一条**必须验伪**的可能:基座是强转调用
|
||||
# `(T*(x)).attr`(parser 统一产成 Call(func=BinOp(BitOr)))时,HandlesExprAttr
|
||||
# 的 `_handle_attr_call_result` 自带 `_FailFastAttrCallBase` 详细 fail-fast
|
||||
# (FailFastError 全仓无 except,必上抛)——若这里仍是通用报文,即说明那条
|
||||
# fail-fast 未被走到,属**另一处缺口**,故显式标注该事实。
|
||||
# "求值为空"反推(同一份事实也供 _RequireArgValue 的实参求值失败路径使用,
|
||||
# 见 HandlesExprCall._RequireArgValue)。
|
||||
if isinstance(Node, ast.Attribute):
|
||||
_base: ast.AST = Node.value
|
||||
_parts: list[str] = [f"基座形态={BaseHandle._ExprShape(_base)}"]
|
||||
if isinstance(_base, ast.Name):
|
||||
_bn: str = _base.id
|
||||
_vc: str | None = None
|
||||
_alloc: Any = None
|
||||
try:
|
||||
_vc = (getattr(Gen, 'var_struct_class', None) or {}).get(_bn)
|
||||
if not _vc:
|
||||
_vc = (getattr(Gen, 'global_struct_class', None) or {}).get(_bn)
|
||||
_alloc = (getattr(Gen, 'variables', None) or {}).get(_bn)
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
_parts.append(f"'{_bn}' 的 var_struct_class={_vc!r}")
|
||||
_parts.append(f"alloca 类型={getattr(_alloc, 'type', None)}")
|
||||
_parts.append(f"该名在 Gen.structs={'是' if _vc and _vc in Gen.structs else ('否' if _vc else '—')}")
|
||||
_parts.append("class_members="
|
||||
+ (f"{len(Gen.class_members.get(_vc) or [])} 个字段"
|
||||
if _vc and _vc in Gen.class_members else '无该键'))
|
||||
elif (isinstance(_base, ast.Call) and isinstance(_base.func, ast.BinOp)
|
||||
and isinstance(_base.func.op, ast.BitOr)):
|
||||
_cls: str | None = None
|
||||
try:
|
||||
_cls = self.Trans.ExprAttrHandle._extract_union_base_class(_base.func)
|
||||
except Exception: # noqa: BLE001
|
||||
_cls = None
|
||||
_parts.append(f"联合基类名={_cls!r}")
|
||||
_parts.append(f"短名 in structs={'是' if _cls and _cls in Gen.structs else '否'}")
|
||||
_parts.append("class_members="
|
||||
+ (f"{len(Gen.class_members.get(_cls) or [])} 个字段"
|
||||
if _cls in Gen.class_members else '无该键'))
|
||||
_parts.append("注: 强转基座形态本应走 _FailFastAttrCallBase 详细报文,"
|
||||
"此处仍是通用报文 ⇒ 那条 fail-fast 未触发")
|
||||
msg += "\n│ 基址诊断: " + ";".join(_parts)
|
||||
msg += "\n│ 基址诊断: " + self._DescribeAttrBase(Gen, Node)
|
||||
_vlog().compile_error(msg, src_file, lineno, code_line)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -443,6 +443,15 @@ class ExprCallHandle(BaseHandle):
|
||||
loc: str = f"{src_file}:{lineno}"
|
||||
if col >= 0:
|
||||
loc += f":{col}"
|
||||
# 实参是属性读时补同一份基址事实(与 HandlesBase._RaiseUnresolvedExpr 共用
|
||||
# `_DescribeAttrBase`):属性读取值失败的两类根因(类名登记退化 / 键不同源)
|
||||
# 必须一眼可见,不再从"求值失败"反推。
|
||||
_base_facts: str = ''
|
||||
if isinstance(ArgNode, ast.Attribute):
|
||||
try:
|
||||
_base_facts = self._DescribeAttrBase(Gen, ArgNode)
|
||||
except Exception: # noqa: BLE001
|
||||
_base_facts = ''
|
||||
raise Exception(
|
||||
f"[TransPyC] 调用实参编译期求值为空: 被调者 '{Callee}' 的第 {ArgIndex} 个实参 "
|
||||
f"'{expr_text}'({ArgKind} 形态)求值失败;已终止编译,不丢弃该实参"
|
||||
@@ -450,6 +459,7 @@ class ExprCallHandle(BaseHandle):
|
||||
f"常见根因:枚举成员/名称未登记、跨模块符号查找失败、类定义在声明期结构体不完整。"
|
||||
f"位置 {loc}"
|
||||
f"{(',源码: ' + code_line) if code_line else ''}"
|
||||
f"{chr(10) + '│ 基址诊断: ' + _base_facts if _base_facts else ''}"
|
||||
)
|
||||
|
||||
def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
|
||||
Reference in new issue
Block a user