From 0678cc8c48c9026c336d9348d1eb0f6a1fc284d7 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 14 Oct 2026 16:40:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(viperc/diag):=20=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E5=AE=9A=E4=BD=8D=E5=88=B0=E5=85=B7=E4=BD=93=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=20+=20=E6=A0=88=E5=B8=A7=E8=B7=9F=E8=B8=AA=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E8=AF=AD=E5=8F=A5=EF=BC=88=E6=96=B9=E6=A1=88=20A+B?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 即可得到“调用点 + 具体表达式”两帧。 --- App/lib/core/Gen/Call/CallGenLib.vp | 3 +++ App/lib/core/Gen/Stmt/StmtGenMixin.vp | 6 ++++++ App/lib/core/Gen/Type/TypeGenBase.vp | 24 ++++++++++++++++++++++++ App/lib/core/Gen/Type/TypeGenErr.vp | 10 ++++++++-- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/App/lib/core/Gen/Call/CallGenLib.vp b/App/lib/core/Gen/Call/CallGenLib.vp index 449824e..4a32cd0 100644 --- a/App/lib/core/Gen/Call/CallGenLib.vp +++ b/App/lib/core/Gen/Call/CallGenLib.vp @@ -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 diff --git a/App/lib/core/Gen/Stmt/StmtGenMixin.vp b/App/lib/core/Gen/Stmt/StmtGenMixin.vp index 5481afb..127448d 100644 --- a/App/lib/core/Gen/Stmt/StmtGenMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenMixin.vp @@ -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) diff --git a/App/lib/core/Gen/Type/TypeGenBase.vp b/App/lib/core/Gen/Type/TypeGenBase.vp index 951d83b..ab06724 100644 --- a/App/lib/core/Gen/Type/TypeGenBase.vp +++ b/App/lib/core/Gen/Type/TypeGenBase.vp @@ -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)): diff --git a/App/lib/core/Gen/Type/TypeGenErr.vp b/App/lib/core/Gen/Type/TypeGenErr.vp index 52f917c..0e4e710 100644 --- a/App/lib/core/Gen/Type/TypeGenErr.vp +++ b/App/lib/core/Gen/Type/TypeGenErr.vp @@ -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 = "" - # 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: