From a43513c9a7239418b1184c4f370c29ff3807b466 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 11:15:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(FuncGen):=20=E6=88=90=E5=91=98=E8=A1=A8?= =?UTF-8?q?=E4=B8=8E=20body=20=E7=AD=89=E9=95=BF=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E5=81=9A=E7=B1=BB=E5=9E=8B=E5=AF=B9=E9=BD=90=E6=A0=A1?= =?UTF-8?q?=E5=87=86=EF=BC=88base=20=E6=81=92=E4=B8=BA=200=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=20TypeGenMixin=20=E5=AD=97=E6=AE=B5=E5=81=8F?= =?UTF-8?q?=E7=A7=BB=E5=B9=B3=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 判据:_member_base 的 delta 长度启发式在 _Delta == 0 时给出 base=0(FuncGen.py:441), 而 base=2 **只可能**来自其后的"类型一致性校准"(:446-480,对 b∈{0,1,2} 逐项比类型取高分)。 但该校准用的是**严格类型相等**:声明侧的联合类型(如 `list[str] | t.CPtr`)可能被记成 折叠后的 i8*,而 body 槽仍是具体指针(`%list[str]*`)⇒ b=0 丢掉这些匹配,某个平移 b 却能靠指针槽互相撞分拿到更高分。 _Delta == 0(成员表项数 == body 槽数)本身就是"逐位对齐"(定义端 body 由成员表生成; 跨模块端 body(.stub.ll) 与 .vpi 同一声明顺序)⇒ base 必须为 0,此时不应再校准。 现场(本次):TypeGenMixin 41 成员 / 41 槽(@t.NoVTable,_Delta=0),base 被抬到 2 ⇒ Generator.vp:136 `SubTypeGen.Gen = self`(Gen 声明 `%"47382dc8277c9d28.Generator"*`、 正确槽为 0)写到槽 40(`%"6fbe68e8fca81223.TypeSpecArena"*`)⇒ "指针隐式转换已禁止(非基本类型(结构体/类/联合)):不能把指针类型 … 隐式转为 …"。 (该报文本身是上一提交 909d8ff0 补的"成员槽来源明细",这次正是靠它直接读出了 base/下标/声明槽类型/布局槽类型四项事实。) 附带:成员槽失败报文再补"名序"(_DescribeMemberSlot 打印 index:name 全表)——偏移算错时 第一现场就是"名序与 body 布局不同源",逐项列出即可直接判定是哪一侧漂移,不必再猜。 验证:py_compile 通过。_Delta != 0 的既有校准现场(ast.Constant 的 `cnst.lineno` 落到 pool 槽等)不受影响(本次只加前置条件,未改校准逻辑本身)。 --- lib/core/Handles/HandlesAssign.py | 6 ++++++ lib/core/LLVMCG/FuncGen.py | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index f617f74..5dca602 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -1624,6 +1624,12 @@ class AssignHandle(BaseHandle): Lines.append( f" class_members[{ClassName}] 项数={len(Members)} base={Base} " f"下标={Idx} 声明槽类型={Declared}") + # 名序(index:name):偏移=下标法/配对法算错时,第一现场就是"名序与 body + # 布局不同源"(如把某字段排到表尾/表头)。逐项列出即可直接与 body 槽对照, + # 不必再猜是哪一侧漂移(现场:TypeGenMixin 41 项里 'Gen' 本应在 0)。 + Lines.append(" class_members 名序: [" + + ", ".join(f"{_mi}:{_mn}" for _mi, (_mn, _) in enumerate(Members)) + + "]") except Exception as _e1: Lines.append(f" class_members 读取失败: {type(_e1).__name__}: {_e1}") Layout: Any = None diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index 95cf436..1d6c502 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -453,8 +453,20 @@ class FuncGenMixin: # 校准办法:对 b∈{0,1,2} 逐项比较"成员声明类型 vs elements[b+i] 类型", # 取一致度最高者(完全相同 +2;同为指针但类型不同 +0)。正确对齐时 # 指针槽几乎全中,错位对齐只能靠 i32 撞运气,分数明显更低;平手保留启发式。 + # + # 【只在长度不齐(_Delta != 0)时校准】_Delta == 0 表示"成员表项数 == body + # 槽数":定义端 body 由成员表生成、跨模块端 body(.stub.ll)与 .vpi 同源 + # (同一声明顺序),长度相等即**逐位对齐**,base 必为 0。此时再用严格类型 + # 比较挑 b 反而会误判——声明侧的联合类型(如 `list[str] | t.CPtr`)可能被记成 + # 折叠后的 i8*,而 body 槽仍是具体指针(`%list[str]*`):b=0 丢掉这些匹配, + # 某个平移 b 却能靠指针槽互相撞分拿到更高分。 + # 现场(2026-09-30):TypeGenMixin(41 成员 / 41 槽 / @t.NoVTable,_Delta=0) + # base 被抬到 2 ⇒ `SubTypeGen.Gen = self`(Gen 声明 Generator*、正确槽 0) + # 落到槽 40(TypeSpecArena*)⇒ "指针隐式转换已禁止(非基本类型(结构体/类/联合))"。 + # _Delta != 0 的既有现场(ast.Constant 的 `cnst.lineno` 落到 pool 槽等)不受影响, + # 仍走校准。 _MembersCal: list = self.class_members.get(_Cls, []) - if _MembersCal and _NumElems > 0: + if _MembersCal and _NumElems > 0 and _Delta != 0: _BestB: int = base _BestScore: int = -1 _HeurScore: int = -1