from __future__ import annotations from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator import vast as ast import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode from lib.includes import t from lib.core.SymbolUtils import ( IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotationWithContext, AnnotationContainsName, IsCPtrNode, RequireDefineConstStorable, FindAutoAddrMode, ) def _IsGenericTpName(name: str) -> bool: """判断名称是否为泛型类型参数(单字母大写,如 T/U/V) 用于 _is_struct_ptr_union 判定:elem_ptr: T | t.CPtr = t.CPtr(...) (_list.vp 泛型方法体,T 未解析)时按 8 字节指针槽处理,避免 var_struct_class 误注册 llvmlite.Value 后 elem_ptr[0] cast 到 Value* 与函数声明 i8* 不匹配(8fbba llc 报错根因)。标量 T(如 int)退化为 Ptr(i32) 不命中 _HandleSubscriptLlvm 的 i8 分支,不受此影响。 """ if not name: return False return len(name) == 1 and name.isalpha() and name.isupper() # 指针/未知**占位**类名(非真实类):联合注解 rawptr[T] / X | t.CPtr 折叠后, # var_struct_class 里可能落进这些占位名(它们可能恰好也在 Gen.structs 里,如 # 'rawptr')。占位名不表态具体类 ⇒ 不得登记为「注解声明类」的权威值,否则会挡住 # "无注解赋值从右值推断类名"的正常路径(如 `p: t.CPtr = Point()` 之后 `p.x` 需要 # Point)。形态三种(见本文件 L753 的同类判据):裸 'rawptr'、带模块前缀 # 'sha1.rawptr'、下标式 'rawptr[X]';CPtr 一族的裸名/限定名同样计入。 _PTR_MARKER_CLASS_NAMES: frozenset[str] = frozenset({ 'rawptr', 't.rawptr', 'c.rawptr', 'CPtr', 't.CPtr', 'c.CPtr', 'CAutoPtr', 't.CAutoPtr', 'CRef', 't.CRef', 'CTempRef', 't.CTempRef', }) def _IsPtrMarkerClassName(Name: str | None) -> bool: """类名是否为指针/未知占位名(判据见 _PTR_MARKER_CLASS_NAMES)""" if not Name: return False if Name in _PTR_MARKER_CLASS_NAMES: return True # 带模块前缀('sha1.rawptr')与下标式('rawptr[X]')两种形态 if '.rawptr' in Name or Name.startswith('rawptr['): return True if '.CPtr' in Name or Name.startswith('CPtr['): return True return False class AnnAssignHandle(BaseHandle): def _StoreOrStrCopy(self, VarName: str, VarPtr: ir.Value, Value: ir.Value) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen DestPtr: ir.Value = Gen._load(VarPtr, name=VarName) if isinstance(DestPtr.type, ir.PointerType) and isinstance(DestPtr.type.pointee, ir.IntType) and DestPtr.type.pointee.width == 8: if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.IntType) and Value.type.pointee.width == 8: if 'llvm.memcpy' not in Gen.functions: memcpy_type: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(32), ir.IntType(1)]) Gen.functions['llvm.memcpy'] = Gen._CreateOrReuseFuncDecl('llvm.memcpy', memcpy_type) if isinstance(DestPtr.type.pointee, ir.IntType) and not isinstance(DestPtr.type.pointee, ir.IntType(8)): DestPtr = Gen.builder.bitcast(DestPtr, ir.PointerType(ir.IntType(8)), name=f"strcpy_dst_cast_{VarName}") if isinstance(Value.type.pointee, ir.IntType) and not isinstance(Value.type.pointee, ir.IntType(8)): Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"strcpy_src_cast_{VarName}") size: ir.Constant = ir.Constant(ir.IntType(64), 8) align: ir.Constant = ir.Constant(ir.IntType(32), 1) isvolatile: ir.Constant = ir.Constant(ir.IntType(1), 0) Gen.builder.call(Gen.functions['llvm.memcpy'], [DestPtr, Value, size, align, isvolatile], name=f"strcpy_call_{VarName}") return try: CastedVal: ir.Value = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") Gen._store(CastedVal, VarPtr) except Exception: # 回退:bitcast 失败时 alloca 新变量 NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) Gen._store(Value, NewVar) Gen.variables[VarName] = NewVar @staticmethod def _RhsEndsWithVoidCall(Gen: LlvmCodeGenerator, BlockBefore: ir.Block | None, InsnStart: int) -> bool: """判定刚求值的带注解赋值 RHS 是否"按类型即无值"(以返回 void 的调用收尾)。 判据完全取自**实际发射的指令**(不依赖 RHS 的 AST 形态白名单):仅当求值 发生在同一基本块、且新增指令的最后一条是返回 void 的 call 时,才认为该 表达式语义上本就无值(如返回 void 的内建/库调用),此时"无值可存"合法。 其余情况——无任何指令产出(类型下标被当乘法 ⇒ 整条 RHS 未生成任何东西) 或只产出 load/gep 等非收尾指令后求值失败(属性链解析失败,实测同块新增 1 条 load)——都属编译期求值失败,必须 fail-fast。 """ BlockAfter: ir.Block | None = Gen.builder.block if Gen.builder is not None else None if InsnStart < 0 or BlockAfter is None or BlockAfter is not BlockBefore: return False NewInstrs: list[ir.Instruction] = BlockAfter.instructions[InsnStart:] if not NewInstrs: return False Last: ir.Instruction = NewInstrs[-1] return isinstance(Last, ir.CallInstr) and isinstance(Last.type, ir.VoidType) def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen AttrName: str = Target.attr if isinstance(Target.value, ast.Name) and Target.value.id == 'self': ClassName: str | None = self._CurrentCpythonObjectClass if not ClassName: self_var: ir.Value | None = Gen.variables.get('self') if self_var: var_type: ir.Type = self_var.type if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType): var_type = var_type.pointee if isinstance(var_type, ir.PointerType): pointee: ir.Type = var_type.pointee for cn, st in Gen.structs.items(): if st == pointee: ClassName = cn break if ClassName and ClassName in Gen.structs: SelfVar: ir.Value | None = Gen._get_var_ptr('self') if SelfVar: SelfPtr: ir.Value = Gen._load(SelfVar, name="self") # 基址收口(判据见 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 # 模块全局变量写入(治本修复 2026-08-27,与 HandlesAssign 同款): # X.attr = ... 且 X 是 import 模块(含别名/后缀匹配 _ImportedModules) # 时按"模块全局变量"直接 store,优先 {sha1}.{Attr} 前缀名,回退裸名。 # 必须放在 ClassName heuristic(startswith(CN))之前,否则模块名与 # 类名同名(如 CompilerFactory)会被误判为类字段 → fail-fast。 _mod_imported: list[str] | None = getattr(self.Trans, '_ImportedModules', None) _resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) _is_mod_write: bool = False if _mod_imported: _is_mod_write = (VarName in _mod_imported or _resolved_mod in _mod_imported) if not _is_mod_write: for _mn in _mod_imported: if (_mn == VarName or _mn.endswith(f".{VarName}") or _mn == _resolved_mod or _mn.endswith(f".{_resolved_mod}")): _is_mod_write = True break if _is_mod_write: _mod_sha1_map: dict[str, str] = getattr(Gen, 'ModuleSha1Map', {}) _cands: list[str] = [VarName, _resolved_mod] for _mn in _mod_imported: if _mn.endswith(f".{VarName}") or _mn == VarName: if _mn not in _cands: _cands.append(_mn) for _cand in _cands: _sha1: str | None = _mod_sha1_map.get(_cand) if _sha1: _prefixed: str = f"{_sha1}.{AttrName}" if _prefixed in Gen.module.globals: _pgv: ir.GlobalVariable = Gen.module.globals[_prefixed] if isinstance(_pgv, ir.Function): return self._StoreWithCoerce(Value, _pgv) return if AttrName in Gen.module.globals: _gv: ir.GlobalVariable = Gen.module.globals[AttrName] if isinstance(_gv, ir.Function): return self._StoreWithCoerce(Value, _gv) return # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储) # 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖) _fd_meta_name: str = f"{VarName}__meta__" if _fd_meta_name in Gen.variables and '_str' in Gen.structs: _fd_offset = Gen._get_member_offset(AttrName, '_str') if _fd_offset is not None: _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name] _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr") self._StoreWithCoerce(Value, _fd_field_ptr) return ClassName: str | None = Gen.var_struct_class.get(VarName) if not ClassName: for CN in Gen.structs: if VarName == CN.lower() or VarName.startswith(CN): ClassName = CN break if not ClassName and VarName in Gen.variables: VarPtr: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): pointee: ir.Type = VarPtr.type.pointee if isinstance(pointee, ir.PointerType): pointee = pointee.pointee for CN, ST in Gen.structs.items(): if pointee == ST: ClassName = CN break IsUnion: bool = False if ClassName: ClassTypeInfo: Any = self.Trans.SymbolTable.lookup(ClassName) if ClassTypeInfo: if ClassTypeInfo.IsUnion: IsUnion = True if ClassName and ClassName in Gen.structs: ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) if ObjVal: if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IntType) and ObjVal.type.pointee.width == 8: ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") # opaque 泛型结构体 → 特化版本 bitcast # 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub), # 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者是不同的 # IdentifiedStructType,直接比较会失败。这里 bitcast 到特化版本, # 使后续 GEP 能正确访问字段。 if (isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee is not Gen.structs[ClassName] 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: NestedStructType: ir.Type = Gen.structs[NestedStructName] ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") offset: int = Gen._get_member_offset(AttrName, NestedStructName) if offset is not None and offset < len(NestedStructType.elements): 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, _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): pointee: ir.Type = ObjVal.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: # 基址收口(判据见 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: Gen: LlvmCodeGenerator = self.Trans.LlvmGen if isinstance(Ptr.type, ir.PointerType): TargetType: ir.Type = Ptr.type.pointee if Value.type != TargetType: # None(空值常量)允许隐式转换为任意字段类型:指针→空指针,其余→零值。 if Gen._IsNoneValue(Value, Node): Value = (ir.Constant(TargetType, None) if isinstance(TargetType, ir.PointerType) else Gen._ZeroConst(TargetType)) elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType): if TargetType.width < Value.type.width: # 目标 i1:真值归一化 `x != 0`(与 bool(x)/if 条件同一判据), # 不是 trunc 取最低位(运行时值 2 会得 false,与 `if 2:` 相反) if TargetType.width == 1: Value = Gen._CoerceIntToI1(Value, name="bool_norm") # 隐式窄化**禁止**(与 MemoryOps._coerce_value 同口径,规则 2026-10-10): # 位宽高→低会丢高位,必须显式 cast 或加宽目标类型。 # 唯一豁免:源是**编译期常量且值落进目标位宽**(无信息损失)。 elif (isinstance(Value, ir.Constant) and isinstance(Value.constant, int) and -(1 << (TargetType.width - 1)) <= Value.constant <= (1 << TargetType.width) - 1): Value = Gen.builder.trunc(Value, TargetType, name="trunc_const") else: from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"隐式窄化禁止:{Value.type.width} 位整数不能隐式赋给 {TargetType.width} 位类型" f"(会丢高位);请显式转换(如 int32(x) / t.CInt32T(x) )或把目标类型加宽" f"{Gen._DescribeValueNode(Node)}" ) else: Value = Gen.builder.zext(Value, TargetType, name="zext") elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): Allowed: bool Reason: str Allowed, Reason = Gen._ClassifyPtrImplicitConvert(Value.type, TargetType) if not Allowed: from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"指针隐式转换已禁止({Reason}):不能把指针类型 {Value.type} 隐式转为 {TargetType};" f"如需转换请显式 cast(如 t.CPtr(...))" f"{Gen._DescribeValueNode(Node)}" ) Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast") elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType): Value = Gen.builder.inttoptr(Value, TargetType, name="int_to_ptr") elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.PointerType): # 指针 → 整数:隐式转换一律禁止(与 ViperC coerce_to_type 同口径) # (None 已在上方短路为零值,不会落到这里)。 from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"指针隐式转整数已禁止:不能把指针类型 {Value.type} 赋给整数类型 {TargetType};" f"如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))" f"{Gen._DescribeValueNode(Node)}" ) Gen._store(Value, Ptr) def _EvalRhsWithTargetHint(self, Node: ast.AnnAssign, VarType: Any, Gen: Any) -> Any: """求值注解赋值的 RHS,并把**左值注解的靶型类**作为提示传给属性链解析。 与 VPC `translate_value` 的 `target_ty`(使用处真实站点种类)同思路:注解是 源码级权威意图(RHS 必须能赋给它)。两个类的成员表都有同名字段时,属性链读错 类名不会当场报错,只会**静默**给出错类型(现场 CallGenDispatch.vp:787 `len_ap: llvmlite.LLVMType* = len_val.Ty.Pointee`:`.Pointee` 属 LLVMType 的 REnum 变体镜像,却因接收者被判成 ParamNode(只有 Next/Ty) 而 fail-fast;ParamNode.Ty 是 裸 rawptr ⇒ 内层读回 i8*,外层再找不到 Pointee)。传提示可把这类情形兜回来。 提示只在"解析出的类**不声明**该字段"时生效(见 HandlesExprAttr._apply_target_struct_hint 的两条件判定),故不会篡改本来正确的链; 求值结束(含异常)即复位,不跨语句泄漏。 """ _Saved: Any = getattr(Gen, '_TargetStructHint', None) _Hint: Any = _Saved if (isinstance(VarType, ir.PointerType) and isinstance(getattr(VarType, 'pointee', None), ir.IdentifiedStructType)): try: _Hint = Gen._extract_short_name(getattr(VarType.pointee, 'name', '') or '') except Exception: _Hint = _Saved try: Gen._TargetStructHint = _Hint return self.HandleExprLlvm(Node.value, VarType=VarType) finally: Gen._TargetStructHint = _Saved def _HandleGenericListLiteralAssign(self, VarName: str, Node: ast.AnnAssign, Gen: LlvmCodeGenerator, list_sub: ast.Subscript) -> None: """处理 list[T] = [...] → 构造 list[T] 对象 + append 序列。 将 list 字面量翻译为: 1. 特化 list[T] 类 2. alloca + __before_init__ + __new__(pool) + __before_init__ + __init__(pool) 3. 对每个元素调用 append(elem) 4. 将堆指针存入变量 list_sub 是从注解中提取的 list[...] Subscript 节点(支持 list[T] 和 list[T] | t.CPtr) """ # 1. 解析元素类型 slice_node: ast.expr = list_sub.slice result: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node) if result is None: return type_arg: str = result[0] type_name: str = result[1] # 2. 特化 list[T] 类 spec_name: str | None = self.Trans.ClassHandler._specialize_generic_class( 'list', [type_arg], Gen, type_names=[type_name]) if spec_name is None: return # 3. 获取结构体类型 StructType: ir.Type | None = Gen.structs.get(spec_name) if StructType is None: return if isinstance(StructType, ir.PointerType): StructType = StructType.pointee # 4. 查找 pool 变量(pool / _mbuddy / mbuddy / mb) pool_val: ir.Value | None = None for pool_name in ('pool', '_mbuddy', 'mbuddy', 'mb'): if pool_name in Gen.variables: pool_var: ir.Value = Gen.variables[pool_name] if isinstance(pool_var.type, ir.PointerType): pointee: ir.Type = pool_var.type.pointee if isinstance(pointee, ir.PointerType): # alloca of pointer → load pool_val = Gen._load(pool_var, name=f"pool_load_{VarName}") else: pool_val = pool_var else: pool_val = pool_var break if pool_val is None: return # 5. alloca 临时结构体 alloca_ptr: ir.AllocaInstr = Gen._allocaEntry(StructType, name=f"{VarName}_alloca") # 6. 调用 __before_init__(alloca_ptr) before_init_name: str = f'{spec_name}.__before_init__' before_init_func: ir.Function | None = None if Gen._has_function(before_init_name): before_init_func = Gen._get_function(before_init_name) Gen.builder.call(before_init_func, [alloca_ptr], name=f"before_init_{VarName}") # 7. 调用 __new__(alloca_ptr, pool_val) → heap_ptr new_method_name: str = f'{spec_name}.__new__' heap_ptr: ir.Value = alloca_ptr has_new: bool = Gen._find_function(new_method_name) is not None if has_new: new_func: ir.Function | None = Gen._find_function(new_method_name) if new_func: new_args: list[ir.Value] = [alloca_ptr, pool_val] self.Trans.ExprCallHandle._fill_default_args(new_args, new_func, new_method_name) # 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。 adjusted_new: list[ir.Value] = Gen._adjust_args(new_args, new_func) heap_ptr = Gen.builder.call(new_func, adjusted_new, name=f"new_{VarName}") # 转换返回指针类型 target_ptr_type: ir.PointerType = ir.PointerType(StructType) if isinstance(heap_ptr.type, ir.PointerType) and heap_ptr.type != target_ptr_type: heap_ptr = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{VarName}_cast") elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type: if heap_ptr.type.width < 64: i64_val: ir.Value = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{VarName}_i64") heap_ptr = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{VarName}_ptr") else: heap_ptr = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{VarName}_ptr") # 对堆指针重新调用 __before_init__ if before_init_func: Gen.builder.call(before_init_func, [heap_ptr], name=f"before_init_{VarName}_heap") # 8. 调用 __init__(heap_ptr, pool_val, elem_size=0) init_name: str = f'{spec_name}.__init__' if Gen._has_function(init_name): init_func: ir.Function | None = Gen._get_function(init_name) if init_func: elem_size_val: ir.Constant = ir.Constant(ir.IntType(64), 0) init_args: list[ir.Value] = [heap_ptr, pool_val, elem_size_val] self.Trans.ExprCallHandle._fill_default_args(init_args, init_func, init_name) # 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。 adjusted_init: list[ir.Value] = Gen._adjust_args(init_args, init_func) Gen.builder.call(init_func, adjusted_init, name=f"init_{VarName}") # 9. 对每个元素调用 append(heap_ptr, elem_val) append_name: str = f'{spec_name}.append' append_func: ir.Function | None = Gen._find_function(append_name) if append_func and Node.value and isinstance(Node.value, ast.List): elts: list[ast.expr] = Node.value.elts for i, elem_node in enumerate(elts): elem_val: ir.Value | None = self.HandleExprLlvm(elem_node) if elem_val: append_args: list[ir.Value] = [heap_ptr, elem_val] self.Trans.ExprCallHandle._fill_default_args(append_args, append_func, append_name) # 自动取址已收口到 Gen._adjust_args(唯一汇聚点,按 func.name 查表)。 adjusted_append: list[ir.Value] = Gen._adjust_args(append_args, append_func) Gen.builder.call(append_func, adjusted_append, name=f"append_{VarName}_{i}") # 10. 创建变量并存储堆指针 # 判断变量类型:list[T] | t.CPtr → i8*;list[T] → Ptr(StructType) is_cptr_union: bool = isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) if is_cptr_union: # list[T] | t.CPtr → 变量类型为 i8* i8_ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8)) var: ir.AllocaInstr = Gen._allocaEntry(i8_ptr_type, name=VarName) # bitcast heap_ptr (Ptr(StructType)) → i8* if isinstance(heap_ptr.type, ir.PointerType) and heap_ptr.type != i8_ptr_type: stored_val: ir.Value = Gen.builder.bitcast(heap_ptr, i8_ptr_type, name=f"store_cast_{VarName}") else: stored_val = heap_ptr Gen._store(stored_val, var) else: # list[T] → 变量类型为 Ptr(StructType) var = Gen._allocaEntry(ir.PointerType(StructType), name=VarName) Gen._store(heap_ptr, var) Gen.variables[VarName] = var Gen.var_struct_class[VarName] = spec_name Gen.global_struct_class[VarName] = spec_name Gen._record_var_signedness(VarName, False) def _HandleAnnAssignLlvm(self, Node: ast.AnnAssign) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen self.Trans._current_assign_node = Node try: self._HandleAnnAssignLlvmInner(Node) finally: self.Trans._current_assign_node = None # 【注解声明类台账(2026-09-30)】带注解声明过的变量,其类名由**声明**决定, # 是权威类型:后续赋值只能把右值**转换进**该类型,不能反过来改掉它。 # 放在 Inner **返回之后**:Inner 内部多处(BinOp 联合短名回退、rawptr[X] 恢复等) # 会按注解写 var_struct_class,此处取的是**终值**。 # 反例(现场 includes/ast/parser.vp:1899 与 :1919): # `node: rawptr[AST] = Name(ps.pool, name_str, ASTCtx.Load)` —— 本行本身合法(上转) # 但若让右值推出的类 `Name` 覆盖声明的 `AST`,则下一处 # `node = _parse_fstring(...)`(返回 rawptr[AST])就变成被禁止的**向下转型**: # VPC 报 "指针隐式转指针已禁止:源类型 %AST* → 目标类型 %Name*"。 if isinstance(getattr(Node, 'target', None), ast.Name) and getattr(Node, 'annotation', None) is not None: _VarName: str = Node.target.id _DeclCls: str | None = Gen.var_struct_class.get(_VarName) # 只把**真实类名**记为权威:指针/未知标记名(rawptr/CPtr/... 这些是联合 # 注解 `rawptr[T]`/`X | t.CPtr` 折叠后的占位名,可能恰好在 Gen.structs 里) # 不表态具体类,若一并记为权威会挡住"无注解赋值从右值推断类名"的正常路径 # (如 `p: t.CPtr = Point()` 之后 `p.x` 需要 Point)。 if _DeclCls and not _IsPtrMarkerClassName(_DeclCls): _M: dict = getattr(Gen, 'var_annotated_class', None) if _M is None: _M = {} Gen.var_annotated_class = _M _M[_VarName] = _DeclCls def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None: Gen: LlvmCodeGenerator = self.Trans.LlvmGen # 值引用标记(`&T` / `&temp T`)仅用于函数参数位:局部/全局变量注解出现即 fail-fast。 _ref_mode: str | None = FindAutoAddrMode(Node.annotation) if _ref_mode is not None: from lib.core.LLVMCG.FuncGen import FailFastError _ann_text: str = ast.unparse(Node.annotation) raise FailFastError( f"变量注解不支持值引用(`&T` / `&temp T`):'{_ann_text}'。" f"值引用仅用于函数参数位;局部变量请改用显式指针类型(如 `T*`)。") # 内建定长数组构造子 array 的注解校验(误用即 fail-fast,含文件:行:列): # 局部变量/self 字段注解不经过 ResolveAnnotationType,故在此显式校验。 self._CheckFixedArrayKeyword(Node.annotation) # M1 协程:记录 async 函数调用赋值的变量名(coro.coro_run 内联翻译需要) if isinstance(Node.target, ast.Name) and Node.value is not None: if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): callee: str = Node.value.func.id if hasattr(self.Trans, 'AsyncHandler') and self.Trans.AsyncHandler._IsAsyncFunc(callee): if not hasattr(Gen, '_coro_var_async'): Gen._coro_var_async = {} Gen._coro_var_async[Node.target.id] = callee if isinstance(Node.target, ast.Name): VarName: str = Node.target.id TypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) if TypeInfo is None: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CInt() IsPtr: bool = TypeInfo.IsPtr if TypeInfo.IsDefine: if Node.value and isinstance(Node.value, ast.Constant): # fail-fast:常量值必须能落进声明类型(define 带类型形态)/ 64 位存储 # (自动推导形态)。唯一判据见 SymbolUtils.RequireDefineIntStorable。 RequireDefineConstStorable(Gen, self.Trans, Node, TypeInfo.BaseType, Node.annotation, Node.value.value, VarName) if not hasattr(Gen, '_define_constants'): Gen._define_constants = {} Gen._define_constants[VarName] = Node.value.value info: CTypeInfo = CTypeInfo() info.IsDefine = True info.DefineValue = Node.value.value self.Trans.SymbolTable.insert(VarName, info) Gen._record_var_signedness(VarName, TypeInfo.IsUInt) elif Node.value: # 非 Constant 表达式:尝试编译期求值(如 t.CSizeT().Size // 8) from lib.core.ConstEvaluator import ConstEvaluator, EvalContext ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) eval_val = ConstEvaluator.eval_full(Node.value, ctx) if eval_val is not None and isinstance(eval_val, (int, float)): RequireDefineConstStorable(Gen, self.Trans, Node, TypeInfo.BaseType, Node.annotation, eval_val, VarName) if not hasattr(Gen, '_define_constants'): Gen._define_constants = {} Gen._define_constants[VarName] = eval_val info: CTypeInfo = CTypeInfo() info.IsDefine = True info.DefineValue = eval_val self.Trans.SymbolTable.insert(VarName, info) Gen._record_var_signedness(VarName, TypeInfo.IsUInt) return if TypeInfo.IsStr or (isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str'): # 仅指针层数 <= 1 才算裸 str/bytes(i8*),可以压平:`str | t.CPtr` / # `str*` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 指针数组), # 压平会让局部变量比模块级同名全局槽少一层指针 # (全局走 HandlesAssign._EmitGlobalAnnAssignLlvm 的 FromNode,得到 i8**), # 于是 includes/sys.vp `_argv = argv_arr` 被指针隐式转换 fail-fast 拦下。 # 与 HandlesFunctions.py:599 / HandlesImports.py:1440 的 # `IsStr and PtrCount <= 1` 同一条规则源。 if TypeInfo.PtrCount <= 1: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CChar() TypeInfo.PtrCount = 1 IsPtr = True # FakeDuck: 为 str 变量创建影子结构体 a__meta__ (栈上, per-instance) # a 保持为 char* 用于 printf; a__meta__ 存储 __data__ 和 __mbuddy__ 字段 # 仅对 str 类型创建,bytes 和 t.CChar|t.CPtr 不创建 if '_str' in Gen.structs and isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str': _meta_name: str = f"{VarName}__meta__" _meta_var: ir.AllocaInstr = Gen._allocaEntry(Gen.structs['_str'], name=_meta_name) Gen.variables[_meta_name] = _meta_var # 标记指针到 str/bytes 的变量 (BinOp 注解如 str | t.CPtr) # elem_ptr[0] 应加载/存储 8 字节 (指针), 而非 1 字节 (字符) # 仅当注解包含 str 或 bytes 时设置(t.CChar | t.CPtr 不应设置,它是纯字符指针) if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'): Gen.var_ptr_element[VarName] = True # 同时记录到全局字典,使全局变量在跨函数访问时仍能用 8 字节指针步长 Gen.global_var_ptr_element[VarName] = True parse_result = ParseListAnnotation(Node.annotation) if parse_result: elem_type_node: ast.expr = parse_result.elem_type_node ElemType, ElemTypeInfo = self.ResolveListElementType( elem_type_node, Gen, handle_str=True, void_fallback_width=32, ) if parse_result.is_pointer: # 单参数 list[type] → 指针 # 但如果有列表字面量初始化值 [a, b, c],则按数组 t.CArray[type, N] 处理 if not (Node.value and isinstance(Node.value, ast.List)): VarType: ir.Type = ir.PointerType(ElemType) var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName) Gen.variables[VarName] = var Gen._record_var_signedness(VarName, False) if self.Trans.VarScopes: self.Trans.VarScopes[-1][VarName] = ElemTypeInfo return # 有列表字面量值,继续走数组路径(count_node=None 时从列表长度推断) count_node: ast.expr | None = parse_result.count_node ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='local') VarType = ir.ArrayType(ElemType, ArrayCount) var = Gen._allocaEntry(VarType, name=VarName) Gen.variables[VarName] = var Gen._record_var_signedness(VarName, False) if Node.value and isinstance(Node.value, ast.List): InitConstants: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '') if InitConstants: try: InitVal: ir.Constant = ir.Constant(VarType, InitConstants) Gen.builder.store(InitVal, var) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): str_val: str = Node.value.value + '\x00' str_bytes: bytearray = bytearray(str_val, 'utf-8') if isinstance(VarType, ir.ArrayType) and len(str_bytes) < VarType.count: str_bytes.extend(b'\x00' * (VarType.count - len(str_bytes))) try: InitVal: ir.Constant = ir.Constant(VarType, str_bytes[:VarType.count] if isinstance(VarType, ir.ArrayType) else str_bytes) Gen.builder.store(InitVal, var) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") if self.Trans.VarScopes: self.Trans.VarScopes[-1][VarName] = ElemTypeInfo # 记录数组元素字节序 if ElemTypeInfo and ElemTypeInfo.ByteOrder == 'big' and isinstance(ElemType, ir.IntType) and ElemType.width in (16, 32, 64): Gen.local_var_byteorders[VarName] = 'big' return # list[T] 泛型类注解 + list 字面量值 → 构造 list[T] 对象 + append 序列 # (list[str] = ["a", "b"] 不应走 C 数组路径,而应构造 list[str] 对象) # 支持两种注解形式:list[T] 和 list[T] | t.CPtr list_sub: ast.Subscript | None = None if (isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list'): list_sub = Node.annotation elif (isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)): for side in (Node.annotation.left, Node.annotation.right): if (isinstance(side, ast.Subscript) and isinstance(side.value, ast.Name) and side.value.id == 'list'): list_sub = side break if (list_sub is not None and not isinstance(list_sub.slice, ast.Tuple) and Node.value is not None and isinstance(Node.value, ast.List) and hasattr(self.Trans.ClassHandler, '_generic_class_templates') and 'list' in self.Trans.ClassHandler._generic_class_templates): self._HandleGenericListLiteralAssign(VarName, Node, Gen, list_sub) return # Only fall back to the left operand when the union neither resolved a base # type nor accumulated multi-level pointers. A pointer-marker based union # (`t.CPtr*` = `t.CPtr | t.CPtr` => CVoid/2) is already a fully resolved # multi-level pointer; falling back to its left operand (`t.CPtr` => 1 layer) # used to silently degrade it to i8*. Keep PtrCount > 1 untouched. if (TypeInfo.IsVoid and TypeInfo.PtrCount <= 1 and isinstance(Node.annotation, ast.BinOp)): found: str | None = FindStructNameInAnnotationWithContext( Node.annotation, self.Trans, Gen) if found: TypeInfo = CTypeInfo() TypeInfo.BaseType = t.CStruct(name=found) TypeInfo.PtrCount = 1 IsPtr = True elif isinstance(Node.annotation.left, ast.Attribute): AttrTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left) if AttrTypeInfo and AttrTypeInfo.BaseType: TypeInfo = AttrTypeInfo TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1) IsPtr = True # 对于局部变量声明 s: TestStruct(不带 | t.CPtr),应为栈上结构体而非指针 # GetCTypeInfo 默认设置 PtrCount=1,但纯结构体名注解应为值类型 if (isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs and TypeInfo.IsStruct and Node.annotation.id not in Gen.class_vtable): TypeInfo.PtrCount = 0 IsPtr = False # const / volatile 局部变量登记(统一登记入口)。放在此处:TypeInfo 的 # PtrCount/IsStruct 已定稿(上方 526-547),且早于本函数所有后续分支与 # 提前 return(数组/list/_reg_values/已存在 alloca 等),保证「局部变量」 # 这一登记点只有一处、无遗漏。 Gen.RegisterVarQualifiers(VarName, TypeInfo, Node.annotation, IsGlobal=False) VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo) if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name: stripped: str = TypeInfo.Name if stripped in Gen.class_vtable and stripped in Gen.structs: VarType = ir.PointerType(Gen.structs[stripped]) IsPtr = True if isinstance(VarType, ir.IdentifiedStructType): struct_name: str = getattr(VarType, 'name', '') if struct_name and Gen.class_vtable: for cls_name in Gen.class_vtable: if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: VarType = ir.PointerType(VarType) IsPtr = True break if isinstance(VarType, ir.VoidType): VarType = ir.IntType(32) IsUnsigned: bool = TypeInfo.IsUInt # 修复 3: BinOp 注解(如 ast.Arguments | t.CPtr)的 var_struct_class 设置 # TypeInfo.Name 由 _HandleSubscript 设置(特化名如 list[sha1.ASTptr])或 # GetCTypeInfo 设置(普通结构体名),经 _MergeCTypeInfoInto 传播后保留。 # 此处确保 BinOp 注解的变量也能被 _get_var_class 识别,避免方法调用分派 # fallthrough 到 char pointer fallback 错误匹配其他类(如 AST.__len__)。 # 使用 not in 条件,不覆盖后续 L337-339/L396-398 对 ast.Name 注解的精确设置。 if TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs: if VarName not in Gen.var_struct_class: Gen.var_struct_class[VarName] = TypeInfo.Name Gen.global_struct_class[VarName] = TypeInfo.Name # 联合指针注解(X | t.CPtr)短名回退:resolver 对模块限定 struct # 段(如 llvmlite.Value)无法精确 in Gen.structs(键可能是 'Value' # 或带 sha1 前缀),Name 常退化为指针别名 'rawptr'(被注册成 opaque # struct)→ 变量 var_struct_class 登记为 rawptr → 字段访问 # "属性 'Next' 在类 'rawptr' 中找不到"(FuncGenMixin.vp L307)。 # FindStructNameInAnnotation 以 attr/短名命中,找回真实类名。 if (isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)): _union_struct_name2: str | None = FindStructNameInAnnotationWithContext( Node.annotation, self.Trans, Gen) # resolver 对模块限定 struct 联合(llvmlite.Value | t.CPtr)常给出 # 指针占位名(如 '{sha1}.rawptr')且该占位恰好注册在 Gen.structs, # 使上方 TypeInfo.Name in Gen.structs 通过并登记错误类名 → 字段 # 访问 "属性 'Next' 在类 'rawptr' 中找不到"。凡短名命中真实类 # (attr 精确 in structs),一律覆盖为真实类名(Value)。 if _union_struct_name2 and _union_struct_name2 in Gen.structs: if Gen.var_struct_class.get(VarName) != _union_struct_name2: Gen.var_struct_class[VarName] = _union_struct_name2 if getattr(Gen, 'global_struct_class', None) is not None: Gen.global_struct_class[VarName] = _union_struct_name2 # Subscript rawptr[X] / t.CPtr[X] 注解的本地结构指针变量(如 # includes/ast/parser.vp _fix_store_ctx 里 `tp: rawptr[Tuple] = # (rawptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的 # builtins 分支把 rawptr[X] 折叠为 i8*(PtrCount=1/CVoid),既不登记 # var_struct_class 也不保留内层 X —— 单级 Name 字段取值(tp.elts) # 在属性访问层 ClassName 解析为 None → 求值 None → 赋值被 fail-fast # 拦截(parser.vp L427 bootstrap 根因)。与上方 BinOp 联合的短名回退 # 对称:把内层 X 解析为真实 struct 键(兼容短名 / 带 class_sha1 前缀 # 的键)并登记;仅在缺失或指针占位(rawptr…)时覆盖,不碰已精确登记值。 _rst_sub: ast.AST | None = None if isinstance(Node.annotation, ast.Subscript): _rst_v: ast.expr = Node.annotation.value _rst_nm: str = '' if isinstance(_rst_v, ast.Name): _rst_nm = _rst_v.id elif isinstance(_rst_v, ast.Attribute) and isinstance(_rst_v.value, ast.Name): _rst_nm = f'{_rst_v.value.id}.{_rst_v.attr}' if _rst_nm in ('rawptr', 't.CPtr'): _rst_sub = Node.annotation if _rst_sub is not None: _rst_sl: ast.AST = _rst_sub.slice if hasattr(ast, 'Index') and isinstance(_rst_sl, ast.Index): _rst_sl = _rst_sl.value _rst_tn: str = '' if isinstance(_rst_sl, ast.Name): _rst_tn = _rst_sl.id elif isinstance(_rst_sl, ast.Attribute) and isinstance(_rst_sl.value, ast.Name): _rst_tn = _rst_sl.attr _rst_tk: str | None = None if _rst_tn: if _rst_tn in Gen.structs: _rst_tk = _rst_tn else: _rst_sha: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(_rst_tn) if _rst_sha and f'{_rst_sha}.{_rst_tn}' in Gen.structs: _rst_tk = f'{_rst_sha}.{_rst_tn}' else: for _rst_k3 in Gen.structs: _rst_short3: str = _rst_k3.split('.')[-1] if '.' in _rst_k3 else _rst_k3 if _rst_short3 == _rst_tn: _rst_tk = _rst_k3 break if _rst_tk: _rst_cur: str | None = Gen.var_struct_class.get(VarName) _rst_need: bool = (not _rst_cur or _rst_cur == 'rawptr' or '.rawptr' in _rst_cur or _rst_cur.startswith('rawptr[')) if _rst_need and _rst_cur != _rst_tk: Gen.var_struct_class[VarName] = _rst_tk if getattr(Gen, 'global_struct_class', None) is not None: Gen.global_struct_class[VarName] = _rst_tk # 检测指针到指针缓冲区变量:注解为 StructName | t.CPtr,且赋值来自 t.CPtr(...) 调用。 # 这种变量(如 list[T].__getitem__ 中的 elem_ptr: T | t.CPtr = t.CPtr(...)) # 实际指向存储结构体指针的缓冲区(T=AST|t.CPtr 时特化为 AST*,缓冲区存 AST* 数组)。 # [index] 应 bitcast 为 AST** 后 GEP 指针数组再 load,而非 GEP 结构体数组。 # 泛型特化将 T|t.CPtr 降级为 StructName|t.CPtr(丢失一层指针),故通过赋值来源区分: # elem_ptr 的值是 t.CPtr(buf + idx*elem_size)(原始指针运算,缓冲区内容未知), # pts 的值是 (Point|t.CPtr)(...)(类型转换,明确指向 Point 结构体)。 _is_cptr_assign: bool = ( isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Attribute) and isinstance(Node.value.func.value, ast.Name) and Node.value.func.value.id == 't' and Node.value.func.attr == 'CPtr' ) _is_struct_ptr_union: bool = ( isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) and ((IsCPtrNode(Node.annotation.left) and isinstance(Node.annotation.right, ast.Name) and (Node.annotation.right.id in Gen.structs or _IsGenericTpName(Node.annotation.right.id))) or (IsCPtrNode(Node.annotation.right) and isinstance(Node.annotation.left, ast.Name) and (Node.annotation.left.id in Gen.structs or _IsGenericTpName(Node.annotation.left.id)))) ) if _is_cptr_assign and _is_struct_ptr_union: Gen.var_ptr_element[VarName] = True Gen.global_var_ptr_element[VarName] = True if VarName in Gen._reg_values: OldVal: ir.Value = Gen._reg_values[VarName] if isinstance(OldVal.type, ir.PointerType): var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) Gen._store(OldVal, var) Gen.variables[VarName] = var del Gen._reg_values[VarName] if Node.value: InitValue: ir.Value | None = self._EvalRhsWithTargetHint(Node, VarType, Gen) if InitValue: self._StoreOrStrCopy(VarName, var, InitValue) elif isinstance(Node.value, ast.Attribute): # 防静默:带值带注解属性链求值失败禁止跳过(见 __function.vp # 两级链 blk = func.Blocks.Head 编译产物 store 丢失根因)。 self._RaiseUnresolvedExpr("带注解赋值", Node.value, Gen, Node.annotation, VarName) Gen._record_var_signedness(VarName, IsUnsigned) return del Gen._reg_values[VarName] InitValue: ir.Value | None = None RhsBlock: ir.Block | None = Gen.builder.block if Gen.builder is not None else None RhsInsnStart: int = len(RhsBlock.instructions) if RhsBlock is not None else -1 if Node.value: InitValue = self._EvalRhsWithTargetHint(Node, VarType, Gen) # 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型 if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): CalledName: str = Node.value.func.id if CalledName in Gen._closure_return_types: Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName] if InitValue is None and Node.value is not None: # 防静默(通用判据,不再只认 ast.Attribute):带值带注解赋值 RHS # 求值为 None 且非"按类型即无值"(未以返回 void 的调用收尾)时, # 变量 alloca 已创建却无 store → 后续 load 读未初始化栈变量 # (运行期随机崩溃;如类型下标被当乘法的 list[X*]*(...) 整条 RHS # 不产任何指令)。判据取自实际发射的指令,见 _RhsEndsWithVoidCall。 if not self._RhsEndsWithVoidCall(Gen, RhsBlock, RhsInsnStart): self._RaiseUnresolvedExpr("带注解赋值", Node.value, Gen, Node.annotation, VarName) if VarName in Gen._reg_values: del Gen._reg_values[VarName] if VarName in Gen.variables and Gen.variables[VarName] is not None: if InitValue and isinstance(InitValue.type, ir.PointerType): pointee: ir.Type = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): struct_name: str = getattr(pointee, 'name', '') is_vtable_class: bool = False for cls_name in Gen.class_vtable: if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: is_vtable_class = True break if is_vtable_class: var: ir.AllocaInstr = Gen._allocaEntry(InitValue.type, name=VarName) Gen._store(InitValue, var) Gen.variables[VarName] = var if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: Gen.var_struct_class[VarName] = Node.annotation.id Gen.global_struct_class[VarName] = Node.annotation.id Gen._record_var_signedness(VarName, IsUnsigned) return if InitValue: try: VarPtr: ir.Value = Gen.variables[VarName] if isinstance(VarPtr.type, ir.PointerType): TargetType: ir.Type = VarPtr.type.pointee if InitValue.type != TargetType: # 统一走 `_coerce_value`(隐式转换的唯一收敛点): # 此前这里手写 `zext/trunc`,整型加宽一律 zext ⇒ 负常量被当无符号 # 处理(现场:`b: int64 = -196608` 落成 0x00000000FFFD0000 大正数, # IntWidthTest Test 5/6 的 FAIL)。`_coerce_value` 对 i32→i64 用 # `sext` 保持符号,隐式窄化亦按规则 fail-fast。 _coerced: ir.Value | None = Gen._coerce_value(InitValue, TargetType, Node) if _coerced is not None: InitValue = _coerced Gen._store(InitValue, VarPtr) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") Gen._record_var_signedness(VarName, IsUnsigned) return if VarName in Gen.global_vars: if VarName in Gen.module.globals: GVar: ir.GlobalVariable = Gen.module.globals[VarName] if InitValue: Gen._store(InitValue, GVar) Gen.variables[VarName] = GVar Gen._record_var_signedness(VarName, IsUnsigned) return var: ir.AllocaInstr = Gen._allocaEntry(VarType, name=VarName) if InitValue and isinstance(InitValue.type, ir.PointerType): pointee: ir.Type = InitValue.type.pointee # 当 InitValue 是 i8* (t.CPtr) 且注解是 Gen.structs 中的结构体名时, # bitcast 为对应的结构体指针,以便正确存储和设置 var_struct_class # 例如: sub: dict = sub_p (sub_p 是 t.CPtr) if (isinstance(pointee, ir.IntType) and pointee.width == 8 and isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs): TargetStructType: ir.Type = Gen.structs[Node.annotation.id] if isinstance(TargetStructType, ir.PointerType): TargetStructType = TargetStructType.pointee InitValue = Gen.builder.bitcast(InitValue, ir.PointerType(TargetStructType), name=f"cast_{VarName}_to_{Node.annotation.id}") pointee = InitValue.type.pointee if isinstance(pointee, ir.IdentifiedStructType): struct_name: str = getattr(pointee, 'name', '') is_vtable_class: bool = False for cls_name in Gen.class_vtable: if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: is_vtable_class = True break if is_vtable_class and not isinstance(VarType, ir.PointerType): var = Gen._allocaEntry(InitValue.type, name=VarName) VarType = InitValue.type IsPtr = True Gen._store(InitValue, var) Gen.variables[VarName] = var if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: Gen.var_struct_class[VarName] = Node.annotation.id Gen.global_struct_class[VarName] = Node.annotation.id Gen._record_var_signedness(VarName, IsUnsigned) return # 方向判定用:取注解一侧的泛型基名(`Base[...]` 或 `Base[...] | t.CPtr` # 形态中的 Base)。此判据**不依赖泛型模板注册表**(list/dict 等内建 # 容器可能未登记),只做结构性识别;仅 Name 形态可识别,属性链 # (如 t.CPtr[...])不参与。 _ann_gen_base: str | None = None _ann_sub_side: ast.expr | None = None if isinstance(Node.annotation, ast.Subscript): _ann_sub_side = Node.annotation elif (isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)): for _ann_side in (Node.annotation.left, Node.annotation.right): if isinstance(_ann_side, ast.Subscript): _ann_sub_side = _ann_side break if _ann_sub_side is not None: _ann_base_v: ast.expr = _ann_sub_side.value # 兼容嵌套下标链(Base[...][...]):逐层剥到最内层 Name while isinstance(_ann_base_v, ast.Subscript): _ann_base_v = _ann_base_v.value if isinstance(_ann_base_v, ast.Name): _ann_gen_base = _ann_base_v.id # 「反向重建」方向判定(其二,见下方 _rb_is_upcast)所需的**注解侧 # 被指类**:注解被 TypeMerge 折叠成 i8*(rawptr[X] / t.CPtr[X],见 # 上方 635-684)时 VarType.pointee 不是结构体,此时用该处恢复进 # var_struct_class 的 X —— 那正是注解写明的被指类。 _ann_pointee: ir.Type | None = None if isinstance(VarType, ir.PointerType): _ap: ir.Type = VarType.pointee if isinstance(_ap, ir.IdentifiedStructType): _ann_pointee = _ap else: _ask: str | None = Gen.var_struct_class.get(VarName) _ann_st: ir.Type | None = Gen.structs.get(_ask) if _ask else None if isinstance(_ann_st, ir.PointerType): _ann_st = _ann_st.pointee _ann_pointee = _ann_st for CN, ST in Gen.structs.items(): # 泛型占位类型(T/U/V,如 GSList[T].Head 的元素类型)opaque 无 body, # 不参与变量类型重建/var_struct_class 设置:跟随 T* 会污染注解声明的 # 真实类型(如 BasicBlock*),导致后续字段访问/循环体翻译静默失败。 # (属性访问层已特化返回真实元素类型,此处为防御性兜底。) _cn_short: str = CN.split('.')[-1] if '.' in CN else CN if _IsGenericTpName(_cn_short): continue # rawptr 占位 struct('rawptr' / '{sha1}.rawptr' / 'rawptr[...]')是 # 模块限定联合 X | t.CPtr 被 resolver 退化的产物(无真实字段), # 绝不能覆盖注解已解析出的真实类名(如 Value)→ env_size_val.Next # 报 "属性在类 'rawptr' 中找不到"(FuncGenMixin.vp L307 根因)。 if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['): continue if pointee is ST or pointee == ST: # 若注解是泛型特化(如 ndarray[t.CDouble] | t.CPtr), # 构造正确的特化名(如 ndarray[double]),而非用 opaque 基础名 resolved_cn: str = CN if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) and '[' not in CN: for side in (Node.annotation.left, Node.annotation.right): if isinstance(side, ast.Subscript): bn: ast.expr = side.value bnm: str | None = bn.id if isinstance(bn, ast.Name) else (bn.attr if isinstance(bn, ast.Attribute) else None) # 归一化比较:CN 可能带 16 位 sha1 模块前缀 # (如 'e94ef9e139461915.list'),注解侧裸名为 # 'list',直接与 CN 比较恒不等 ⇒ 特化名恢复失败 # ⇒ 写入裸泛型基名 ⇒ .get() 按错误元素类型 # 分派崩溃。用 _cn_short(已去前缀)比较。 if bnm and bnm == _cn_short: sn2: ast.AST = side.slice if hasattr(ast, 'Index') and isinstance(sn2, ast.Index): sn2 = sn2.value r2: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(sn2) if r2: resolved_cn = f'{CN}[{r2[0]}]' break if resolved_cn != Gen.var_struct_class.get(VarName): Gen.var_struct_class[VarName] = resolved_cn Gen.global_struct_class[VarName] = resolved_cn if isinstance(VarType, ir.PointerType) and VarType.pointee is not ST and VarType.pointee != ST: # 方向判定:本重建的本意是「注解退化成裸基类 / i8*, # RHS 构造出精确特化 ⇒ 用 RHS 反向升级」(见 L765 注释)。 # 但 RHS 的 pointee 若为**裸泛型基类**(丢类型实参,如 # {sha1}.list)而注解一侧本身就是带类型实参的泛型 # (`Base[...]` 或 `Base[...] | t.CPtr`),以 RHS 重建 # alloca 会把注解已解析出的特化类型覆盖成裸基类 → 之后 # .get() 按错误元素类型分派(list[int].get 返回 i32)→ # inttoptr 截断指针 → 读垃圾 AST 节点崩溃 # (MatchGenMixin._handle_renum_match 现场根因)。 # 判据(_cn_short 无 '[' 且与注解泛型基名同名)只拦这一 # 确定的方向错误,属**结构性识别**而非兜底:注解退化为 # i8*/裸基类、RHS 精确特化的合法升级路径不受影响。 _rb_is_bare_generic: bool = ( _ann_gen_base is not None and '[' not in _cn_short and _cn_short == _ann_gen_base ) # 方向判定(其二):注解写明的被指类是 RHS 被指类的 # **基类**时,注解就是合法的「基类指针」声明,RHS 只是 # 继承上转 —— 以 RHS 重建 alloca 会把声明类型**窄化**成 # 派生类,使同一变量随后赋基类/兄弟类的值被指针隐式 # 转换 fail-fast 拦下(includes/ast/parser.vp # `node: rawptr[AST] = Name(...)` 之后 # `node = _new_const_str(...)` 现场根因)。 # 判据只拦「上转被窄化」这一个确定的方向错误:注解退化 # 成 i8*/裸占位(_ann_pointee 非其基类)时不受影响。 _rb_is_upcast: bool = ( _ann_pointee is not None and _ann_pointee is not ST and _ann_pointee != ST and Gen._IsInheritanceUpcastPointee(pointee, _ann_pointee) ) if not _rb_is_bare_generic and not _rb_is_upcast: var = Gen._allocaEntry(ir.PointerType(pointee), name=VarName) VarType = ir.PointerType(pointee) break if InitValue: try: if InitValue.type != VarType: if Gen._IsNoneValue(InitValue, Node.value): # None(空值常量)允许隐式转换为任意变量类型: # 指针→空指针,其余→零值(整数 0 / 浮点 0.0 / 聚合 zeroinitializer)。 InitValue = (ir.Constant(VarType, None) if isinstance(VarType, ir.PointerType) else Gen._ZeroConst(VarType)) elif isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType): # 统一走 `_coerce_value`(隐式转换的唯一收敛点):此处原先手写 # `zext`,整型加宽一律零扩展 ⇒ 负常量被当无符号处理。 # 现场:`b: int64 = -196608` 落成 4294770688(0x00000000FFFD0000) # ⇒ 随后 `b >> 1` 呈现“逻辑右移”假象(IntWidthTest Test 5/6)。 # `_coerce_value` 对 i32→i64 用 `sext` 保符号;隐式窄化按其规则 fail-fast。 _coerced_i: ir.Value | None = Gen._coerce_value(InitValue, VarType, Node.value) if _coerced_i is not None: InitValue = _coerced_i elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType): Allowed: bool Reason: str Allowed, Reason = Gen._ClassifyPtrImplicitConvert(InitValue.type, VarType, Node.value) if not Allowed: from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"指针隐式转换已禁止({Reason}):不能用指针类型 {InitValue.type} 初始化 " f"{VarName}: {VarType};如需转换请显式 cast(如 t.CPtr(...))" f"{Gen._DescribeValueNode(Node.value)}" ) InitValue = Gen.builder.bitcast(InitValue, VarType, name=f"cast_{VarName}") elif isinstance(VarType, ir.PointerType) and isinstance(InitValue.type, ir.IntType): InitValue = Gen.builder.inttoptr(InitValue, VarType, name=f"int2ptr_{VarName}") elif isinstance(VarType, ir.IntType) and isinstance(InitValue.type, ir.PointerType): # 指针 → 整数:隐式转换一律禁止(与 ViperC coerce_to_type 同口径) # (None 已在上方短路为零值,不会落到这里)。 from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"指针隐式转整数已禁止:不能用指针类型 {InitValue.type} 初始化整数变量 " f"{VarName}: {VarType};如需转换请显式 cast(如 t.CUInt64T(p) / t.CInt(p))" f"{Gen._DescribeValueNode(Node.value)}" ) # 大端局部变量:存储时 bswap InitValue = Gen._apply_bswap_if_big(InitValue, TypeInfo.ByteOrder, f"bswap_store_{VarName}") Gen._store(InitValue, var, Node=Node.value) except (TypeError, ValueError) as _e: # 仅回退 llvmlite 自身的类型/值错误;FailFastError 等一律上抛(不吞) if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") Gen.variables[VarName] = var Gen._record_var_signedness(VarName, IsUnsigned) # FakeDuck: 初始化影子结构体 a__meta__ 的字段 _meta_name_check: str = f"{VarName}__meta__" if _meta_name_check in Gen.variables and '_str' in Gen.structs: _meta_var_init: ir.Value = Gen.variables[_meta_name_check] _str_st: ir.Type = Gen.structs['_str'] # __data__ 字段 = 字符串指针 _data_off = Gen._get_member_offset('__data__', '_str') if _data_off is not None and InitValue: _data_ptr = Gen.builder.gep(_meta_var_init, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _data_off)], name=f"{VarName}_meta_data") Gen._store(InitValue, _data_ptr) # __mbuddy__ 字段 = NULL _mpool_off = Gen._get_member_offset('__mbuddy__', '_str') if _mpool_off is not None: _mpool_ptr = Gen.builder.gep(_meta_var_init, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _mpool_off)], name=f"{VarName}_meta_mbuddy") Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), _mpool_ptr) # FakeDuck: 从 with 上下文自动注入 requires 字段(如 __mbuddy__) self.Trans.ExprCallHandle._InjectRequiresFields(_meta_var_init, '_str', Gen) # 记录局部变量字节序 if TypeInfo.ByteOrder == 'big': if isinstance(VarType, ir.IntType) and VarType.width in (16, 32, 64): Gen.local_var_byteorders[VarName] = 'big' elif isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width in (16, 32, 64): Gen.local_var_byteorders[VarName] = 'big' if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): found_struct: str | None = FindStructNameInAnnotationWithContext( Node.annotation, self.Trans, Gen) # 若 FindStructNameInAnnotation 仅返回裸模板名(如 'ndarray'),但注解中 # 含泛型特化(如 numpy.ndarray[t.CDouble]),用 LLVM 类型名构造特化名 # (如 'ndarray[double]')。main.py 的 Gen.structs 可能只有 opaque 'ndarray', # 但 numpy 模块已特化 ndarray[double],方法调用通过 sha1 前缀查找。 if found_struct and '[' not in found_struct: for side in (Node.annotation.left, Node.annotation.right): if isinstance(side, ast.Subscript): base_node: ast.expr = side.value base_nm: str | None = None if isinstance(base_node, ast.Name): base_nm = base_node.id elif isinstance(base_node, ast.Attribute): base_nm = base_node.attr if base_nm and base_nm == found_struct: slice_node: ast.AST = side.slice if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index): slice_node = slice_node.value result: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node) if result: found_struct = f'{base_nm}[{result[0]}]' break if found_struct: Gen.var_struct_class[VarName] = found_struct Gen.global_struct_class[VarName] = found_struct if InitValue and isinstance(InitValue.type, ir.PointerType): pointee: ir.Type = InitValue.type.pointee if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: # rawptr 占位 struct 不参与覆盖(见 L706-711 说明) if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['): break Gen._var_to_heap_ptr[VarName] = InitValue # 不覆盖已设置的特化名(含 '['):opaque 基础类型(如 ndarray) # 会匹配到裸模板名,但注解已提供更精确的特化名(如 ndarray[double]) existing_cn: str | None = Gen.var_struct_class.get(VarName) if not (existing_cn and '[' in existing_cn) and CN != existing_cn: Gen.var_struct_class[VarName] = CN Gen.global_struct_class[VarName] = CN break if self.Trans.VarScopes: if TypeInfo: self.Trans.VarScopes[-1][VarName] = TypeInfo else: DefaultInfo: CTypeInfo = CTypeInfo() DefaultInfo.BaseType = t.CInt self.Trans.VarScopes[-1][VarName] = DefaultInfo elif isinstance(Node.target, ast.Attribute): if isinstance(Node.target.value, ast.Name) and Node.target.value.id == 'self': if Node.value: AttrVarType: Any = None try: if IsListAnnotation(Node.annotation): slice_node: ast.AST = Node.annotation.slice if isinstance(slice_node, ast.Name): AttrVarType = f't.CArray[{slice_node.id}]' elif isinstance(slice_node, ast.Tuple): elts: str = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts) AttrVarType = f't.CArray[{elts}]' elif isinstance(slice_node, ast.Attribute): # 还原 t.xxx 形式(如 t.CInt、t.CArray) if isinstance(slice_node.value, ast.Name): AttrVarType = f't.CArray[{slice_node.value.id}.{slice_node.attr}]' else: AttrVarType = f't.CArray[{ast.unparse(slice_node)}]' if AttrVarType is None: AttrTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) if AttrTypeInfo: AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"解析类型失败: {_e}", "Exception") _RhsBlock: ir.Block | None = Gen.builder.block if Gen.builder is not None else None _RhsInsnStart: int = len(_RhsBlock.instructions) if _RhsBlock is not None else -1 Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=AttrVarType) if Value: self._HandleAttributeStoreLlvm(Node.target, Value) elif not self._RhsEndsWithVoidCall(Gen, _RhsBlock, _RhsInsnStart): # 防静默(通用判据,不再只认 ast.Attribute):self 字段带注解 # 赋值右侧求值失败(None)必须报错,否则字段写被静默跳过。 self._RaiseUnresolvedExpr("self 字段带注解赋值", Node.value, Gen, Node.annotation, Node.target.attr) if Value: AttrName: str = Node.target.attr len_name: str = f'{AttrName}__len' ClassName: str | None = self._CurrentCpythonObjectClass if not ClassName: self_var: ir.Value | None = Gen.variables.get('self') if self_var: var_type: ir.Type = self_var.type if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType): var_type = var_type.pointee if isinstance(var_type, ir.PointerType): pointee: ir.Type = var_type.pointee for cn, st in Gen.structs.items(): if st == pointee: ClassName = cn break if ClassName and ClassName in Gen.class_members: for m_name, m_type in Gen.class_members[ClassName]: if m_name == len_name: list_len: ir.Constant | None = None if isinstance(Node.value, ast.List): list_len = ir.Constant(ir.IntType(64), len(Node.value.elts)) if list_len is not None: 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(len_name, ClassName) LenPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=len_name) Gen._store(list_len, LenPtr) break