fix(诊断): _get_node_info 还原自动注入 import 的行偏移;属性写入失败补成员槽来源明细

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])两侧数据,可直接判定是声明侧退化
   还是布局侧退化(本次现场即"表内下标被同名继承项过滤移位"一类)。
This commit is contained in:
TermiNexus committed 2026-09-30 10:46:42 +08:00
1 parent a18ca4da3b
commit 909d8ff0eb
2 files changed
+53 -4

No files matched your search

+15
View File
@@ -1179,7 +1179,22 @@ class AssignHandle(BaseHandle):
if isinstance(member_type, ir.IntType): if isinstance(member_type, ir.IntType):
Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}") Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}")
# 成员槽写入失败时补「来源明细」(与 `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) 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: if not ClassName:
imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None) imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None)
resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName)
+38 -4
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
from typing import Any from typing import Any
import vast as ast import vast as ast
import os import os
import re
import llvmlite.ir as ir import llvmlite.ir as ir
from lib.includes import t as _t from lib.includes import t as _t
from lib.includes.t import CTypeRegistry 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.core.SymbolUtils import EnumIntWidth, _ENUM_DEFAULT_INT_WIDTH
from lib.constants.config import DEFAULT_HOTSPOT_CALLEES 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): class VaArgInstruction(ir.Instruction):
def descr(self, buf: list[str]) -> None: def descr(self, buf: list[str]) -> None:
@@ -1213,13 +1218,39 @@ class BaseGenMixin:
return self._current_source_lines[lineno - 1].rstrip('\r\n') return self._current_source_lines[lineno - 1].rstrip('\r\n')
return None 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: def _get_node_info(self) -> str:
info: str = "" info: str = ""
if self._current_node_info: 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: if self._current_source_file:
info += f" in {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: if lineno > 0:
info += f", line {lineno}:" info += f", line {lineno}:"
source_line: str | None = self._get_source_line(lineno) source_line: str | None = self._get_source_line(lineno)
@@ -1232,9 +1263,12 @@ class BaseGenMixin:
报文风格照本仓既有「表达式文本 + 位置 + 源码片段」: 报文风格照本仓既有「表达式文本 + 位置 + 源码片段」:
表达式 '<unparse>'(<节点形态>,位置 文件:行:列),源码: <该行> 表达式 '<unparse>'(<节点形态>,位置 文件:行:列),源码: <该行>
关键:**列号按有符号打印**——未知(无属性 / <0)时打印 '-',绝不把 col_offset 关键 ①:**列号按有符号打印**——未知(无属性 / <0)时打印 '-',绝不把 col_offset
的 -1 当无符号打成 4294967295(此前 TPV 侧诊断错位的根因)。取不到节点时 的 -1 当无符号打成 4294967295(此前 TPV 侧诊断错位的根因)。取不到节点时
回退当前语句上下文(_get_node_info 风格),不再固定打印外层 Assign。 回退当前语句上下文(_get_node_info 风格),不再固定打印外层 Assign。
关键 ②:**行号必须先还原为磁盘行号**(_DiskLineno)——节点行号含文件头
自动注入 import 的偏移,直接用来读源码会读到下一行(现场:真实错误行
1141,这里印成 1142 且源码显示出 1142 行的 `return "t.CPtr"`)。
""" """
if Node is None: if Node is None:
return self._get_node_info() return self._get_node_info()
@@ -1244,7 +1278,7 @@ class BaseGenMixin:
Expr = getattr(Node, 'attr', '') or getattr(Node, 'id', '') or '<expr>' Expr = getattr(Node, 'attr', '') or getattr(Node, 'id', '') or '<expr>'
RawLine: int = getattr(Node, 'lineno', 0) or 0 RawLine: int = getattr(Node, 'lineno', 0) or 0
Col: Any = getattr(Node, 'col_offset', -1) 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 '' Loc: str = self._current_source_file or ''
if Line > 0: if Line > 0:
Loc += f":{Line}" Loc += f":{Line}"