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:
1 parent
49ff1b995f
commit
96d8e13c5a
2 files changed
+33
-10
No files matched your search
@@ -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
|
||||
|
||||
@@ -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})"
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user