From 9afd6a45ed0396c7edbca3c0f57409c97e746a9f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 15:44:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(HandlesClassDef/HandlesImports):=20?= =?UTF-8?q?=E5=B1=95=E5=B9=B3=E5=9D=97=E5=B9=82=E7=AD=89=E2=80=94=E2=80=94?= =?UTF-8?q?=E5=9D=97=E5=B7=B2=E6=95=B4=E6=AE=B5=E5=9C=A8=E8=A1=A8=E5=A4=B4?= =?UTF-8?q?/=E5=B0=BE=E6=97=B6=E4=B8=8D=E5=86=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=8F=92=E5=85=A5=EF=BC=88=E4=BF=AE=2041=E2=86=9273=20?= =?UTF-8?q?=E7=9A=84=20body=20=E5=88=86=E5=8F=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别:a(编译器缺陷,且已泄漏进 emit 的 IR)。 on-disk 实证:Phase 1 声明(temp/.stub.ll)与 Phase 2 emit(output/.stub.ll) 对同一类的 body 槽数不一致,共 7 个类,全在 Generator/ClassGen/TypeGen 继承链上: TypeGenCType 41 → 73(+32) TypeGenCDef 41 → 73 TypeGenErr 41 → 73 ClassGenMixin 42 → 50(+8) ClassGenVTable 42 → 50 ClassGenEnum 42 → 50 ClassGenDef 42 → 50 逐槽比对:output[0:41] == temp,且 **output[41:73] == temp[9:41]** —— 多出的 32 槽 正是"追加前那张表**尾部** 32 项的原样副本"。下游即 Repl.vp:802 `GenApi._g_gen.TypeGenCType.CTypedefNames` 因两份 body(41/73)歧义而 "基座 pointee 未匹配 Gen.structs 中任何 struct"。 成因:两条展平路径判据**不对称**—— - 导入侧 `PrependInheritedBlock`:前置,且自带"表头是否等于块"的幂等判据; - 定义侧 HandlesClassDef 展平:直接 `class_members + _flat` **追加**,**无任何判据**。 一旦块已整段位于表尾(或表中段),就会被再插一次,表里多出 len(块) 条重复条目, body 随之多出同名槽。 修法:新增唯一判据源 `HandlesImports.InheritedBlockAlreadyPresent(Table, Block)`—— "块是否整段位于 `Table` 的**头部或尾部**(名字 + IR 类型逐项相同)", 两个插入点都接它(导入侧前置 ⇒ 头部;定义侧追加 ⇒ 尾部)。 刻意**不判表中段**:中段的同序列与"合法的同名并存"(子类在自有段重复声明父类字段, body 本来就有两个槽)不可区分,判成"已存在"会误删本该有的槽;真出现中段重复时 仍由 StructGen 的重名条目告警兜住。跳过重复时打印一行 WARN(类名 / 块长 / 表长), 只跳过重复、不改其余布局。 冒烟(内联 python,无临时文件):现场形状(块 = 表[9:41])→ True;中段 → False; 仅名字相同而类型不同 → False;空块 / 块比表长 / 非 tuple 条目 → False。 静态核验:compileall 通过;全仓 symtable 未定义名扫描 0 条。 --- lib/core/Handles/HandlesClassDef.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 8794dc3..342b73e 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -823,7 +823,24 @@ class ClassHandle(BaseHandle): continue _FlattenInherited(ParentClass, _seen_cls, _flat, Gen) if _flat: - Gen.class_members[ClassName] = Gen.class_members[ClassName] + _flat + # 【幂等(2026-09-30)】该祖先块已作为**连续整段**存在于本表时不再追加: + # 本处是**追加**(`class_members + _flat`),与导入侧的 + # `PrependInheritedBlock`(前置,自带表头判据)判据不对称,"块已在表中段/ + # 尾部"的情形谁都不判 ⇒ 整块再插一次,表里多出 len(_flat) 条重复条目, + # body 随之多出同名槽(现场:output/.stub.ll 的 TypeGenCType 73 槽 + # = temp 声明 41 槽 + 其 [9:41] 的原样副本;同族 7 个类, + # 下游即 Repl.vp:802 的"基座 pointee 未匹配任何 struct")。 + # 判据(名字 + IR 类型逐项连续匹配)与成因见 + # HandlesImports.InheritedBlockAlreadyPresent;只跳过重复、不改其余布局。 + from lib.core.Handles.HandlesImports import InheritedBlockAlreadyPresent as _BlkPresent + if _BlkPresent(list(Gen.class_members[ClassName]), _flat): + _vlog().warning( + f"[成员展平] 类 '{ClassName}' 的祖先块({len(_flat)} 项)已存在于成员表" + f"(表 {len(Gen.class_members[ClassName])} 项)⇒ 跳过重复追加" + f"(重复会让 body 多出同名槽、与 Phase 1 声明布局分叉)", + "成员展平") + else: + Gen.class_members[ClassName] = Gen.class_members[ClassName] + _flat # ============================================================ # 多继承方法合并:遍历所有父类(声明顺序)收集方法(短名去重,先声明父类优先), # vtable 槽/方法名用"实际定义类.方法"(如 B.get_b,与 TPV 一致),