From a060e1d76ed3aa5c57056868b0f855f3b28fe021 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 14 Oct 2026 17:38:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(viperc):=20=E9=97=AD=E5=8C=85=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=8F=96=E5=9D=80=E8=BF=94=E5=9B=9E=E9=97=AD=E5=8C=85?= =?UTF-8?q?=E6=8C=87=E9=92=88=EF=BC=8C=E5=B9=B6=E8=AE=A9=E6=96=B9=E6=B3=95?= =?UTF-8?q?/=E6=9E=84=E9=80=A0=E5=AE=9E=E5=8F=82=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E5=AE=9A=E4=BD=8D=E5=88=B0=E5=85=B7=E4=BD=93?= =?UTF-8?q?=E5=AE=9E=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ExprGenOps 取址:嵌套 def 提升出的闭包变量在父函数里是 i8** 槽,&f 原来返回槽地址(二级),传给 callback: t.CPtr 会因级数不符报 CastError(source level 2 -> target level 1);现按闭包名表判定,返回其值 i8*(一级),与“函数名即地址(同 C)”一致 - CallGenCall._call_method_on_ptr:实参逐个转换原来统一传 node=None,失败时只能退回函数定义行(只剩一帧);现按 arg_nodes 带上每个实参自身的 AST 节点(slot 0 是 self),报错可定位到具体实参表达式并显示完整两帧 - TypeGenErr:移除定位用的 [TEMP-DIAG] 临时打印 --- App/lib/core/Gen/Call/CallGenCall.vp | 10 +++++++++- App/lib/core/Gen/Expr/ExprGenOps.vp | 8 ++++++++ App/lib/core/Gen/Type/TypeGenErr.vp | 9 --------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index 3bdd95a..7923625 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -485,19 +485,27 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): pc_node: mlirlite.Value* = head new_head_pc: mlirlite.Value* = head prev_pc: mlirlite.Value* = None + pc_idx: int = 0 while pc_node is not None: pc_next_save: mlirlite.Value* = pc_node.Next coerced_pc: mlirlite.Value* = pc_node + # 每个实参带上**它自己的 AST 节点**(arg_nodes 与链上 slot 1.. 对应,slot 0 是 + # self):转换失败时报错才能定位到这个实参表达式(如 `&_on_submit`),而不是 + # 因 node=None 退回"函数定义行"、只剩一帧。 + pc_arg_node: ast.AST* = node + if pc_idx >= 1 and arg_nodes is not None and (pc_idx - 1) < len(arg_nodes): + pc_arg_node = arg_nodes.get(pc_idx - 1) if pc_param is not None: pty_pc: mlirlite.LLVMType* = mlirlite.param_get_ty(pc_param) if pty_pc is not None: - c_pc: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, pc_node, pty_pc, None) + c_pc: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, pc_node, pty_pc, pc_arg_node) if c_pc is not None: coerced_pc = c_pc pc_param = mlirlite.param_get_next(pc_param) coerced_pc.Next = None if prev_pc is None: new_head_pc = coerced_pc else: prev_pc.Next = coerced_pc prev_pc = coerced_pc + pc_idx += 1 pc_node = pc_next_save head = new_head_pc diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index d547d42..4a47bde 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -755,6 +755,14 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): gv_ao: mlirlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(mod, nm_ao.id) if gv_ao is not None and gv_ao.Name is not None and gv_ao.Ty is not None: v_ao = self.Gen.ExprGenAttr.make_global_ref(pool, gv_ao.Name, gv_ao.Ty) if v_ao is not None and v_ao.Ty is not None: + # 闭包变量(嵌套 `def f()` 被提升后在父函数里是一个 **i8\*\*** 槽,见 + # FuncGenMixin.translate_nested_function_def 第 13e 步):变量自身就是那个 + # 函数的闭包指针,`&f` 应给出它的**值**(一级 i8*),而不是槽地址 i8**(二级) + # ——否则传给 `callback: t.CPtr` 会因级数不符报 CastError(source level 2 -> + # target level 1)。与“函数名即地址(同 C)”一致。闭包槽与普通函数指针变量 + # 同为 i8**、类型上无法区分,故用闭包名表判定(第 13e 步已登记该名字)。 + if self.Gen.CallGenLeafKit.is_closure_name(nm_ao.id) != 0 and v_ao.Ty.Pointee is not None: + return mlirlite.build_load(builder, v_ao.Ty.Pointee, v_ao) # Object-pointer variable (alloca is Ptr(Ptr(Struct))): the variable is the object, return the object pointer (load once), aligned with translate_c_addr. match v_ao.Ty: case mlirlite.LLVMType.Ptr(ao1): diff --git a/App/lib/core/Gen/Type/TypeGenErr.vp b/App/lib/core/Gen/Type/TypeGenErr.vp index 27dc554..d0aceb2 100644 --- a/App/lib/core/Gen/Type/TypeGenErr.vp +++ b/App/lib/core/Gen/Type/TypeGenErr.vp @@ -47,7 +47,6 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase): # 当前帧(错误点)位置:优先 node,其次调用栈最内层有行号的帧,最后 current_file。 lineno: int = 0 if node is not None: lineno = node.lineno - raw_line: int = lineno # [TEMP-DIAG] 兜底前的原始节点行号(定位完删除) file_name: str = self.Gen.TypeGenResolve.get_current_file() if file_name is None: file_name = "" # 报错位置兜底(“节点位置不可信”时优先用正在翻译的实参位置,精确定位到 @@ -85,14 +84,6 @@ novirtual class TypeGenErr(TypeGenBase.TypeGenBase): Diag.finish() return 0 - # [TEMP-DIAG] 定位“报错位置”问题用(定位完删除):把决策输入打出来 - # node=节点原始行号(0=合成) curarg=当前实参行号 trace=栈深 top=栈最内层行号 - ti_top: int = -1 - if self.Gen.TypeGenBase.TraceCount > 0: - tf_d: GenTypes.TraceFrame* = self.Gen.TypeGenBase._get_trace_frame(self.Gen.TypeGenBase.TraceCount - 1) - if tf_d is not None: ti_top = tf_d.lineno - stdio.printf("[TEMP-DIAG] node=%d curarg=%d trace=%d top=%d -> shown=%d\n", - raw_line, self.Gen.TypeGenBase.CurArgLine, self.Gen.TypeGenBase.TraceCount, ti_top, lineno) Diag.begin(ent, err_type, msg) # 调用链帧(按"自外向内"顺序)**由本类遍历**(只有它拿得到 TraceFrame),填入 entry。 for i in range(int(self.Gen.TypeGenBase.TraceCount)):