From a714ec9d37eefcd29b7f8cd642ba1ec3d35780e8 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 1 Oct 2026 20:45:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(VpiReader):=20=E8=BF=94=E5=9B=9E/=E5=BD=A2?= =?UTF-8?q?=E5=8F=82=E6=B3=A8=E8=A7=A3=E5=88=87=E5=88=86=E5=8F=AA=E5=9C=A8?= =?UTF-8?q?=E9=A1=B6=E5=B1=82=20`|`=20=E5=A4=84=E6=96=AD=E6=AE=B5=EF=BC=88?= =?UTF-8?q?=E6=8B=AC=E5=8F=B7=E6=84=9F=E7=9F=A5=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _resolve_vpi_ret_annot_str 原按裸 `|` 切段,`list[ast.AST | t.CPtr] | t.CPtr` 会被切成 `list[ast.AST` / `t.CPtr]` / `t.CPtr`;首段再经 strrchr('.') 落到 `AST` ⇒ 定义侧类型解析成 `AST*`(元素指针),而正确答案是 list 专化结构体的指针。现场:跨模块调用 coerce 时报 "源类型 list[AST*]* → 目标类型 AST*"(CallGenLib._coerce_args_to_def_params 的 cargs 形参)。 现切分按 `[`/`]` 深度,只在顶层 `|` 处断段(与 _cache_vpi_param_annots_text 的顶层逗号 切分同口径)。改后该段解析不出 ⇒ 落 i8* 通配,与 `list[str] | t.CPtr` 等同形注解的既有 行为一致;配合 CallGen 侧的 bitcast 对齐(见上一笔)即可安全使用。 --- App/lib/Stub/StubGen/VpiReader.vp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/App/lib/Stub/StubGen/VpiReader.vp b/App/lib/Stub/StubGen/VpiReader.vp index 987c4cd..6397fbc 100644 --- a/App/lib/Stub/StubGen/VpiReader.vp +++ b/App/lib/Stub/StubGen/VpiReader.vp @@ -1526,7 +1526,22 @@ def _resolve_vpi_ret_annot_str(pool: memhub.MemBuddy*, while pos < buf_len and ret_annot[pos] == ' ': pos += 1 seg_start: sizet = pos - while pos < buf_len and ret_annot[pos] != '|': + # 只在**顶层**切 `|`:`[...]` 内的 `|` 属于泛型实参内部的联合注解,裸切会把首段 + # 截成 `list[ast.AST`(来自 `list[ast.AST | t.CPtr] | t.CPtr`),该段再经 + # strrchr('.') 落到 `AST` ⇒ 定义侧解析成 `AST*`(元素的指针),而正确答案是 + # list 专化结构的指针(至少也应落 i8* 通配)。深度计数按 `[`/`]`,与 + # _cache_vpi_param_annots_text 的顶层逗号切分同口径。 + depth_ra: int = 0 + while pos < buf_len: + ch_ra: char = ret_annot[pos] + if ch_ra == '[': + depth_ra += 1 + elif ch_ra == ']': + if depth_ra > 0: + depth_ra -= 1 + elif ch_ra == '|': + if depth_ra == 0: + break pos += 1 seg_end: sizet = pos # trim 尾随空格