From 909d8ff0eb93bcd9190759d195c7a8528a4aeb02 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 10:46:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E8=AF=8A=E6=96=AD):=20=5Fget=5Fnode=5Finfo?= =?UTF-8?q?=20=E8=BF=98=E5=8E=9F=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=85=A5=20imp?= =?UTF-8?q?ort=20=E7=9A=84=E8=A1=8C=E5=81=8F=E7=A7=BB=EF=BC=9B=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=86=99=E5=85=A5=E5=A4=B1=E8=B4=A5=E8=A1=A5=E6=88=90?= =?UTF-8?q?=E5=91=98=E6=A7=BD=E6=9D=A5=E6=BA=90=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) 行号还原(b 机制缺陷,实测可证):Phase2Translator._inject_auto_imports 在源码头 注入 import _list/_dict/json,AST 节点行号整体下移 N (translator._line_offset = N),而 Gen._current_source_lines 是**磁盘**原文。 BaseGen._get_node_info / _DescribeValueNode 此前直接用 AST 行号读源码 ⇒ 同一次 fail-fast 里出现两套互相矛盾的行号:_ErrorStack 帧印磁盘行 1140/1141, _get_node_info 印 1142,并把源码显示成 1142 行的 `return "t.CPtr"` (真实错误行是 1141 的 `...LastBuiltinsTypedefResult = "t.CPtr"`,与被指语句无关)。 新增 BaseGen._DiskLineno,判据与 HandlesBase._FailFastFixedArrayKeyword:687、 HandlesAssign._RaiseGlobalAttrError:2051、LlvmGenerator/HandlesBody 的 _ErrorStack 各站点逐字一致;标签行号(_current_node_info)与源码行一并还原。 2) 成员槽来源明细:HandlesAssign 的「对象.字段 = 值」写入路径(:1182)此前 _StoreWithCoerce 失败时只报隐式转换禁令,不报目标槽来源,报文与被指语句、 偏移对不上。现与 `self.x = ...` 路径(:897-905)同口径补 _DescribeMemberSlot: 附上 class_members 声明侧(项数/base/表内下标/声明槽类型)与布局侧 (struct name/元素数/elements[offset])两侧数据,可直接判定是声明侧退化 还是布局侧退化(本次现场即"表内下标被同名继承项过滤移位"一类)。 --- lib/core/Handles/HandlesAssign.py | 17 ++++++++++++- lib/core/LLVMCG/BaseGen.py | 42 ++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 32bcd76..f617f74 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -1179,7 +1179,22 @@ class AssignHandle(BaseHandle): if isinstance(member_type, ir.IntType): Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}") - self._StoreWithCoerce(Value, MemberPtr) + # 成员槽写入失败时补「来源明细」(与 `self.x = ...` 路径 :897-905 + # 同一套 `_DescribeMemberSlot`):槽类型的两条独立来源 + # (class_members 声明侧 / struct body 布局侧)不一致时,值会被 + # 写进类型完全不同的槽(现场:`self.Gen.TypeGenCType. + # LastBuiltinsTypedefResult = "t.CPtr"` 落到 i32 槽 → 指针隐式 + # 转整数 fail-fast);报文里逐项列出两侧数据即可直接判定谁退化 + # (此处目标形态是 `对象.字段 = 值`,Base 侧同理取 ObjVal 所指布局)。 + try: + self._StoreWithCoerce(Value, MemberPtr) + except Exception as _Me: + from lib.core.LLVMCG.FuncGen import FailFastError as _FFE + if not isinstance(_Me, _FFE): + raise + raise _FFE( + f"{_Me}{self._DescribeMemberSlot(Gen, ClassName, AttrName, offset, ObjVal)}" + ) from _Me if not ClassName: imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None) resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 5178250..c08fd69 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -2,6 +2,7 @@ from __future__ import annotations from typing import Any import vast as ast import os +import re import llvmlite.ir as ir from lib.includes import t as _t from lib.includes.t import CTypeRegistry @@ -9,6 +10,10 @@ from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap from lib.core.SymbolUtils import EnumIntWidth, _ENUM_DEFAULT_INT_WIDTH from lib.constants.config import DEFAULT_HOTSPOT_CALLEES +# `_current_node_info` 的形态:"line N[, col C][ (额外)]"(由 _set_node_info 生成)。 +# _get_node_info 用它把标签行号还原成磁盘行号(见 _DiskLineno)。 +_LINE_INFO_RE: re.Pattern[str] = re.compile(r'line (\d+)(.*)\Z', re.S) + class VaArgInstruction(ir.Instruction): def descr(self, buf: list[str]) -> None: @@ -1213,13 +1218,39 @@ class BaseGenMixin: return self._current_source_lines[lineno - 1].rstrip('\r\n') return None + def _DiskLineno(self, Lineno: int) -> int: + """AST 行号 → 磁盘真实行号(减掉文件头自动注入 import 的行数)。 + + 判据与其余各处**逐字一致**(HandlesBase._FailFastFixedArrayKeyword:687、 + HandlesAssign._RaiseGlobalAttrError:2051、LlvmGenerator/HandlesBody 的 + _ErrorStack 各站点):Phase2Translator 在解析前用 _inject_auto_imports + 往源码头注入 `import _list/_dict/json`,AST 全部节点行号因此整体下移 N + (translator._line_offset = N);而 `Gen._current_source_lines` 是**磁盘** + 原文 ⇒ 任何"AST 行号 + 源码行"的输出都必须先减 N,否则印出的源码是下一行。 + 本渲染器此前漏还原,于是同一次 fail-fast 里出现两套矛盾行号 + (现场:真实错误在 TypeGenResolve.vp:1141 `= "t.CPtr"`, + _get_node_info 印 1142 且源码取到 1142 行的 `return "t.CPtr"`, + 而 _ErrorStack 帧印的是正确的 1141/1140)。 + """ + if Lineno <= 0: + return Lineno + _offset: int = int(getattr(self._Trans, '_line_offset', 0) or 0) + if _offset > 0 and Lineno > _offset: + return Lineno - _offset + return Lineno + def _get_node_info(self) -> str: info: str = "" if self._current_node_info: - info = f" [{self._current_node_info}]" + # 标签里的行号同样是 AST 行号:必须与下面的源码行**一起**还原, + # 否则标签(1142)与源码(1141)互相矛盾。 + _m = _LINE_INFO_RE.match(self._current_node_info) + _info: str = (f"line {self._DiskLineno(int(_m.group(1)))}{_m.group(2)}" + if _m is not None else self._current_node_info) + info = f" [{_info}]" if self._current_source_file: info += f" in {self._current_source_file}" - lineno: int = self._current_lineno + lineno: int = self._DiskLineno(self._current_lineno) if lineno > 0: info += f", line {lineno}:" source_line: str | None = self._get_source_line(lineno) @@ -1232,9 +1263,12 @@ class BaseGenMixin: 报文风格照本仓既有「表达式文本 + 位置 + 源码片段」: 表达式 ''(<节点形态>,位置 文件:行:列),源码: <该行> - 关键:**列号按有符号打印**——未知(无属性 / <0)时打印 '-',绝不把 col_offset + 关键 ①:**列号按有符号打印**——未知(无属性 / <0)时打印 '-',绝不把 col_offset 的 -1 当无符号打成 4294967295(此前 TPV 侧诊断错位的根因)。取不到节点时 回退当前语句上下文(_get_node_info 风格),不再固定打印外层 Assign。 + 关键 ②:**行号必须先还原为磁盘行号**(_DiskLineno)——节点行号含文件头 + 自动注入 import 的偏移,直接用来读源码会读到下一行(现场:真实错误行 + 1141,这里印成 1142 且源码显示出 1142 行的 `return "t.CPtr"`)。 """ if Node is None: return self._get_node_info() @@ -1244,7 +1278,7 @@ class BaseGenMixin: Expr = getattr(Node, 'attr', '') or getattr(Node, 'id', '') or '' RawLine: int = getattr(Node, 'lineno', 0) or 0 Col: Any = getattr(Node, 'col_offset', -1) - Line: int = RawLine or self._current_lineno or 0 + Line: int = self._DiskLineno(RawLine or self._current_lineno or 0) Loc: str = self._current_source_file or '' if Line > 0: Loc += f":{Line}"