Files
TransPyC/lib/core/Handles/HandlesAnnAssign.py
T
TermiNexus aaf9330b3b fix(tpc): 负数常量与负值整型加宽改为保符号,sext 与常量折叠,不再零扩展
根因:多处手写 zext 做整型加宽,把有符号为负的常量当无符号处理。涉及 HandlesAnnAssign 局部标量初始化两处、HandlesExprCall 的 typedef 与 builtins 强转两处。

一元负号对常量无条件发运行期 neg,常量 -1 变成 neg i32 指令后再被零扩展成 4294967295。

_eval_global_const 用无符号读回值取负,-196608 被物化成 4294770688 即 0x00000000FFFD0000。

现场:b 为 int64 等于 -196608 后,b 右移 1 呈逻辑右移假象,负数右移循环不收敛,见 IntWidthTest Test 5 与 Test 6。

改法:统一收敛到 _coerce_value,加宽用 sext,窄化按其规则 fail-fast;一元负号对常量直接折叠为有符号常量;_eval_global_const 先按位宽还原带符号真值。

另修右移符号性:去掉 emit_binary_op 里按 self._last_var_name 的残留变量名重判,调用方改按 _check_node_unsigned 判定。

验收:Test/IntWidthTest 10 项全 PASS,此前 TPC 侧 5 项通过 2 项失败。
2026-10-14 20:49:35 +08:00

1254 lines
84 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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