From fa6b3c2e6433b177bfde5724f20c51b1b848b982 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 28 Sep 2026 23:21:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpc):=20=E3=80=8C=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E7=89=A9=E5=8C=96=E3=80=8D=E8=B1=81=E5=85=8D=E8=A6=86=E7=9B=96?= =?UTF-8?q?=20REnum=20=E5=8F=98=E4=BD=93=E6=9E=84=E9=80=A0=EF=BC=88*?= =?UTF-8?q?=E6=A7=BD=20=3D=20=20=E8=A2=AB?= =?UTF-8?q?=E8=AF=AF=E6=8B=A6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a 编译器缺陷:规则③(非基本类型值 ↔ 指针隐式转换一律禁止——含 T* → T) 的唯一例外是「构造物化」,但 _CtorCallStructType 只按 callee 名在 Gen.structs 里取聚合类型:对 REnum 变体构造 Qual.Variant(...)(如 llvmlite.LLVMType.Struct(fields, fcount, name))取到的是**变体短名 Struct**, structs 中不存在 ⇒ 恒 miss,于是 `*existing.Ty = ` 被当作指针→值 隐式转换拦下。报文自己写着「构造物化除外」,实现却没覆盖这一形态。 修法:按 HandlesExprCall._HandleCallLlvm 的分派顺序补齐判据 —— 先按 callee 名 判类构造(Point()),miss 后再按**限定名 Qual**(REnum 类,如 LLVMType)取一次 聚合类型。REnum 变体构造返回 boxed 指针(_allocaEntry(RenumType)),其 pointee 恰为 structs[Qual],与 target_type 比对通过即放行,随后走既有的 「load + 整对象 store」物化路径(与 c.DerefAs 的整对象拷贝分支等价)。 现场:非基本类型的值/指针隐式转换已禁止(构造物化除外):不能把指针类型 %"50741ad4b4b0934d.LLVMType"* 隐式转为值类型 %"50741ad4b4b0934d.LLVMType" (ClassGenDef.vp:117)。 --- lib/core/LLVMCG/MemoryOps.py | 45 +++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/lib/core/LLVMCG/MemoryOps.py b/lib/core/LLVMCG/MemoryOps.py index 9f7b3fe..201fd03 100644 --- a/lib/core/LLVMCG/MemoryOps.py +++ b/lib/core/LLVMCG/MemoryOps.py @@ -389,34 +389,53 @@ class MemoryOpsMixin: return Node def _CtorCallStructType(self, Node: Any = None) -> Any: - """AST 层判定:Node(或其值子节点)是否为「类/构造调用」右值;是则返回其构造的 + """AST 层判定:Node(或其值子节点)是否为「构造调用」右值;是则返回其构造的 聚合类型(IdentifiedStruct/LiteralStruct),否则返回 None。 规则③(非基本类型值 ↔ 指针隐式转换一律禁止)的**唯一例外**是「构造物化」: 右值来自该类型的构造调用时放行(构造语义,非类型转换)。判据复用本仓既有的 - 「Call 的被调方是类/构造」口径(见 HandlesExprCall._HandleCallLlvm 的分派): - - callee 裸名/属性名命中已注册类(`Gen.structs`)→ 构造; + 「Call 的被调方是构造」口径(见 HandlesExprCall._HandleCallLlvm 的分派顺序): + - callee 裸名/属性名命中已注册聚合(`Gen.structs`)→ 类构造(`Point()`); + - callee 是 `Qual.Variant(...)` / `mod.Qual.Variant(...)` 的**变体**写法 —— + 变体短名(如 `Struct`)不在 `Gen.structs` 中,构造出的聚合类型挂在 + **限定名 Qual**(REnum 类,如 `LLVMType`)下,故再按 Qual 取一次。 + REnum 变体构造返回 **boxed 指针**(`Gen._allocaEntry(RenumType)`, + 见 HandlesExprCall._HandleREnumConstructLlvm),其 pointee 恰是 + `structs[Qual]` —— 正是「构造物化」要放行的形态 + (`*existing.Ty = llvmtype.Struct(...)`,boxed 指针 → 值槽的整对象拷贝)。 - 泛型类模板特化(Box(42))需类型实参推断,静态取不到类型 → 保守返回 None。 + 顺序与 `_HandleCallLlvm` 一致:先按 callee 名判类构造,miss 后再按限定名判 + 变体构造(若同名类存在,实际 dispatch 也走类构造路径)。 """ N: Any = MemoryOpsMixin._ValueNodeOf(Node) if not isinstance(N, ast.Call): return None Func: Any = getattr(N, 'func', None) ClassName: str | None = None + Qualifier: str | None = None if isinstance(Func, ast.Name): ClassName = Func.id elif isinstance(Func, ast.Attribute): ClassName = Func.attr - if not ClassName: - return None - ST: Any = getattr(self, 'structs', {}).get(ClassName) - if ST is None: - return None - if isinstance(ST, ir.PointerType): - ST = ST.pointee - if not isinstance(ST, (ir.IdentifiedStructType, ir.LiteralStructType)): - return None - return ST + # 变体构造的限定名:`Qual.Variant` 的 Qual(Name)或 `mod.Qual.Variant` + # 的 Qual(Attribute.attr)。 + _QualNode: Any = getattr(Func, 'value', None) + if isinstance(_QualNode, ast.Name): + Qualifier = _QualNode.id + elif isinstance(_QualNode, ast.Attribute): + Qualifier = _QualNode.attr + Structs: Any = getattr(self, 'structs', {}) + for _Cand in (ClassName, Qualifier): + if not _Cand: + continue + ST: Any = Structs.get(_Cand) + if ST is None: + continue + if isinstance(ST, ir.PointerType): + ST = ST.pointee + if isinstance(ST, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ST + return None def _alloca(self, typ: ir.Type, name: str = '', align: int | None = None, size: ir.Value | None = None) -> ir.AllocaInstr: if align is None: