feat(viperc/diag): 报错定位到具体表达式 + 栈帧跟踪当前语句(方案 A+B)
A:报错节点是合成节点(lineno==0,如构造器内联出的参数赋值)时,优先用“正在翻译的实参 位置”兜底 → 报错精确指向调用处的表达式(如 `&_on_submit`),不再退回函数定义行。 - TypeGenBase 新增 CurArgFile/CurArgLine/CurArgCol 与 set_cur_arg() - CallGenLib 翻译实参前调用 set_cur_arg(当前文件, arg_node 位置) - TypeGenErr 兜底顺序改为:节点自身行号 → CurArg → 栈最内层帧 - 语句边界清空 CurArg,避免兜底串味到上一条语句的实参 B:栈帧跟踪“当前语句”位置(Python traceback 口径) - TypeGenBase.update_top_trace_position():更新最内层帧的 lineno/col - translate_stmt 每条语句推进时调用 → 报错时栈帧给出的是调用点所在语句,而非函数定义行 配合 A 即可得到“调用点 + 具体表达式”两帧。
This commit is contained in:
1 parent
70c271d2a4
commit
0678cc8c48
4 files changed
+41
-2
No files matched your search
@@ -221,6 +221,9 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
if self.Gen.ExprGenBase._str_rejects_ptr_kind(cur) != 0:
|
||||
if VpiReader._vpi_param_annot_seg_is(sha1_buf, cls_nm, meth_nm, idx, "str") != 0 or VpiReader._vpi_param_annot_seg_is(sha1_buf, cls_nm, meth_nm, idx, "bytes") != 0:
|
||||
self.Gen.ExprGenBase.fail_if_str_annot_agg_ptr(cur, 1, arg_node)
|
||||
# 记录当前实参位置:被调者内部报错若是合成节点(无行号),可据此定位到这个实参表达式
|
||||
if arg_node is not None:
|
||||
self.Gen.TypeGenBase.set_cur_arg(self.Gen.TypeGenResolve.get_current_file(), arg_node.lineno, arg_node.col_offset + 1)
|
||||
node_v = self._coerce_arg_value_to_ty(pool, builder, node_v, tgt_ty, arg_node, trans, tpl_src)
|
||||
if new_head is None: new_head = node_v
|
||||
else: new_tail.Next = node_v
|
||||
|
||||
@@ -32,6 +32,12 @@ novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# define). Every instruction then carries ", !dbg !N".
|
||||
if node is not None and trans._cur_builder is not None:
|
||||
DebugInfoGen.SetStatement(trans.Pool, trans._cur_builder, node.lineno, node.col_offset + 1)
|
||||
# 让最内层栈帧跟踪“当前语句”位置:报错时栈帧给出的是调用点所在语句,而非函数定义行
|
||||
#(Python traceback 口径;配合 TypeGenBase.set_cur_arg 可得到“调用点 + 具体表达式”两帧)。
|
||||
if node is not None:
|
||||
self.Gen.TypeGenBase.update_top_trace_position(node.lineno, node.col_offset + 1)
|
||||
# 语句边界处清掉上一条语句遗留的实参位置,避免兜底定位“串味”到旧实参
|
||||
self.Gen.TypeGenBase.set_cur_arg(None, 0, 0)
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "statement translation nested too deeply (likely an AST self-reference cycle or a translation bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
mret: int = self._translate_stmt_impl(trans, node)
|
||||
|
||||
@@ -28,6 +28,11 @@ novirtual class TypeGenBase:
|
||||
Gen: Generator.Generator*
|
||||
TraceFrames: GenTypes.TraceFrame* # malloc array (TypeGenMixin.TRACE_MAX slots)
|
||||
TraceCount: int
|
||||
# --- 当前实参位置:翻译调用实参时记录。报错节点是**合成**的(lineno==0,如构造器内联出的
|
||||
# 参数赋值)时,用它兜底定位到具体表达式(如 `&_on_submit`),而不是回退到函数定义行。---
|
||||
CurArgFile: str
|
||||
CurArgLine: int
|
||||
CurArgCol: int
|
||||
|
||||
# --- Global generic specialization context (was _g_generic_tp_names/_g_generic_type_args) ---
|
||||
GenericTpNames: list[str]*
|
||||
@@ -107,6 +112,9 @@ novirtual class TypeGenBase:
|
||||
if self is None: return 1
|
||||
self.TraceFrames = None
|
||||
self.TraceCount = 0
|
||||
self.CurArgFile = None
|
||||
self.CurArgLine = 0
|
||||
self.CurArgCol = 0
|
||||
self.GenericTpNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self.GenericCtxStack = None
|
||||
@@ -199,6 +207,22 @@ novirtual class TypeGenBase:
|
||||
frame.lineno = 0
|
||||
frame.col_start = 0
|
||||
frame.col_end = 0
|
||||
# update_top_trace_position - 让最内层栈帧跟踪“当前语句”位置(Python traceback 口径:
|
||||
# 帧行号随语句推进而更新)。这样报错时栈帧给出的是**调用点所在语句**,而不是函数定义行;
|
||||
# 配合 set_cur_arg,即可得到“调用点 + 具体表达式”两帧。
|
||||
def update_top_trace_position(self, lineno: int, col_start: int) -> None:
|
||||
"""Track the current statement on the innermost trace frame."""
|
||||
if self.TraceCount <= 0 or lineno <= 0: return
|
||||
frame: GenTypes.TraceFrame* = self._get_trace_frame(self.TraceCount - 1)
|
||||
if frame is None: return
|
||||
frame.lineno = lineno
|
||||
frame.col_start = col_start
|
||||
# set_cur_arg - 记录正在翻译的实参位置(file/line/col),供“合成节点无行号”时兜底定位。
|
||||
def set_cur_arg(self, file_name: str, lineno: int, col_start: int) -> None:
|
||||
"""Remember the argument position currently being translated."""
|
||||
self.CurArgFile = file_name
|
||||
self.CurArgLine = lineno
|
||||
self.CurArgCol = col_start
|
||||
def clear_trace(self) -> None:
|
||||
"""Clear the trace stack (called before translating each file)."""
|
||||
for i in range(int(self.TraceCount)):
|
||||
|
||||
@@ -49,8 +49,14 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
if node is not None: lineno = node.lineno
|
||||
file_name: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if file_name is None: file_name = "<unknown>"
|
||||
# Line-number fallback: cloned/synthesized nodes may have lineno 0 (e.g. ast.Arg built by
|
||||
# generic specialization hardcodes 0). Fall back to the trace stack's last valid frame.
|
||||
# 合成节点无行号时的兜底顺序:
|
||||
# ① 正在翻译的实参位置(精确到 `&_on_submit` 这类表达式,见 TypeGenBase.set_cur_arg);
|
||||
# ② 调用栈最内层有行号的帧(现已随语句推进更新,给出调用点语句)。
|
||||
if lineno <= 0 and self.Gen.TypeGenBase.CurArgLine > 0:
|
||||
if self.Gen.TypeGenBase.CurArgFile is not None:
|
||||
file_name = self.Gen.TypeGenBase.CurArgFile
|
||||
lineno = self.Gen.TypeGenBase.CurArgLine
|
||||
col_start = self.Gen.TypeGenBase.CurArgCol
|
||||
if lineno <= 0 and self.Gen.TypeGenBase.TraceCount > 0:
|
||||
ti_b: int = self.Gen.TypeGenBase.TraceCount - 1
|
||||
while ti_b >= 0:
|
||||
|
||||
Reference in new issue
Block a user