fix(Handles): 成员表登记改实时按名判重,消成员表重名条目(AST.children 重复)
类体字段收集循环每轮都可能重入并清空重填同一张成员表(CollectAnnAssignMember → 泛型特化 → _generate_structs → _TryLoadClassMembersFromPyi(force=True) → HandlesImports.py:3415,该 force 分支不受字段收集中保护),而三处只在循环前快照一次名字集合的判据即时失效,会把嵌套帧已登记的同一字段再追加一条:AST 的最后一个字段 children(注解含 list[...] 泛型容器,是全类唯一触发该重入的字段)被登记两次 ⇒ 表 8 项/去重 7 项、重名条目 children@7;该表再被祖先块展平原样拷给 AST 的每个子类 ⇒ StructGen「[结构体布局] 成员表含重名条目」在大量 AST 子类(ExprNode/Stmt/MatchCase/ExceptHandler…)上齐发。三处一律改为实时读表判重(HandlesClassDef 自有字段段与 _PreRegisterClassMembers、HandlesImports 跨模块自有字段段),判据语义与改前逐字相同;自有字段段刻意只跳过本轮循环开始后才出现的同名,以保住字段名遮蔽 fail-fast 与既有布局语义。
This commit is contained in:
1 parent
a7d8589af6
commit
e2c84daa65
2 files changed
+38
-8
No files matched your search
@@ -936,6 +936,23 @@ class ClassHandle(BaseHandle):
|
||||
# 自有字段追加段的起点(供下方"字段名遮蔽"检查切分自有/继承两段;
|
||||
# 此时 class_members[ClassName] 只含继承前缀,见 :825)。
|
||||
_OwnFieldStart: int = len(Gen.class_members[ClassName])
|
||||
# 【嵌套重入防重(2026-09-30)】本循环**每轮都可能重入**同一张表:
|
||||
# CollectAnnAssignMember → ResolveAnnotationType → 泛型特化(list[X] 等)
|
||||
# → _generate_structs / _TryLoadClassMembersFromPyi → _EmitExternalClassDeclLlvm
|
||||
# → 可按 .vpi **清空并重填**本类成员表(HandlesImports.py:3408 的 force 分支,
|
||||
# 由 HandlesImports.py:2647/2654 与 FuncGen.py:1057 触发;该分支不受
|
||||
# "字段收集中"保护,见 HandlesImports.py:3299 的 `not force` 豁免)。
|
||||
# 此时本循环后面的 `append` 会把**嵌套帧已经登记过的同一字段**再写一条 ——
|
||||
# 现场:AST 的最后一个字段 `children: list[rawptr[AST]] | t.CPtr` 是全类唯一
|
||||
# 触发泛型特化的注解,处理它时嵌套帧重填了 AST 表(7 项),本循环恢复后
|
||||
# 又追加一次 `children` ⇒ 表 8 项 / 去重 7 项,重名条目 `children@7`;
|
||||
# 该表又被祖先块展平**原样拷贝**给 AST 的每个子类(_FlattenInherited 只按
|
||||
# 祖先名过滤、不按名去重)⇒ StructGen 的"[结构体布局] 成员表含重名条目"
|
||||
# 在大量 AST 子类上齐发(AST/Stmt/ExprNode/MatchCase/ExceptHandler…)。
|
||||
# 判据刻意收窄:**只跳过"本轮循环开始之后才出现"的同名条目**(嵌套帧刚登记
|
||||
# 的那条)。循环前已在表里的同名(继承前缀/同名字段)照旧追加 ⇒ 上方
|
||||
# "字段名遮蔽"fail-fast 的判据(自有段切分)与既有布局语义逐字不变。
|
||||
_StartNames: set[str] = {m[0] for m in Gen.class_members[ClassName]}
|
||||
for item in Node.body:
|
||||
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
@@ -944,6 +961,9 @@ class ClassHandle(BaseHandle):
|
||||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
if VarName not in _StartNames \
|
||||
and VarName in {m[0] for m in Gen.class_members[ClassName]}:
|
||||
continue
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
# const / volatile 类字段登记(统一登记入口,见 BaseGen)。
|
||||
# 键 `类名.字段名` + 裸字段名;与 TransPyV 侧 ClassGenDef 的
|
||||
@@ -2016,7 +2036,11 @@ class ClassHandle(BaseHandle):
|
||||
return
|
||||
if ClassName not in Gen.class_members:
|
||||
Gen.class_members[ClassName] = []
|
||||
_Existing: set[str] = {n for n, _ in Gen.class_members[ClassName]}
|
||||
# 【防重 · 实时判据(2026-09-30)】原实现循环前快照一次名字集合,循环内只更新
|
||||
# 自己追加的项;而 CollectAnnAssignMember 每轮都可能重入并**清空重填**本类表
|
||||
# (泛型特化 → _generate_structs → _TryLoadClassMembersFromPyi(force=True) →
|
||||
# HandlesImports.py:3415)⇒ 快照失效后会重复追加同一字段。改为每轮实时读表,
|
||||
# 判据语义("名字已在表里就不追加")与改前逐字相同。
|
||||
Gen._collecting_members_set.add(ClassName)
|
||||
try:
|
||||
for item in Node.body:
|
||||
@@ -2028,10 +2052,9 @@ class ClassHandle(BaseHandle):
|
||||
if not parsed:
|
||||
continue
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
if VarName in _Existing:
|
||||
if VarName in {n for n, _ in Gen.class_members[ClassName]}:
|
||||
continue
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
_Existing.add(VarName)
|
||||
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
|
||||
_Signeds: dict = getattr(Gen, 'class_member_signeds', {}).get(ClassName)
|
||||
if isinstance(_Signeds, dict):
|
||||
|
||||
Reference in new issue
Block a user