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: