From 393ffefcd5b5d402b12b67d86753f857f24e6bfe Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 15:14:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(HandlesAssign):=20self=20=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E5=86=99=E5=85=A5=E7=9A=84=E5=9F=BA=E5=9D=80=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E4=B8=BA=20=5FConcretizeGepBase=EF=BC=9B?= =?UTF-8?q?=E6=94=B6=E5=8F=A3=E5=A4=B1=E8=B4=A5=E4=B8=8D=E5=86=8D=E9=9D=99?= =?UTF-8?q?=E9=BB=98=E4=B8=A2=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类别:a(编译器缺陷)。 1) 收口统一:`self.字段 = v` 的基址此前走**内联**孪生体搜索,缺 `_TryLoadStructFromStub` 一步 —— 类键那份仍 opaque 且 Gen.structs 里尚无已具化 孪生体时(body 只在 stub 文件里待加载),内联版会一路走到 GEP 撞 opaque 守卫 (现场:includes/ast/astaux.vp:165 `self.arg = _copy_str(pool, arg)`,基址 pointee 是 opaque 的 %"8312ce86a2fd82c0.Keyword"*,而同短名 'Keyword' 键那份已具化 10 槽)。 现改为调用读路径的**同一判据源** HandlesExprAttr._ConcretizeGepBase / _ConcretePointeeFor:① 类键那份 + stub 补 body → ② 同短名已具化孪生体 → ③ 都拿不到则原样返回、由守卫报根因。偏移与 GEP 同源(返回实例同时作为 _get_member_offset 的 StructHint)。 2) 收口失败改 fail-fast:三条路都拿不到 elements 时,此前会落回 `offset >= max_offset` 的「存回临时变量」分支 —— 该临时变量不在对象布局里, 后续 `self.attr` 读路径按 GEP 取值,写入被**静默丢弃**。现直接 FailFastError, 并报出三次尝试的结果(不兜底)。 静态核验:py_compile 通过;全仓 symtable 未定义名扫描 0 条;以 _GuardIrBuilder + 真实 _ConcretizeGepBase 复现现场实例形状(opaque '8312ce86a2fd82c0.Keyword' + 已具化 'fef783da4d24330d.Keyword'(10 槽))→ 解析成功、GEP 正常发出(索引 3); 未收口的裸 opaque 基址仍被守卫拦下。 --- lib/core/Handles/HandlesAssign.py | 71 ++++++++++++------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index af74153..8eccb34 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -856,51 +856,36 @@ class AssignHandle(BaseHandle): FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") Gen._store(FuncPtrI8, MethodPtrAddr) return - # 自指针的 pointee 可能是**另一份同名 struct 实例**:函数签名里那份 - # 仍 opaque(`_get_or_create_struct` 早期创建、从未 set_body),而类键 - # `Gen.structs[ClassName]` 上那份已具化。typed pointer 的 GEP 必须在 - # 编译期算出元素类型 ⇒ 走 opaque pointee 时 llvmlite 在 - # `types.py:633 self.elements[i.constant]` 抛裸 TypeError - # ('NoneType' object is not subscriptable;现场:astaux.vp - # `Keyword.__init__` 的 `self.arg = _copy_str(pool, arg)`)。 - # 修法:先 bitcast 到**有 body 的那份实例**,再把该实例作为 - # StructHint 交给 `_get_member_offset` —— 偏移与 GEP 必须同源 - # (与属性读取路径 _gep_and_Load_member 的 415916b3 同口径)。 - _SelfPointee: ir.Type | None = None - if isinstance(SelfPtr.type, ir.PointerType): - _SelfPointee = SelfPtr.type.pointee - struct_type: ir.Type = Gen.structs[ClassName] - if (isinstance(_SelfPointee, ir.IdentifiedStructType) - and _SelfPointee.elements is None - and isinstance(struct_type, ir.IdentifiedStructType) - and struct_type.elements is not None): - SelfPtr = Gen.builder.bitcast( - SelfPtr, ir.PointerType(struct_type), - name=f"concrete_self_{ClassName}") - _SelfPointee = struct_type - # 孪生体搜索(治本,2026-09-30):类键实例可能**也是** opaque —— 同一类名 - # 常有两份 struct 实例(短名 'Keyword' / sha1 全名 '.Keyword'), - # 函数签名里的 self 用哪一份、StructGen 具化的是哪一份**并不保证一致**。 - # 现场:includes/ast/astaux.vp:165 `self.arg = _copy_str(pool, arg)` 的 - # 基址 pointee 是 opaque 的 `%".Keyword"*`,GEP 无法在编译期算元素类型。 - # 修法:按**同短名**取一份已具化实例(工具函数 _FindConcreteTwin,读路径 - # HandlesExprAttr 共用同一判据)并 bitcast —— 偏移与 GEP 由此同源。 - # 找不到 ⇒ 保持现状,交由 RequirePointerOperand 的 opaque 守卫 fail-fast - # (报出同短名实例清单,暴露"body 从未 set_body"),**不静默兜底**。 + # 自指针基址收口:与**读路径同一判据源**(HandlesExprAttr + # `_ConcretizeGepBase` / `_ConcretePointeeFor`),三步同源: + # ① 类键那份 opaque ⇒ 先 `_TryLoadStructFromStub` 补 body; + # ② 仍不可用 ⇒ 按同短名取一份已具化实例(`_FindConcreteTwin`); + # ③ 都拿不到 ⇒ 原样返回,由下方 opaque fail-fast 报根因。 + # 写路径此前是**内联**版本、缺 ①:类键那份仍 opaque 且 `Gen.structs` + # 里也还没有孪生体时(body 只在 stub 文件里待加载),内联版会一路走到 + # GEP 撞 opaque(现场 2026-09-30:includes/ast/astaux.vp:165 + # `self.arg = _copy_str(pool, arg)` 的基址 pointee 是 opaque 的 + # %"8312ce86a2fd82c0.Keyword"*,而同短名 'Keyword' 键那份已具化 10 槽)。 + # 偏移与 GEP 必须同源:返回的实例同时作为 `_get_member_offset` 的 StructHint。 + SelfPtr, _SelfPointee = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, SelfPtr, ClassName, f"concrete_self_{ClassName}") + struct_type: ir.Type = (_SelfPointee + if isinstance(_SelfPointee, ir.IdentifiedStructType) + else Gen.structs[ClassName]) if (isinstance(_SelfPointee, ir.IdentifiedStructType) and _SelfPointee.elements is None): - _Twin: ir.IdentifiedStructType | None = Gen._FindConcreteTwin(_SelfPointee) - if _Twin is None: - try: - _Twin = Gen._FindConcreteTwin(Gen.structs.get(ClassName)) - except Exception: - _Twin = None - if _Twin is not None: - SelfPtr = Gen.builder.bitcast( - SelfPtr, ir.PointerType(_Twin), - name=f"concrete_twin_self_{ClassName}") - _SelfPointee = _Twin - struct_type = _Twin + # 收口失败:类键那份、同短名孪生体、以及 `_TryLoadStructFromStub` + # 三条路都没拿到 body。**不得**再落回下方 `offset >= max_offset` + # 的「存回临时变量」分支 —— 该临时变量不在对象布局里,后续 + # `self.attr` 读路径按 GEP 取值,写入会被**静默丢弃**。此处 fail-fast。 + from lib.core.LLVMCG.FuncGen import FailFastError as _FFE0 + raise _FFE0( + f"属性写入 '{ClassName}.{AttrName}' 的 self 基址指向**未具化**" + f"结构体:'{getattr(_SelfPointee, 'name', '?')}'(opaque)。" + f"已尝试:类键 {ClassName!r} 的实例 → 同短名孪生体 → " + f"_TryLoadStructFromStub 补 body,均未拿到 elements。" + f"请查该类 body 为何从未 set_body(StructGen._generate_structs)。" + + (f"\n {Gen._get_node_info()}" if hasattr(Gen, '_get_node_info') else "")) offset: int = Gen._get_member_offset(AttrName, ClassName, _SelfPointee) max_offset: int = (len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType)