diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 8ecb790..1da2993 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -2497,8 +2497,21 @@ class ImportHandle(BaseHandle): # 父类未加载到 class_members(常见于泛型特化基类如 GSListNode[Value], # 其特化不在 .pyi 中)。用 struct body 元素数推断继承字段数。 _st = Gen.structs.get(ClassName) + # 【必须先取快照】`elements` 不是稳定值:`StructGen._generate_structs` 判定 + # "struct body 与 class_members 不一致"时会**主动置 `elements = None`** + # (StructGen.py:579/:590,为强制重新派生的既有机制)。本分支在下方 + # `_ResolveInheritedFieldNames`(加载父类成员 → _TryLoadClassMembersFromPyi + # → _EmitExternalClassDeclLlvm → _generate_structs)里会重入,重入期间本类 + # 的 `elements` 可能被置回 None ⇒ 若在配对时(:2526)才读 `_st.elements`, + # 就是对 None 下标:裸 `TypeError: 'NoneType' object is not subscriptable` + # (2026-09-29 现场:astaux.vp 编译期 `_EmitExternalClassDeclLlvm` 崩, + # 外层 :647 `except Exception` 只 WARN "忽略节点 ClassDef" 就 continue ⇒ + # 该类声明被整条静默丢弃)。 + # 快照与 `_num_elements` 同源(都是 guard 通过的这一份 body),二者必须 + # 一致:槽位数与槽类型取自同一时刻的布局,不能一个用旧、一个用新。 if isinstance(_st, ir.IdentifiedStructType) and _st.elements is not None: - _num_elements = len(_st.elements) + _elements_ph: list = list(_st.elements) + _num_elements = len(_elements_ph) # 如果类有 vtable ptr(struct 首元素),需减去 1 # 否则 vtable ptr 会被误当成 __inherited_0 占位条目, # 导致子类继承时多出一个字段(如 Name(AST) 从 9 字段变成 10) @@ -2523,7 +2536,7 @@ class ImportHandle(BaseHandle): _inherited_ph: list[tuple] = [] for _i_ph in range(_num_inherited): _nm_ph: str = _inh_names[_i_ph] if _i_ph < len(_inh_names) else f'__inherited_{_i_ph}' - _inherited_ph.append((_nm_ph, _st.elements[_slot0_ph + _i_ph])) + _inherited_ph.append((_nm_ph, _elements_ph[_slot0_ph + _i_ph])) # 占位符路径同样整体前置(继承字段在 struct 头部),与主路径保持一致 Gen.class_members[ClassName] = _inherited_ph + Gen.class_members[ClassName] _placeholder_applied = True