根因:多处手写 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 项失败。
1254 lines
84 KiB
Python
1254 lines
84 KiB
Python
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 |