From 00edd90c28a568e412685008c8372702c8b3ee4e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 14:42:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(Handles*):=20GEP=20=E5=9F=BA=E5=9D=80=20opa?= =?UTF-8?q?que=20pointee=20=E6=94=B6=E5=8F=A3=E7=BB=9F=E4=B8=80=E4=B8=BA?= =?UTF-8?q?=E5=8D=95=E4=B8=80=E5=88=A4=E6=8D=AE=E6=BA=90=EF=BC=8C=E8=A1=A5?= =?UTF-8?q?=E9=BD=90=E5=90=8C=E6=97=8F=2012=20=E5=A4=84=E7=BC=BA=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【a 编译器缺陷】7aa12263 修好 `_get_attr_ptr` 的 self 分支后,同族其余 GEP 点仍会在 "基址 pointee 是另一份 opaque 同名实例"时抛裸 TypeError(被 IR 边界守卫拦下,报文为 "GEP 的基址指向**未具化**的具名结构体")。根因是同一套收口逻辑被各点各写一份、且 **多数点根本没写**:真正需要的判据只有一条。 新增唯一判据源(HandlesExprAttr): · `_ConcretePointeeFor(Gen, ClassName, Pointee)`:取该类的**已具化实例** —— ① 类键那份先 `_TryLoadStructFromStub` 补 body;② 否则 `Gen._FindConcreteTwin` (同短名、槽数最多);③ 都取不到 ⇒ None(**不兜底**,交守卫 fail-fast 报同短名 实例清单 + TPC 发射点)。 · `_ConcretizeGepBase(Gen, Ptr, ClassName, Tag)`:pointee 非 opaque ⇒ 原样返回 (对既有正确路径零变化);opaque ⇒ bitcast 到已具化实例并**同时返回该实例**, 供 `_get_member_offset` 作 StructHint(偏移与 GEP 必须同源,与 a43513c9 同口径)。 接入点(全部改为调用上述判据源,逐点行为只在"原本必崩"的情形下变化): · HandlesExprAttr._get_attr_ptr — self / 变量 / 属性链 / i8* / 下标 / 强转基座 六条分支 (self 分支已由 7aa12263 修,此处并入统一判据;下标分支此前**完全没有**收口); · HandlesAnnAssign._HandleAttributeStoreLlvm — self / 变量 / 属性链 三条分支; · HandlesBase._get_int_ptr — 属性分支; · HandlesExprBuiltin(len() 的两个接收者 GEP:`obj.len` 与 list 特化字段); · HandlesMatch — REnum 变体 match 的载荷 GEP(变体 struct 可能未 set_body)。 冒烟(临时脚本已删,鸭子类型 Gen + 真实方法): · `_get_attr_ptr` self 分支 ⇒ 基址 `%"fef783da4d24330d.Keyword"*`(经 cast_self_Keyword)PASS; · `_get_attr_ptr` i8* 分支 ⇒ 同上 PASS; · `HandlesAnnAssign` self 分支 ⇒ GEP 基址为已具化实例 PASS; · 回归:基址本就具化时必须**原样**(不得多出 bitcast)PASS。 另:`python -m compileall TransPyC/lib` 全绿。 --- lib/core/Handles/HandlesAnnAssign.py | 37 ++++++-- lib/core/Handles/HandlesBase.py | 7 +- lib/core/Handles/HandlesExprAttr.py | 126 ++++++++++++++++--------- lib/core/Handles/HandlesExprBuiltin.py | 14 ++- lib/core/Handles/HandlesMatch.py | 9 +- 5 files changed, 133 insertions(+), 60 deletions(-) diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 36691b7..49edd1c 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -96,9 +96,16 @@ class AnnAssignHandle(BaseHandle): SelfVar: ir.Value | None = Gen._get_var_ptr('self') if SelfVar: SelfPtr: ir.Value = Gen._load(SelfVar, name="self") - offset: int = Gen._get_member_offset(AttrName, ClassName) - MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) + # 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase):self 的 pointee + # 可能是**另一份 opaque 同名实例**(函数签名那份),typed pointer 下 + # GEP 必须编译期算出元素类型 ⇒ 先补 body / 取同短名孪生体再 GEP。 + _SP: Any + SelfPtr, _SP = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, SelfPtr, ClassName, f"cast_self_{ClassName}") + offset: int = Gen._get_member_offset(AttrName, ClassName, _SP) + if offset is not None: + MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) elif isinstance(Target.value, ast.Name): VarName: str = Target.value.id @@ -193,6 +200,12 @@ class AnnAssignHandle(BaseHandle): and '[' in ClassName): ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_spec_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: + # 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase):类键那份可能 + # 仍是 opaque(body 未 set_body / 另一份实例已具化)⇒ 先补 body / + # 取同短名孪生体,偏移与 GEP 同源。 + _STa: Any + ObjVal, _STa = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, ObjVal, ClassName, f"cast_{ClassName}") if IsUnion: NestedStructName: str = f"{ClassName}_{AttrName}" if NestedStructName in Gen.structs: @@ -203,9 +216,10 @@ class AnnAssignHandle(BaseHandle): MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) self._StoreWithCoerce(Value, MemberPtr) return - offset: int = Gen._get_member_offset(AttrName, ClassName) - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) + offset: int = Gen._get_member_offset(AttrName, ClassName, _STa) + if offset is not None: + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) elif isinstance(Target.value, ast.Attribute): ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal and isinstance(ObjVal.type, ir.PointerType): @@ -213,9 +227,14 @@ class AnnAssignHandle(BaseHandle): if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: - offset: int = Gen._get_member_offset(AttrName, CN) - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) + # 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase) + _STb: Any + ObjVal, _STb = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, ObjVal, CN, f"cast_{CN}") + offset: int = Gen._get_member_offset(AttrName, CN, _STb) + if offset is not None: + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) break def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value, Node: ast.AST | None = None) -> None: diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index 10ce8fc..a3baa1e 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -810,7 +810,12 @@ class BaseHandle: StructName = ClassName break if StructName and StructName in Gen.structs: - offset: int = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen) + # 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase):pointee 可能是 + # **另一份 opaque 同名实例**,typed pointer 下 GEP 必须编译期算出 + # 元素类型 ⇒ 先补 body / 取同短名孪生体,并以该实例算偏移(同源)。 + obj_val, _STk = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, obj_val, StructName, f"cast_{StructName}") + offset: int = Gen._get_member_offset(Node.attr, StructName, _STk) member_ptr: Any = Gen.builder.gep(obj_val, [_ir.Constant(_ir.IntType(32), 0), _ir.Constant(_ir.IntType(32), offset)], name=f"{Node.attr}_ptr") return member_ptr return None diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index 875061a..b1ecbf3 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -1772,6 +1772,54 @@ class ExprAttrHandle(BaseHandle): # ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ========== + def _ConcretePointeeFor(self, Gen: LlvmCodeGenerator, ClassName: str | None, + Pointee: Any) -> Any: + """取该类的**已具化实例**(GEP 基址可用的那份):类键那份 → 同短名孪生体 → None。 + + 为什么需要:同一类名常有两份 struct 实例(短名 'Keyword' / sha1 全名 + '.Keyword'),"函数签名里的 self 用哪一份"与"StructGen 具化的是哪一份" + 并不保证一致;typed pointer 下 GEP 必须在**编译期**从 pointee 算元素类型, + 撞 opaque 即抛裸 TypeError('NoneType' object is not subscriptable)。 + + 判据(全仓同族点同一套,不引入新判据): + ① 类键那份(`Gen.structs[ClassName]`)可经 `_TryLoadStructFromStub` 补出 body; + ② 否则按**同短名**取一份已具化实例(`Gen._FindConcreteTwin`,槽数最多); + ③ 都拿不到 ⇒ None(**不兜底**,交 IR 边界守卫 fail-fast 报同短名实例清单)。 + """ + _Twin: Any = None + if ClassName: + _ST: Any = Gen.structs.get(ClassName) + if isinstance(_ST, ir.IdentifiedStructType) and not _ST.elements: + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + _ST = Gen.structs.get(ClassName, _ST) + if isinstance(_ST, ir.IdentifiedStructType) and _ST.elements: + _Twin = _ST + if _Twin is None and isinstance(Pointee, ir.IdentifiedStructType): + try: + _Twin = Gen._FindConcreteTwin(Pointee) + except Exception: + _Twin = None + return _Twin + + def _ConcretizeGepBase(self, Gen: LlvmCodeGenerator, Ptr: Any, ClassName: str | None, + Tag: str) -> tuple[Any, Any]: + """GEP 基址收口:pointee 为 **opaque** 具名结构体时 bitcast 到已具化实例。 + + 判据与实例来源见 `_ConcretePointeeFor`;返回 `(基址指针, 该类的已具化实例)`, + 第二个返回值同时用作 `_get_member_offset` 的 StructHint —— 偏移与 GEP 必须同源 + (hint 只接受同类,见 FuncGen._member_base)。pointee 非 opaque 时原样返回, + 对既有正确路径零变化;都取不到实例时同样原样返回(不兜底,由守卫报根因)。 + """ + if not isinstance(getattr(Ptr, 'type', None), ir.PointerType): + return Ptr, None + _Pointee: Any = Ptr.type.pointee + if not isinstance(_Pointee, ir.IdentifiedStructType) or _Pointee.elements is not None: + return Ptr, _Pointee + _Twin: Any = self._ConcretePointeeFor(Gen, ClassName, _Pointee) + if _Twin is None: + return Ptr, _Pointee + return (Gen.builder.bitcast(Ptr, ir.PointerType(_Twin), name=Tag), _Twin) + def _get_attr_ptr(self, Node: ast.Attribute) -> ir.Value | None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen if not isinstance(Node, ast.Attribute): @@ -1785,36 +1833,13 @@ class ExprAttrHandle(BaseHandle): if SelfVar: SelfPtr: Any = Gen._load(SelfVar, name="self") if isinstance(SelfPtr.type, ir.PointerType): - # 基址 pointee 若**未具化**(opaque):typed pointer 下 GEP 必须 - # 在编译期算出元素类型,否则 llvmlite 内部抛裸 TypeError - # ('NoneType' object is not subscriptable)。与**同函数下方 - # 各分支**(属性链分支 / i8* 分支:均先 _TryLoadStructFromStub - # 补 body、再 bitcast 到已具化实例)同口径 —— 偏移与 GEP 必须 - # 同源;本分支此前是唯一漏了这套处理的分支。 - # 现场(2026-09-30):includes/ast/astaux.vp:165 - # `self.arg = _copy_str(pool, arg)`,GEP 名 'arg',基址 pointee - # 是 opaque 的 `%"8312ce86a2fd82c0.Keyword"*`,而同短名的 - # 'Keyword' 键上那份已具化(10 槽)。 - _SelfPointee: Any = SelfPtr.type.pointee - if (isinstance(_SelfPointee, ir.IdentifiedStructType) - and _SelfPointee.elements is None): - _ST: Any = Gen.structs.get(ClassName) - if isinstance(_ST, ir.IdentifiedStructType) and not _ST.elements: - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - _ST = Gen.structs.get(ClassName, _ST) - _Twin: Any = None - if isinstance(_ST, ir.IdentifiedStructType) and _ST.elements: - _Twin = _ST - else: - try: - _Twin = Gen._FindConcreteTwin(_SelfPointee) - except Exception: - _Twin = None - if _Twin is not None: - SelfPtr = Gen.builder.bitcast( - SelfPtr, ir.PointerType(_Twin), - name=f"cast_self_{ClassName}") - _SelfPointee = _Twin + # 基址收口(见 _ConcretizeGepBase):opaque 基址先补 body/取孪生体 + # 再 GEP。现场(2026-09-30):includes/ast/astaux.vp:165 + # `self.arg = _copy_str(pool, arg)`,GEP 名 'arg',基址 pointee 是 + # opaque 的 %"8312ce86a2fd82c0.Keyword"*,而同短名的 'Keyword' + # 键上那份已具化(10 槽)。 + SelfPtr, _SelfPointee = self._ConcretizeGepBase( + Gen, SelfPtr, ClassName, f"cast_self_{ClassName}") offset: int | None = Gen._get_member_offset(Node.attr, ClassName, _SelfPointee) if offset is None: return None @@ -1851,14 +1876,11 @@ class ExprAttrHandle(BaseHandle): if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}") if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: - ST: Any = Gen.structs[ClassName] - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - ST = Gen.structs.get(ClassName, ST) - if ST.elements is not None and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{ClassName}") - offset = Gen._get_member_offset(Node.attr, ClassName) - if offset is not None and ST.elements is not None: + # 基址收口(见 _ConcretizeGepBase):类键那份可能仍 opaque ⇒ 补 body / + # 取同短名孪生体后再 GEP(偏移同源)。 + ObjVal, ST = self._ConcretizeGepBase(Gen, ObjVal, ClassName, f"cast_{ClassName}") + offset = Gen._get_member_offset(Node.attr, ClassName, ST) + if offset is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None: MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) return MemberPtr elif isinstance(Node.value, ast.Attribute): @@ -1871,20 +1893,21 @@ class ExprAttrHandle(BaseHandle): CN: str ST: Any CN, ST = found - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) - ST = Gen.structs.get(CN, ST) - if ST.elements is not None and isinstance(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None: - InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}") - offset = Gen._get_member_offset(Node.attr, CN) - if offset is not None and ST.elements is not None: + # 基址收口(见 _ConcretizeGepBase):链尾 pointee 可能仍是类键上那份 + # opaque 实例 ⇒ 补 body / 取同短名孪生体后再 GEP(偏移同源)。 + InnerPtr, ST = self._ConcretizeGepBase(Gen, InnerPtr, CN, f"cast_{CN}") + offset = Gen._get_member_offset(Node.attr, CN, ST) + if offset is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None: MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) return MemberPtr elif isinstance(pointee, ir.IntType) and pointee.width == 8: AttrClassName: str | None = self._get_attr_class(Node.value, Gen) if AttrClassName and AttrClassName in Gen.structs: CastedObj: Any = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}") - offset = Gen._get_member_offset(Node.attr, AttrClassName) + # 类键那份可能仍 opaque ⇒ 统一收口(见 _ConcretizeGepBase) + CastedObj, ST2 = self._ConcretizeGepBase( + Gen, CastedObj, AttrClassName, f"cast_twin_{AttrClassName}") + offset = Gen._get_member_offset(Node.attr, AttrClassName, ST2) if offset is not None: MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) return MemberPtr @@ -1896,7 +1919,9 @@ class ExprAttrHandle(BaseHandle): found = Gen.find_struct_by_pointee(pointee) if found: CN, ST = found - offset = Gen._get_member_offset(Node.attr, CN) + # 基址收口(本分支此前完全没有这一步:opaque 时 GEP 直接抛裸 TypeError) + SubPtr, ST = self._ConcretizeGepBase(Gen, SubPtr, CN, f"cast_{CN}") + offset = Gen._get_member_offset(Node.attr, CN, ST) if offset is not None: MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) return MemberPtr @@ -1917,6 +1942,13 @@ class ExprAttrHandle(BaseHandle): if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): self.Trans.ImportHandler._TryLoadStructFromStub(UnionCls, Gen) ST = Gen.structs.get(UnionCls, ST) + if isinstance(ST, ir.IdentifiedStructType) and not ST.elements: + # 类键那份仍 opaque(body 未 set_body / 另一份实例已具化)⇒ 取已具化 + # 实例作目标 pointee,否则 bitcast/inttoptr 出来的基址仍是 opaque、 + # GEP 在编译期算不出元素类型(判据见 _ConcretePointeeFor)。 + _TwU: Any = self._ConcretePointeeFor(Gen, UnionCls, ST) + if _TwU is not None: + ST = _TwU TargetPtrTy: Any = ir.PointerType(ST) if isinstance(ObjVal.type, ir.PointerType): if ObjVal.type != TargetPtrTy: diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index cac113a..b16213e 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -648,7 +648,13 @@ class ExprBuiltinHandle(BaseHandle): self_val = Gen._get_var_ptr(obj_name) if self_val: self_ptr = Gen._load(self_val, name="obj_for_len") - offset = Gen._get_member_offset(len_member, bare_cls) + # 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase):接收者的 + # pointee 可能是**另一份 opaque 同名实例**,GEP 需要在编译期算出 + # 元素类型 ⇒ 先补 body / 取同短名孪生体,并以该实例算偏移(同源)。 + _STl: Any + self_ptr, _STl = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, self_ptr, bare_cls, f"cast_{bare_cls}") + offset = Gen._get_member_offset(len_member, bare_cls, _STl) len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{obj_name}_{len_member}_ptr") return Gen._load(len_ptr, name=f"{obj_name}_{len_member}") # 修复 stdint.vp 崩溃(0xC0000005)根因:`list[X] | t.CPtr` 联合字段 @@ -672,7 +678,11 @@ class ExprBuiltinHandle(BaseHandle): self_val = Gen._get_var_ptr(obj_name) if self_val: self_ptr = Gen._load(self_val, name="obj_for_len") - offset = Gen._get_member_offset(attr_name, bare_cls) + # 基址收口(判据见 ExprAttrHandle._ConcretizeGepBase) + _STl2: Any + self_ptr, _STl2 = self.Trans.ExprAttrHandle._ConcretizeGepBase( + Gen, self_ptr, bare_cls, f"cast_{bare_cls}") + offset = Gen._get_member_offset(attr_name, bare_cls, _STl2) if offset is not None: list_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{obj_name}_{attr_name}_ptr") list_val = Gen._load(list_ptr, name=f"{obj_name}_{attr_name}") diff --git a/lib/core/Handles/HandlesMatch.py b/lib/core/Handles/HandlesMatch.py index 97b578d..93c7663 100644 --- a/lib/core/Handles/HandlesMatch.py +++ b/lib/core/Handles/HandlesMatch.py @@ -1,5 +1,5 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Handles.HandlesBase import BaseHandle @@ -439,6 +439,13 @@ class MatchHandle(BaseHandle): NestedStructName: str = f"{RenumName}_{VariantName}" if NestedStructName in Gen.structs: NestedStructType: ir.Type = Gen.structs[NestedStructName] + # 变体 struct 可能仍是 opaque(body 未 set_body / 同名两份实例) + # ⇒ 先取已具化实例,否则 GEP 在编译期算不出元素类型(判据见 + # ExprAttrHandle._ConcretePointeeFor)。 + _TwV: Any = self.Trans.ExprAttrHandle._ConcretePointeeFor( + Gen, NestedStructName, NestedStructType) + if isinstance(_TwV, ir.IdentifiedStructType): + NestedStructType = _TwV NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType) variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") for bind_name, member_name, member_type, member_idx in bindings: