fix(FuncGen): 成员表与 body 等长时不再做类型对齐校准(base 恒为 0),修 TypeGenMixin 字段偏移平移

判据:_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 槽等)不受影响(本次只加前置条件,未改校准逻辑本身)。
This commit is contained in:
TermiNexus committed 2026-09-30 11:15:58 +08:00
1 parent de89fda73d
commit a43513c9a7
2 files changed
+19 -1

No files matched your search

+6
View File
@@ -1624,6 +1624,12 @@ class AssignHandle(BaseHandle):
Lines.append( Lines.append(
f" class_members[{ClassName}] 项数={len(Members)} base={Base} " f" class_members[{ClassName}] 项数={len(Members)} base={Base} "
f"下标={Idx} 声明槽类型={Declared}") 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: except Exception as _e1:
Lines.append(f" class_members 读取失败: {type(_e1).__name__}: {_e1}") Lines.append(f" class_members 读取失败: {type(_e1).__name__}: {_e1}")
Layout: Any = None Layout: Any = None
+13 -1
View File
@@ -453,8 +453,20 @@ class FuncGenMixin:
# 校准办法:对 b∈{0,1,2} 逐项比较"成员声明类型 vs elements[b+i] 类型", # 校准办法:对 b∈{0,1,2} 逐项比较"成员声明类型 vs elements[b+i] 类型",
# 取一致度最高者(完全相同 +2;同为指针但类型不同 +0)。正确对齐时 # 取一致度最高者(完全相同 +2;同为指针但类型不同 +0)。正确对齐时
# 指针槽几乎全中,错位对齐只能靠 i32 撞运气,分数明显更低;平手保留启发式。 # 指针槽几乎全中,错位对齐只能靠 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, []) _MembersCal: list = self.class_members.get(_Cls, [])
if _MembersCal and _NumElems > 0: if _MembersCal and _NumElems > 0 and _Delta != 0:
_BestB: int = base _BestB: int = base
_BestScore: int = -1 _BestScore: int = -1
_HeurScore: int = -1 _HeurScore: int = -1