fix(err): 成员查找 fail-fast 改用可读异常 + 报错语句栈不再重复长报文

① 新增 MemberLookupFailFast(KeyError):_get_member_offset 的 fail-fast 原用 raise KeyError(消息),而 KeyError.__str__ = repr(消息) ⇒ 报文被加上引号、换行被转义成字面 \n(含"源代码 (文件, 行号): 行号 | 源码"的多行报文彻底不可读)。新类继承 KeyError(保住 HandlesExprAttr 两处 except KeyError 兜底点)但 __str__ 返回裸消息。

② 顺带删除该处的 traceback.print_stack 调试转储(遗留调试语句,输出噪音)。

③ Phase2Translator 语句栈渲染:原格式把同一条异常消息贴在每一层帧后面 ⇒ 一句话被打印 N 次;改为外层→内层的调用路径逐帧印位置、异常消息只在最内层印一次。
This commit is contained in:
TermiNexus committed 2026-09-28 16:48:58 +08:00
1 parent 49ff1b995f
commit 96d8e13c5a
2 files changed
+33 -10

No files matched your search

+11 -4
View File
@@ -2055,11 +2055,18 @@ class Phase2Translator:
error_stack = getattr(trans.translator, '_ErrorStack', [])
if error_stack:
self._last_ErrorStack = error_stack
chain_lines = []
for entry in reversed(error_stack):
if len(entry) >= 3:
exc_msg, line_info = entry[1], entry[2]
# 语句栈渲染:error_stack 按"由内向外"入栈(内层语句先 append),
# 这里反转为"外层 → 内层"的调用路径;**异常消息只在最内层印一次**,
# 其余帧只印位置——否则同一段长 fail-fast 报文会被每个帧重复一遍
# (旧格式把消息贴在每一帧后面,输出里同一句话出现 N 次,不可读)。
entries: list = [entry for entry in error_stack if len(entry) >= 3]
chain_lines: list[str] = []
for chain_idx, entry in enumerate(reversed(entries)):
exc_msg, line_info = entry[1], entry[2]
if chain_idx == len(entries) - 1:
chain_lines.append(" %s\n %s" % (line_info, exc_msg))
else:
chain_lines.append(" %s" % (line_info,))
if chain_lines:
enriched = str(e) + "\n" + "\n".join(chain_lines)
raise type(e)(enriched) from e
+22 -6
View File
@@ -19,6 +19,24 @@ class FailFastError(Exception):
"""
class MemberLookupFailFast(KeyError):
"""成员偏移查找失败的 fail-fast 异常(**继承 KeyError** 以保持既有兜底点可用)。
为什么继承 KeyError:本仓有两处 `except KeyError` 把 `_get_member_offset` 的
失败当作"该字段类型未知"继续回查(HandlesExprAttr 的字段类型三级回退),改成
其它异常类型会把这些兜底点击穿。
为什么重写 `__str__`:KeyError 的默认 `__str__` 是 `repr(消息)` —— 会在报文两端
加引号、并把换行/制表转义成字面 `\\n`,多行 fail-fast 报文(含"源代码 (文件, 行号):
行号 | 源码")因此彻底不可读。这里原样返回裸消息,与 FailFastError 的观感一致。
"""
def __str__(self) -> str:
if self.args and isinstance(self.args[0], str):
return self.args[0]
return super().__str__()
class FuncGenMixin:
def setup_from_symbol_table(self, SymbolTable: Any) -> None:
@@ -737,12 +755,10 @@ 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]
try:
import traceback as _tb
_tb.print_stack(file=sys.stderr)
except Exception:
pass
raise KeyError(
# 异常类型: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})"
)