fix(tpc): 继承前缀配槽改用 elements 快照,不再对已被重置为 None 的 body 下标
类别:a(编译器缺陷)—— 裸 Python TypeError 崩溃 + 外层静默吞掉整条类声明。 现场:编译 includes/ast/astaux.vp 时 HandlesImports.py:2526 `_inherited_ph.append((_nm_ph, _st.elements[_slot0_ph + _i_ph]))` → TypeError: 'NoneType' object is not subscriptable (栈由 VLogger.warning 打印 exc_info 后首次可见;外层 HandlesImports.py:647 `except Exception` 只 WARN "忽略节点 ClassDef" 就 continue ⇒ 该类声明整条 被静默丢弃,类型解析退化。) 根因(TOCTOU):guard 在 :2500 通过(elements is not None),但两侧之间 `_ResolveInheritedFieldNames`(:2535)会加载父类成员: _ResolveInheritedFieldNames → _TryLoadClassMembersFromPyi → _EmitExternalClassDeclLlvm → _generate_structs 而 `_generate_structs` 判定"struct body 与 class_members 不一致"时会**主动** `existing_st.elements = None`(StructGen.py:579/:590,既有机制,为强制重新派生) ⇒ 配对时读到的 elements 已变 None。 修复:guard 通过时立即对 elements 取快照 `_elements_ph`,槽位数与槽位类型取自 **同一时刻**的布局(`_num_elements` 本就取自它,二者必须同源);配对用快照, 不再触碰可能被重入重置的 `_st.elements`。无重入时行为与改前逐字节一致。
This commit is contained in:
1 parent
24573e5af6
commit
467e62a45e
1 file changed
+15
-2
@@ -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
|
||||
|
||||
Reference in new issue
Block a user