diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 645c728..e0d3475 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -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): diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 3fbb542..bf7ff8c 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -2315,7 +2315,16 @@ class ImportHandle(BaseHandle): # 置入保护后重入的 _generate_structs 会跳过本类(StructGen.py:461), # 待本节收集+展平完成后由下方显式 _generate_structs() 一次性 set_body。 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: # 跳过编译期元数据字段(__provides__/__requires__/__require_must__) if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): @@ -2325,18 +2334,16 @@ class ImportHandle(BaseHandle): if parsed: VarName, MemberType, TypeInfo = parsed 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)) - _existing_member_names.add(VarName) Gen.class_member_signeds[ClassName][VarName] = None Gen.class_member_bitfields[ClassName][VarName] = 0 else: if TypeInfo.IsBitField: Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth 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)) - _existing_member_names.add(VarName) Gen.class_member_bitfields[ClassName][VarName] = 0 # 与 HandlesClassDef 对齐:联合类型字段(如 `list[str] | t.CPtr`) # 记录泛型特化名到 class_member_element_class。否则跨模块 import