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:
TermiNexus committed 2026-09-30 19:31:21 +08:00
1 parent a7d8589af6
commit e2c84daa65
2 files changed
+38 -8

No files matched your search

+26 -3
View File
@@ -936,6 +936,23 @@ class ClassHandle(BaseHandle):
# 自有字段追加段的起点(供下方"字段名遮蔽"检查切分自有/继承两段; # 自有字段追加段的起点(供下方"字段名遮蔽"检查切分自有/继承两段;
# 此时 class_members[ClassName] 只含继承前缀,见 :825)。 # 此时 class_members[ClassName] 只含继承前缀,见 :825)。
_OwnFieldStart: int = len(Gen.class_members[ClassName]) _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: for item in Node.body:
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__) # 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
@@ -944,6 +961,9 @@ class ClassHandle(BaseHandle):
parsed = self.CollectAnnAssignMember(item, Gen) parsed = self.CollectAnnAssignMember(item, Gen)
if parsed: if parsed:
VarName, MemberType, TypeInfo = 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)) Gen.class_members[ClassName].append((VarName, MemberType))
# const / volatile 类字段登记(统一登记入口,见 BaseGen)。 # const / volatile 类字段登记(统一登记入口,见 BaseGen)。
# 键 `类名.字段名` + 裸字段名;与 TransPyV 侧 ClassGenDef 的 # 键 `类名.字段名` + 裸字段名;与 TransPyV 侧 ClassGenDef 的
@@ -2016,7 +2036,11 @@ class ClassHandle(BaseHandle):
return return
if ClassName not in Gen.class_members: if ClassName not in Gen.class_members:
Gen.class_members[ClassName] = [] 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) Gen._collecting_members_set.add(ClassName)
try: try:
for item in Node.body: for item in Node.body:
@@ -2028,10 +2052,9 @@ class ClassHandle(BaseHandle):
if not parsed: if not parsed:
continue continue
VarName, MemberType, TypeInfo = parsed VarName, MemberType, TypeInfo = parsed
if VarName in _Existing: if VarName in {n for n, _ in Gen.class_members[ClassName]}:
continue continue
Gen.class_members[ClassName].append((VarName, MemberType)) Gen.class_members[ClassName].append((VarName, MemberType))
_Existing.add(VarName)
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation) Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
_Signeds: dict = getattr(Gen, 'class_member_signeds', {}).get(ClassName) _Signeds: dict = getattr(Gen, 'class_member_signeds', {}).get(ClassName)
if isinstance(_Signeds, dict): if isinstance(_Signeds, dict):
+12 -5
View File
@@ -2315,7 +2315,16 @@ class ImportHandle(BaseHandle):
# 置入保护后重入的 _generate_structs 会跳过本类(StructGen.py:461), # 置入保护后重入的 _generate_structs 会跳过本类(StructGen.py:461),
# 待本节收集+展平完成后由下方显式 _generate_structs() 一次性 set_body。 # 待本节收集+展平完成后由下方显式 _generate_structs() 一次性 set_body。
Gen._collecting_members_set.add(ClassName) Gen._collecting_members_set.add(ClassName)
_existing_member_names = {m[0] for m in Gen.class_members[ClassName]} # 【防重 · 实时判据(2026-09-30)】原实现在此**快照一次**名字集合,循环内只
# 更新自己追加的项;而本循环每轮都可能重入同一张类表(CollectAnnAssignMember
# → ResolveAnnotationType → 泛型特化 → _generate_structs →
# _TryLoadClassMembersFromPyi(force=True) → 本文件 :3415 清空并按 .vpi 重填)
# ⇒ 快照即时失效,本循环会把**嵌套帧已经登记过的同一字段**再追加一条
# (现场:AST 的最后一个字段 `children` 因注解含泛型容器而触发该重入,
# 表变 8 项/去重 7 项;该表再被展平原样拷给 AST 的每个子类 ⇒ StructGen
# "[结构体布局] 成员表含重名条目"在大量 AST 子类上齐发)。
# 故改为**每轮实时读表**:判据语义("名字已在表里就不追加")与改前逐字相同,
# 只多看见循环中途出现的名字。
for item in Node.body: for item in Node.body:
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__) # 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
@@ -2325,18 +2334,16 @@ class ImportHandle(BaseHandle):
if parsed: if parsed:
VarName, MemberType, TypeInfo = parsed VarName, MemberType, TypeInfo = parsed
if TypeInfo is None: if TypeInfo is None:
if VarName not in _existing_member_names: if VarName not in {m[0] for m in Gen.class_members[ClassName]}:
Gen.class_members[ClassName].append((VarName, MemberType)) Gen.class_members[ClassName].append((VarName, MemberType))
_existing_member_names.add(VarName)
Gen.class_member_signeds[ClassName][VarName] = None Gen.class_member_signeds[ClassName][VarName] = None
Gen.class_member_bitfields[ClassName][VarName] = 0 Gen.class_member_bitfields[ClassName][VarName] = 0
else: else:
if TypeInfo.IsBitField: if TypeInfo.IsBitField:
Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth
else: else:
if VarName not in _existing_member_names: if VarName not in {m[0] for m in Gen.class_members[ClassName]}:
Gen.class_members[ClassName].append((VarName, MemberType)) Gen.class_members[ClassName].append((VarName, MemberType))
_existing_member_names.add(VarName)
Gen.class_member_bitfields[ClassName][VarName] = 0 Gen.class_member_bitfields[ClassName][VarName] = 0
# 与 HandlesClassDef 对齐:联合类型字段(如 `list[str] | t.CPtr`) # 与 HandlesClassDef 对齐:联合类型字段(如 `list[str] | t.CPtr`)
# 记录泛型特化名到 class_member_element_class。否则跨模块 import # 记录泛型特化名到 class_member_element_class。否则跨模块 import