修正了 TPC 的一些错误,包括 Test 维护后 TPV 无法重新编译或重编译后越界的部分问题
This commit is contained in:
@@ -9,7 +9,7 @@ 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, FindStructNameInAnnotation, AnnotationContainsName
|
||||
from lib.core.SymbolUtils import IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotation, AnnotationContainsName, IsCPtrNode
|
||||
|
||||
|
||||
class AnnAssignHandle(BaseHandle):
|
||||
@@ -105,6 +105,16 @@ class AnnAssignHandle(BaseHandle):
|
||||
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]:
|
||||
if IsUnion:
|
||||
NestedStructName: str = f"{ClassName}_{AttrName}"
|
||||
@@ -139,8 +149,16 @@ class AnnAssignHandle(BaseHandle):
|
||||
if isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if TargetType.width < Value.type.width:
|
||||
Value = Gen.builder.trunc(Value, TargetType, name="trunc")
|
||||
else:
|
||||
Value = Gen.builder.zext(Value, TargetType, name="zext")
|
||||
elif TargetType.width > Value.type.width:
|
||||
if Value.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
Value = Gen.builder.zext(Value, TargetType, name="zext")
|
||||
else:
|
||||
is_unsigned: bool = id(Value) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
Value = Gen.builder.zext(Value, TargetType, name="zext")
|
||||
else:
|
||||
Value = Gen.builder.sext(Value, TargetType, name="sext")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
|
||||
Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType):
|
||||
@@ -468,6 +486,33 @@ class AnnAssignHandle(BaseHandle):
|
||||
if VarName not in Gen.var_struct_class:
|
||||
Gen.var_struct_class[VarName] = TypeInfo.Name
|
||||
Gen.global_struct_class[VarName] = TypeInfo.Name
|
||||
# 检测指针到指针缓冲区变量:注解为 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 (IsCPtrNode(Node.annotation.right)
|
||||
and isinstance(Node.annotation.left, ast.Name)
|
||||
and Node.annotation.left.id in Gen.structs))
|
||||
)
|
||||
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):
|
||||
@@ -511,14 +556,22 @@ class AnnAssignHandle(BaseHandle):
|
||||
VarPtr: ir.Value = Gen.variables[VarName]
|
||||
if isinstance(VarPtr.type, ir.PointerType):
|
||||
TargetType: ir.Type = VarPtr.type.pointee
|
||||
if InitValue.type != TargetType:
|
||||
if isinstance(InitValue.type, ir.IntType) and isinstance(TargetType, ir.IntType):
|
||||
if TargetType.width > InitValue.type.width:
|
||||
InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}")
|
||||
elif TargetType.width < InitValue.type.width:
|
||||
InitValue = Gen.builder.trunc(InitValue, TargetType, name=f"trunc_{VarName}")
|
||||
elif isinstance(InitValue.type, ir.PointerType) and isinstance(TargetType, ir.PointerType):
|
||||
InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}")
|
||||
if InitValue.type != TargetType:
|
||||
if isinstance(InitValue.type, ir.IntType) and isinstance(TargetType, ir.IntType):
|
||||
if TargetType.width > InitValue.type.width:
|
||||
if InitValue.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}")
|
||||
else:
|
||||
is_unsigned: bool = (Node.value is not None and Gen._check_node_unsigned(Node.value)) or id(InitValue) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}")
|
||||
else:
|
||||
InitValue = Gen.builder.sext(InitValue, TargetType, name=f"sext_{VarName}")
|
||||
elif TargetType.width < InitValue.type.width:
|
||||
InitValue = Gen.builder.trunc(InitValue, TargetType, name=f"trunc_{VarName}")
|
||||
elif isinstance(InitValue.type, ir.PointerType) and isinstance(TargetType, ir.PointerType):
|
||||
InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}")
|
||||
Gen._store(InitValue, VarPtr)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
@@ -567,9 +620,25 @@ class AnnAssignHandle(BaseHandle):
|
||||
return
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee is ST or pointee == ST:
|
||||
if CN != Gen.var_struct_class.get(VarName):
|
||||
Gen.var_struct_class[VarName] = CN
|
||||
Gen.global_struct_class[VarName] = CN
|
||||
# 若注解是泛型特化(如 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)
|
||||
if bnm and bnm == CN:
|
||||
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:
|
||||
var = Gen._allocaEntry(ir.PointerType(pointee), name=VarName)
|
||||
VarType = ir.PointerType(pointee)
|
||||
@@ -579,7 +648,15 @@ class AnnAssignHandle(BaseHandle):
|
||||
if InitValue.type != VarType:
|
||||
if isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType):
|
||||
if VarType.width > InitValue.type.width:
|
||||
InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}")
|
||||
if InitValue.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}")
|
||||
else:
|
||||
is_unsigned: bool = (Node.value is not None and Gen._check_node_unsigned(Node.value)) or id(InitValue) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}")
|
||||
else:
|
||||
InitValue = Gen.builder.sext(InitValue, VarType, name=f"sext_{VarName}")
|
||||
elif VarType.width < InitValue.type.width:
|
||||
InitValue = Gen.builder.trunc(InitValue, VarType, name=f"trunc_{VarName}")
|
||||
elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType):
|
||||
@@ -622,6 +699,27 @@ class AnnAssignHandle(BaseHandle):
|
||||
|
||||
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
|
||||
found_struct: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
# 若 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
|
||||
@@ -632,7 +730,10 @@ class AnnAssignHandle(BaseHandle):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
Gen._var_to_heap_ptr[VarName] = InitValue
|
||||
if CN != Gen.var_struct_class.get(VarName):
|
||||
# 不覆盖已设置的特化名(含 '['):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
|
||||
|
||||
@@ -536,7 +536,15 @@ class AssignHandle(BaseHandle):
|
||||
if DefVal.type != expected_type:
|
||||
if isinstance(expected_type, ir.IntType) and isinstance(DefVal.type, ir.IntType):
|
||||
if DefVal.type.width < expected_type.width:
|
||||
DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}")
|
||||
if DefVal.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}")
|
||||
else:
|
||||
is_unsigned: bool = Gen._check_node_unsigned(arg_def[def_idx]) or id(DefVal) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}")
|
||||
else:
|
||||
DefVal = Gen.builder.sext(DefVal, expected_type, name=f"sext_default_{arg_idx}")
|
||||
elif DefVal.type.width > expected_type.width:
|
||||
DefVal = Gen.builder.trunc(DefVal, expected_type, name=f"trunc_default_{arg_idx}")
|
||||
CallArgs.append(DefVal)
|
||||
@@ -802,6 +810,21 @@ class AssignHandle(BaseHandle):
|
||||
(isinstance(_ObjPointee, ir.IdentifiedStructType) and isinstance(_TargetStruct, ir.IdentifiedStructType) and
|
||||
(_ObjPointee.name == _TargetStruct.name or
|
||||
Gen._extract_short_name(_ObjPointee.name) == Gen._extract_short_name(_TargetStruct.name)))))
|
||||
# opaque 泛型结构体 → 特化版本 bitcast
|
||||
# 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub),
|
||||
# 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者 short name 不同
|
||||
# (GSList vs GSList[BasicBlock]),_MatchesStruct 失败。
|
||||
# 验证特化 short name 以 基础名+'[' 开头,bitcast 到特化版本使后续 GEP 能正确访问字段。
|
||||
if (not _MatchesStruct
|
||||
and isinstance(ObjVal.type, ir.PointerType)
|
||||
and isinstance(_ObjPointee, ir.IdentifiedStructType)
|
||||
and isinstance(_TargetStruct, ir.IdentifiedStructType)
|
||||
and '[' in ClassName):
|
||||
_BaseShort: str = Gen._extract_short_name(_ObjPointee.name)
|
||||
_SpecShort: str = Gen._extract_short_name(_TargetStruct.name)
|
||||
if _BaseShort and _SpecShort.startswith(_BaseShort + '['):
|
||||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_TargetStruct), name=f"cast_spec_{ClassName}")
|
||||
_MatchesStruct = True
|
||||
if isinstance(ObjVal.type, ir.PointerType) and _MatchesStruct:
|
||||
if IsUnion:
|
||||
NestedStructName: str = f"{ClassName}_{AttrName}"
|
||||
|
||||
@@ -220,6 +220,11 @@ class ClassHandle(BaseHandle):
|
||||
Gen.global_vars = saved_global_vars
|
||||
self.Trans.VarScopes = saved_var_scopes
|
||||
Gen._generic_class_specializations[spec_key] = (spec_name, declare_only)
|
||||
# 缓存 type_args/type_names,供后续 declare_only=False 完整特化补发方法体使用
|
||||
# (如 _HandleMethodCallLlvm 中发现方法未定义时触发)
|
||||
if not hasattr(Gen, '_generic_class_spec_type_info'):
|
||||
Gen._generic_class_spec_type_info = {}
|
||||
Gen._generic_class_spec_type_info[spec_key] = (list(type_args), list(type_names) if type_names else None)
|
||||
if not hasattr(self.Trans, '_generic_class_specializations'):
|
||||
self.Trans._generic_class_specializations = {}
|
||||
self.Trans._generic_class_specializations[spec_key] = spec_name
|
||||
@@ -535,33 +540,50 @@ class ClassHandle(BaseHandle):
|
||||
if pm_name in parent_defaults:
|
||||
Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name]
|
||||
Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName]
|
||||
if ParentClass in Gen.class_methods:
|
||||
parent_methods: list = list(Gen.class_methods[ParentClass])
|
||||
# 构建子类已有方法映射(方法短名 -> 方法全名)
|
||||
child_method_map: dict[str, str] = {}
|
||||
for m in Gen.class_methods[ClassName]:
|
||||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||||
child_method_map[method_name] = m
|
||||
# 父类方法在前(保证 vtable 布局一致性,子类多态分派索引正确),
|
||||
# 子类新增方法在后。子类覆盖的方法放在父类方法的位置(用子类实现)。
|
||||
new_methods: list = []
|
||||
covered_names: set[str] = set()
|
||||
for pm in parent_methods:
|
||||
method_name: str = pm.split('.')[-1] if '.' in pm else pm
|
||||
if method_name in child_method_map:
|
||||
# 子类覆盖了父类方法 — 用子类的实现,放在父类的位置
|
||||
new_methods.append(child_method_map[method_name])
|
||||
covered_names.add(method_name)
|
||||
else:
|
||||
# 父类独有方法 — 子类未覆盖,注册子类包装器
|
||||
child_method: str = f"{ClassName}.{method_name}"
|
||||
new_methods.append(child_method)
|
||||
Gen.register_method(ClassName, child_method)
|
||||
# 添加子类新增方法(不在父类中的)
|
||||
for m in Gen.class_methods[ClassName]:
|
||||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||||
if method_name not in covered_names:
|
||||
new_methods.append(m)
|
||||
if ParentClass in Gen.class_methods:
|
||||
parent_methods: list = list(Gen.class_methods[ParentClass])
|
||||
# 从 Node.body 收集子类自有方法(此时 Gen.class_methods[ClassName] 可能为空,
|
||||
# 因为自有方法在 L660-676 才注册。若直接用 Gen.class_methods[ClassName],
|
||||
# child_method_map 会为空,所有父类方法被当作"未覆盖"添加为包装器,
|
||||
# 然后 register_method 又把它们追加到 Gen.class_methods[ClassName],
|
||||
# L566 循环再次添加 → 产生重复条目,vtable 布局与导入模块不一致)
|
||||
child_method_map: dict[str, str] = {}
|
||||
child_self_methods_snapshot: list[str] = []
|
||||
for _item in Node.body:
|
||||
if isinstance(_item, ast.FunctionDef):
|
||||
_mname: str = _item.name
|
||||
if _mname in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
_item_meta: FuncMeta = self.Trans.FunctionHandler._ExtractFuncMeta(_item.decorator_list)
|
||||
if FuncMeta.PROPERTY_SETTER in _item_meta:
|
||||
_full: str = f"{ClassName}.{_mname}$set"
|
||||
elif FuncMeta.PROPERTY_DELETER in _item_meta:
|
||||
_full = f"{ClassName}.{_mname}$del"
|
||||
else:
|
||||
_full = f"{ClassName}.{_mname}"
|
||||
_short: str = _mname
|
||||
child_method_map[_short] = _full
|
||||
child_self_methods_snapshot.append(_full)
|
||||
# 父类方法在前(保证 vtable 布局一致性,子类多态分派索引正确),
|
||||
# 子类新增方法在后。子类覆盖的方法放在父类方法的位置(用子类实现)。
|
||||
new_methods: list = []
|
||||
covered_names: set[str] = set()
|
||||
for pm in parent_methods:
|
||||
method_name: str = pm.split('.')[-1] if '.' in pm else pm
|
||||
if method_name in child_method_map:
|
||||
# 子类覆盖了父类方法 — 用子类的实现,放在父类的位置
|
||||
new_methods.append(child_method_map[method_name])
|
||||
covered_names.add(method_name)
|
||||
else:
|
||||
# 父类独有方法 — 子类未覆盖,注册子类包装器
|
||||
child_method: str = f"{ClassName}.{method_name}"
|
||||
new_methods.append(child_method)
|
||||
Gen.register_method(ClassName, child_method)
|
||||
# 添加子类新增方法(不在父类中的)— 使用快照避免 register_method 污染
|
||||
for m in child_self_methods_snapshot:
|
||||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||||
if method_name not in covered_names:
|
||||
new_methods.append(m)
|
||||
Gen.class_methods[ClassName] = new_methods
|
||||
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
|
||||
if (Node.body and isinstance(Node.body[0], ast.Expr)
|
||||
@@ -609,6 +631,19 @@ class ClassHandle(BaseHandle):
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = element_class
|
||||
# 泛型特化结构体指针字段(如 GSList[BasicBlock] | t.CPtr):
|
||||
# 记录特化名,供后续 _try_access_opaque_generic_member 在所有候选特化版本
|
||||
# 都有目标字段(如 Head/Tail/Count)时选择正确特化版本。
|
||||
# 现有 i8* 分支不覆盖结构体指针字段,这里补充。
|
||||
elif (isinstance(MemberType, ir.PointerType)
|
||||
and isinstance(MemberType.pointee, ir.IdentifiedStructType)
|
||||
and isinstance(item.annotation, ast.BinOp)
|
||||
and isinstance(item.annotation.op, ast.BitOr)):
|
||||
spec_in_anno: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
|
||||
if spec_in_anno and '[' in spec_in_anno:
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = spec_in_anno
|
||||
if hasattr(TypeInfo.BaseType, 'IsSigned'):
|
||||
Gen.class_member_signeds[ClassName][VarName] = TypeInfo.BaseType.IsSigned
|
||||
else:
|
||||
|
||||
@@ -377,6 +377,12 @@ class ExprHandle(BaseHandle):
|
||||
if VarName in Gen.global_struct_class:
|
||||
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
|
||||
return VarPtr
|
||||
# 防御性恢复:对于 double-pointer(如 ndarray**,pointee 是 PointerType)
|
||||
# 或其他非结构体类型,若 global_struct_class 已记录该变量的类名,
|
||||
# 也恢复 var_struct_class。这确保方法调用能查找到正确的特化类
|
||||
# (如 ndarray[double]),而非 fallback 到 opaque 基础类型。
|
||||
if VarName in Gen.global_struct_class and VarName not in Gen.var_struct_class:
|
||||
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
|
||||
loaded: ir.Value = Gen._load(VarPtr, name=VarName)
|
||||
# 大端局部变量:读取时 bswap 还原
|
||||
loaded = Gen._apply_bswap_if_big(loaded, getattr(Gen, 'local_var_byteorders', {}).get(VarName, ""), f"bswap_load_{VarName}")
|
||||
|
||||
@@ -87,15 +87,71 @@ class ExprAttrHandle(BaseHandle):
|
||||
return (ST2, CN2)
|
||||
return None
|
||||
|
||||
def _try_access_opaque_generic_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, opaque_struct: Any, Node: ast.Attribute, orig_CN: str) -> ir.Value | None:
|
||||
"""通过特化版本访问 opaque 非特化泛型结构体成员。"""
|
||||
spec_result: Any = self._find_specialized_struct_with_body(Gen, opaque_struct)
|
||||
if spec_result is None:
|
||||
def _try_access_opaque_generic_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, opaque_struct: Any, Node: ast.Attribute, orig_CN: str, parent_hint: str | None = None) -> ir.Value | None:
|
||||
"""通过特化版本访问 opaque 非特化泛型结构体成员。
|
||||
|
||||
遍历所有候选特化版本(如 GSList[Param]/GSList[NameEntry]),
|
||||
优先选择 class_members 中包含 Node.attr 字段的版本,
|
||||
避免选到错误特化版本(如 GSList[NameEntry] 而非 GSList[Param])
|
||||
导致 _get_member_offset 返回 None 而生成 ret null。
|
||||
|
||||
parent_hint: 父上下文提供的特化提示(如 'GSList[BasicBlock]'),
|
||||
当所有候选都有目标字段(如 Head/Tail/Count)时,
|
||||
用此提示选择正确特化版本。"""
|
||||
# 收集所有候选特化版本(有 body 的)
|
||||
candidates: list[tuple[ir.IdentifiedStructType, str]] = []
|
||||
if isinstance(opaque_struct, ir.IdentifiedStructType):
|
||||
base_name: str = opaque_struct.name or ""
|
||||
short_name: str = base_name.split('.')[-1] if '.' in base_name else base_name
|
||||
if short_name and '[' not in short_name:
|
||||
for CN2, ST2 in Gen.structs.items():
|
||||
if not isinstance(ST2, ir.IdentifiedStructType):
|
||||
continue
|
||||
if ST2 is opaque_struct:
|
||||
continue
|
||||
if ST2.elements is None:
|
||||
continue
|
||||
st2_short: str = (ST2.name or "").split('.')[-1] if '.' in (ST2.name or "") else (ST2.name or "")
|
||||
if st2_short.startswith(short_name + '['):
|
||||
candidates.append((ST2, CN2))
|
||||
if not candidates:
|
||||
return None
|
||||
# 优先级 1: parent_hint 精确匹配(如 'GSList[BasicBlock]')
|
||||
# 当父对象字段声明记录了特化名时,直接使用,避免 Head/Tail/Count 等公共字段歧义
|
||||
if parent_hint:
|
||||
hint_short: str = parent_hint.split('.')[-1] if '.' in parent_hint else parent_hint
|
||||
for spec_st, spec_CN in candidates:
|
||||
spec_short: str = spec_CN.split('.')[-1] if '.' in spec_CN else spec_CN
|
||||
if spec_short == hint_short:
|
||||
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
|
||||
for lookup_CN in (spec_CN, orig_CN):
|
||||
bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {})
|
||||
if Node.attr in bitfield_offsets:
|
||||
return self._load_bitfield_member(CastedObj, lookup_CN, Node.attr)
|
||||
offset: int | None = Gen._get_member_offset(Node.attr, lookup_CN)
|
||||
if offset is not None:
|
||||
return self._gep_and_Load_member(Gen, CastedObj, offset, Node.attr, lookup_CN, spec_st)
|
||||
break
|
||||
# 优先级 2: class_members 中包含 Node.attr 字段的特化版本
|
||||
best_candidate: tuple[ir.IdentifiedStructType, str] | None = None
|
||||
for spec_st, spec_CN in candidates:
|
||||
for lookup_CN in (spec_CN, orig_CN):
|
||||
lookup_short: str = lookup_CN.split('.')[-1] if '.' in lookup_CN else lookup_CN
|
||||
for chk_CN in (lookup_CN, lookup_short):
|
||||
if chk_CN in Gen.class_members:
|
||||
if any(name == Node.attr for name, _ in Gen.class_members[chk_CN]):
|
||||
best_candidate = (spec_st, spec_CN)
|
||||
break
|
||||
if best_candidate:
|
||||
break
|
||||
if best_candidate:
|
||||
break
|
||||
if best_candidate is None:
|
||||
best_candidate = candidates[0]
|
||||
spec_st: ir.IdentifiedStructType
|
||||
spec_CN: str
|
||||
spec_st, spec_CN = spec_result
|
||||
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
|
||||
spec_st, spec_CN = best_candidate
|
||||
CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(spec_st), name=f"cast_spec_{orig_CN}")
|
||||
for lookup_CN in (spec_CN, orig_CN):
|
||||
bitfield_offsets: Any = Gen.class_member_bitoffsets.get(lookup_CN, {})
|
||||
if Node.attr in bitfield_offsets:
|
||||
@@ -467,14 +523,33 @@ class ExprAttrHandle(BaseHandle):
|
||||
ClassName = CN
|
||||
struct_match = self._check_struct_match(Gen, ObjVal, ClassName)
|
||||
# 最终回退:var_struct_class 可能被前一个函数污染(如 cur 在不同函数中
|
||||
# 分别是 Line/Param/BasicBlock),通过 ObjVal 的实际 pointee 类型恢复正确类名
|
||||
# 分别是 Line/Param/BasicBlock),通过 ObjVal 的实际 pointee 类型恢复正确类名。
|
||||
# 但若 var_struct_class 已记录特化名(如 ndarray[double]),且 ObjVal 的
|
||||
# pointee 是对应的 opaque 基础类型(如 ndarray),则 bitcast 到特化版本,
|
||||
# 不覆盖为裸模板名(否则后续方法调用会查找 ndarray.xxx 而非 ndarray[double].xxx)
|
||||
if not struct_match and isinstance(ObjVal.type, ir.PointerType):
|
||||
found: Any = Gen.find_struct_by_pointee(ObjVal.type.pointee)
|
||||
if found:
|
||||
ClassName = found[0]
|
||||
struct_match = True
|
||||
if VarName:
|
||||
Gen.var_struct_class[VarName] = ClassName
|
||||
found_name: str = found[0]
|
||||
# 检查 var_struct_class 是否已记录 found_name 的特化版本
|
||||
preserved: bool = False
|
||||
if VarName and VarName in Gen.var_struct_class:
|
||||
cur_spec: str = Gen.var_struct_class[VarName]
|
||||
if ('[' in cur_spec
|
||||
and cur_spec.split('[')[0] == found_name
|
||||
and cur_spec in Gen.structs):
|
||||
# bitcast ObjVal (opaque base*) 到特化类型指针,保留特化名
|
||||
ObjVal = Gen.builder.bitcast(
|
||||
ObjVal, ir.PointerType(Gen.structs[cur_spec]),
|
||||
name=f"cast_spec_{cur_spec}")
|
||||
ClassName = cur_spec
|
||||
struct_match = True
|
||||
preserved = True
|
||||
if not preserved:
|
||||
ClassName = found_name
|
||||
struct_match = True
|
||||
if VarName:
|
||||
Gen.var_struct_class[VarName] = ClassName
|
||||
elif isinstance(ObjVal.type.pointee, ir.IdentifiedStructType):
|
||||
# sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时,
|
||||
# 用短名匹配,优先选字段最多的完整版本
|
||||
@@ -490,7 +565,17 @@ class ExprAttrHandle(BaseHandle):
|
||||
best_elem_count = elem_count
|
||||
struct_match = True
|
||||
if struct_match and VarName:
|
||||
Gen.var_struct_class[VarName] = ClassName
|
||||
# 同样保护特化名:若已记录的特化名的短名基础部分与 ClassName 匹配,保留
|
||||
cur_spec2: str = Gen.var_struct_class.get(VarName, '')
|
||||
if ('[' in cur_spec2
|
||||
and cur_spec2.split('[')[0] == ClassName
|
||||
and cur_spec2 in Gen.structs):
|
||||
ObjVal = Gen.builder.bitcast(
|
||||
ObjVal, ir.PointerType(Gen.structs[cur_spec2]),
|
||||
name=f"cast_spec_{cur_spec2}")
|
||||
ClassName = cur_spec2
|
||||
else:
|
||||
Gen.var_struct_class[VarName] = ClassName
|
||||
if not struct_match:
|
||||
return None
|
||||
|
||||
@@ -611,11 +696,23 @@ class ExprAttrHandle(BaseHandle):
|
||||
|
||||
# 已知结构体类型 → 直接成员访问
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
# 提取父上下文特化提示:当 Node.value 是 Attribute(Name, attr) 时,
|
||||
# 从 var_struct_class 和 class_member_element_class 获取字段声明的特化名。
|
||||
# 例如 func.Blocks.Head 中,func 是 Function,Blocks 字段声明为 GSList[BasicBlock],
|
||||
# 提示为 'GSList[BasicBlock]',避免在所有 GSList[T] 都有 Head 字段时选错特化版本。
|
||||
parent_hint: str | None = None
|
||||
if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name):
|
||||
p_var: str = Node.value.value.id
|
||||
p_attr: str = Node.value.attr
|
||||
p_CN: str | None = Gen.var_struct_class.get(p_var)
|
||||
if p_CN:
|
||||
p_elem_map: Any = Gen.class_member_element_class.get(p_CN, {})
|
||||
parent_hint = p_elem_map.get(p_attr)
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name):
|
||||
st, ok = self._try_Load_struct_from_stub(Gen, CN)
|
||||
if not isinstance(st, ir.IdentifiedStructType) or st.elements is None:
|
||||
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN)
|
||||
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN, parent_hint)
|
||||
if spec_val is not None:
|
||||
return spec_val
|
||||
break
|
||||
@@ -824,12 +921,16 @@ class ExprAttrHandle(BaseHandle):
|
||||
# 但 HandleExprLlvm 已自动 load 返回 AST*(一级指针),
|
||||
# 需要检查 Gen.variables 中的原始 alloca 类型,
|
||||
# 若是二级指针且存储的是结构体指针,应 bitcast ValueVal 为 AST** 后 GEP 再 load,
|
||||
# 避免 GEP AST 结构体数组返回错误的 AST*(指向存储位置而非实际对象)
|
||||
# 避免 GEP AST 结构体数组返回错误的 AST*(指向存储位置而非实际对象)。
|
||||
# 仅当 var_ptr_element 标记为 True 时触发(由 AnnAssign 检测 (S|t.CPtr)|t.CPtr 注解设置),
|
||||
# 防止 pts: Point | t.CPtr(简单结构体指针)错误走二级指针路径。
|
||||
if (isinstance(Node.value, ast.Name)
|
||||
and isinstance(ValueVal.type, ir.PointerType)
|
||||
and isinstance(ValueVal.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))):
|
||||
VarName: str = Node.value.id
|
||||
if VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
_vpe_load: bool = (getattr(Gen, 'var_ptr_element', {}).get(VarName, False)
|
||||
or getattr(Gen, 'global_var_ptr_element', {}).get(VarName, False))
|
||||
if _vpe_load and VarName in Gen.variables and Gen.variables[VarName] is not None:
|
||||
VarAlloca: ir.Value = Gen.variables[VarName]
|
||||
if (isinstance(VarAlloca.type, ir.PointerType)
|
||||
and isinstance(VarAlloca.type.pointee, ir.PointerType)):
|
||||
|
||||
@@ -1272,7 +1272,13 @@ class ExprCallHandle(BaseHandle):
|
||||
if expected_type.width < val.type.width:
|
||||
return Gen.builder.trunc(val, expected_type)
|
||||
else:
|
||||
return Gen.builder.zext(val, expected_type)
|
||||
if val.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
return Gen.builder.zext(val, expected_type, name="zext")
|
||||
is_unsigned: bool = id(val) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
return Gen.builder.zext(val, expected_type, name="zext")
|
||||
return Gen.builder.sext(val, expected_type, name="sext")
|
||||
if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType):
|
||||
if expected_type.width == 64:
|
||||
return Gen.builder.ptrtoint(val, expected_type)
|
||||
@@ -1625,7 +1631,14 @@ class ExprCallHandle(BaseHandle):
|
||||
return ArgVal
|
||||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType):
|
||||
if ArgVal.type.width < TargetType.width:
|
||||
return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
|
||||
if ArgVal.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
|
||||
# C cast 语义:源有符号 → sext;源无符号 → zext;目标符号性仅影响解释
|
||||
is_unsigned: bool = (Node.args and Gen._check_node_unsigned(Node.args[0])) or id(ArgVal) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast")
|
||||
return Gen.builder.sext(ArgVal, TargetType, name=f"sext_{TypedefName}_cast")
|
||||
elif ArgVal.type.width > TargetType.width:
|
||||
return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast")
|
||||
return ArgVal
|
||||
@@ -1754,7 +1767,15 @@ class ExprCallHandle(BaseHandle):
|
||||
if default_val.type != param_type:
|
||||
if isinstance(param_type, ir.IntType) and isinstance(default_val.type, ir.IntType):
|
||||
if default_val.type.width < param_type.width:
|
||||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||||
if default_val.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||||
else:
|
||||
is_unsigned: bool = Gen._check_node_unsigned(default_node) or id(default_val) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}")
|
||||
else:
|
||||
default_val = Gen.builder.sext(default_val, param_type, name=f"sext_default_{i}")
|
||||
elif default_val.type.width > param_type.width:
|
||||
default_val = Gen.builder.trunc(default_val, param_type, name=f"trunc_default_{i}")
|
||||
elif isinstance(param_type, ir.PointerType) and isinstance(default_val.type, ir.IntType):
|
||||
@@ -1823,7 +1844,16 @@ class ExprCallHandle(BaseHandle):
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType):
|
||||
adjusted.append(Gen.builder.ptrtoint(arg, param_type))
|
||||
elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width:
|
||||
adjusted.append(Gen.builder.zext(arg, param_type))
|
||||
if arg.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
adjusted.append(Gen.builder.zext(arg, param_type, name=f"zext_vararg_fixed_{i}"))
|
||||
else:
|
||||
arg_node = Node.args[i] if i < len(Node.args) else None
|
||||
is_unsigned: bool = (arg_node is not None and Gen._check_node_unsigned(arg_node)) or id(arg) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
adjusted.append(Gen.builder.zext(arg, param_type, name=f"zext_vararg_fixed_{i}"))
|
||||
else:
|
||||
adjusted.append(Gen.builder.sext(arg, param_type, name=f"sext_vararg_fixed_{i}"))
|
||||
elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.PointerType):
|
||||
adjusted.append(Gen.builder.bitcast(arg, param_type, name=f"cast_arg_{i}"))
|
||||
else:
|
||||
@@ -1994,6 +2024,23 @@ class ExprCallHandle(BaseHandle):
|
||||
else:
|
||||
# 跨模块基类 — 查找基类的 sha1
|
||||
base_sha1 = struct_sha1_map.get(base_name)
|
||||
# 回退:若 _struct_sha1_map 未命中(普通类导入时不填充),
|
||||
# 扫描 temp/ 下所有 .pyi 查找包含该基类定义的文件
|
||||
if base_sha1 is None:
|
||||
temp_dir = os.path.join(project_root, 'temp')
|
||||
try:
|
||||
pyi_files = os.listdir(temp_dir)
|
||||
except OSError:
|
||||
pyi_files = []
|
||||
for pyi_file in pyi_files:
|
||||
if not pyi_file.endswith('.pyi'):
|
||||
continue
|
||||
candidate_sha1 = pyi_file[:-4]
|
||||
candidate_map = load_pyi(candidate_sha1)
|
||||
if candidate_map and base_name in candidate_map:
|
||||
base_sha1 = candidate_sha1
|
||||
struct_sha1_map[base_name] = base_sha1
|
||||
break
|
||||
if base_sha1:
|
||||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
|
||||
if base_novtable:
|
||||
@@ -2049,6 +2096,63 @@ class ExprCallHandle(BaseHandle):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _try_complete_generic_specialization(self, ClassName: str, MethodName: str, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""泛型特化类方法按需完整特化。
|
||||
|
||||
当 ClassName 是泛型特化名(如 ndarray[double])且缓存中只有
|
||||
declare_only 版本时,补发方法体。这样方法调用能找到 define,
|
||||
避免链接时 undefined reference。
|
||||
|
||||
触发场景:numpy 模块内部函数(如 np_sum)调用 a.sum(),
|
||||
其中 a 的类型注解 ndarray[t.CDouble] | t.CPtr 在类型解析时
|
||||
只触发了 declare_only=True 特化(创建 struct + __before_init__),
|
||||
方法体(fill/delete/dot/sum/...)未被编译。
|
||||
"""
|
||||
# 仅对特化名(含 '[' 且以 ']' 结尾)触发
|
||||
if '[' not in ClassName or not ClassName.endswith(']'):
|
||||
return
|
||||
# 反推模板类名(如 ndarray[double] → ndarray)
|
||||
base_name: str = ClassName.split('[')[0]
|
||||
# 检查是否是已注册的泛型模板
|
||||
if not (hasattr(self.Trans.ClassHandler, '_generic_class_templates') and base_name in self.Trans.ClassHandler._generic_class_templates):
|
||||
return
|
||||
# 构造 spec_key(与 _specialize_generic_class 一致:ClassName<arg1,arg2,...>)
|
||||
spec_key: str = base_name + '<' + ','.join(ClassName[len(base_name) + 1:-1].split('][')) + '>'
|
||||
spec_cache = getattr(Gen, '_generic_class_specializations', {})
|
||||
cached = spec_cache.get(spec_key)
|
||||
if not isinstance(cached, tuple) or len(cached) < 2:
|
||||
return
|
||||
cached_name: str = cached[0]
|
||||
was_declare_only: bool = cached[1]
|
||||
# 仅当缓存是 declare_only 版本时才需要补发
|
||||
if not was_declare_only:
|
||||
return
|
||||
# 检查方法是否已有 define(blocks 非空表示已编译方法体)
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
class_sha1 = struct_sha1_map.get(cached_name)
|
||||
full_method_name: str = f'{class_sha1}.{cached_name}.{MethodName}' if class_sha1 else f'{cached_name}.{MethodName}'
|
||||
existing_func = Gen._find_function(full_method_name)
|
||||
if existing_func is not None:
|
||||
existing_blocks = getattr(existing_func, 'blocks', [])
|
||||
if existing_blocks:
|
||||
return # 方法体已编译
|
||||
# 从缓存获取 type_args/type_names
|
||||
type_info = getattr(Gen, '_generic_class_spec_type_info', {}).get(spec_key)
|
||||
if type_info is None:
|
||||
return
|
||||
cached_type_args, cached_type_names = type_info
|
||||
# 不预先标记:_specialize_generic_class 内部缓存逻辑会检测
|
||||
# cached_declare_only=True 且 declare_only=False,自动补发方法体
|
||||
# 并更新缓存为 (spec_name, False)。预注册机制(L117)防止递归。
|
||||
try:
|
||||
self.Trans.ClassHandler._specialize_generic_class(
|
||||
base_name, cached_type_args, Gen,
|
||||
type_names=cached_type_names, declare_only=False
|
||||
)
|
||||
except Exception:
|
||||
# 失败时恢复 declare_only 标记,避免后续调用跳过补发
|
||||
Gen._generic_class_specializations[spec_key] = (cached_name, True)
|
||||
|
||||
def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value:
|
||||
Gen = self.Trans.LlvmGen
|
||||
MethodName = Node.func.attr
|
||||
@@ -2425,6 +2529,25 @@ class ExprCallHandle(BaseHandle):
|
||||
break
|
||||
if not ClassName:
|
||||
return ir.Constant(ir.IntType(32), 0)
|
||||
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray',不含 '[')
|
||||
# 且注解未指定类型参数时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
|
||||
# (如 'ndarray[double]'),优先选有对应方法的特化。这样方法调用能正确分派到
|
||||
# 特化版本的方法(如 ndarray[double].delete),而非查找 opaque stub declare。
|
||||
if '[' not in ClassName:
|
||||
SpecClass: str | None = None
|
||||
for CN in Gen.structs.keys():
|
||||
if not CN.startswith(f'{ClassName}['):
|
||||
continue
|
||||
struct_sha1_tmp = getattr(Gen, '_struct_sha1_map', {}).get(CN)
|
||||
if struct_sha1_tmp:
|
||||
if Gen._has_function(f'{struct_sha1_tmp}.{CN}.{MethodName}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if Gen._has_function(f'{CN}.{MethodName}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if SpecClass:
|
||||
ClassName = SpecClass
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
class_sha1 = struct_sha1_map.get(ClassName)
|
||||
if class_sha1:
|
||||
@@ -2432,6 +2555,11 @@ class ExprCallHandle(BaseHandle):
|
||||
else:
|
||||
FullMethodName = f'{ClassName}.{MethodName}'
|
||||
|
||||
# 泛型特化类方法按需完整特化:当 ClassName 是特化名(如 ndarray[double])
|
||||
# 且缓存中只有 declare_only 版本时,补发方法体。否则方法调用会查找
|
||||
# stub declare(无 define),链接时报 undefined reference。
|
||||
self._try_complete_generic_specialization(ClassName, MethodName, Gen)
|
||||
|
||||
# 提前查找函数以获取参数信息
|
||||
func_for_kw = Gen._find_function(FullMethodName)
|
||||
if not func_for_kw:
|
||||
@@ -2505,6 +2633,22 @@ class ExprCallHandle(BaseHandle):
|
||||
if func:
|
||||
break
|
||||
p = Gen.class_parent.get(p)
|
||||
# 修复:vtable 分派需要 func 的函数类型。当 func=None 时(如 __new__
|
||||
# 编译较早,MemManager.alloc 的 declare 尚未加入 Gen.functions),
|
||||
# 从 stub 获取函数类型并创建 declare,确保 vtable 分派不被跳过
|
||||
# 回退到直接调用(直接调用基类 MemManager.alloc 返回 NULL → 段错误)。
|
||||
if not func and class_sha1:
|
||||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen)
|
||||
if stub_func_type:
|
||||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||||
if not func and class_sha1:
|
||||
plain_name = f'{ClassName}.{MethodName}'
|
||||
stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen)
|
||||
if stub_func_type:
|
||||
func = self.GetOrCreateStubFuncDecl(FullMethodName, stub_func_type, Gen)
|
||||
if not func:
|
||||
plain_name = f'{ClassName}.{MethodName}'
|
||||
func = Gen._find_function(plain_name)
|
||||
if func:
|
||||
VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}")
|
||||
VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}")
|
||||
@@ -2790,8 +2934,18 @@ class ExprCallHandle(BaseHandle):
|
||||
return (ts, tn)
|
||||
# BinOp (如 AST | CPtr) 或 Attribute (如 t.CPtr / t.CInt)
|
||||
type_str: str = self._resolve_type_arg_str(sn)
|
||||
# type_name 取原始名称(不带模块前缀),用于 T 替换
|
||||
raw_name: str = self._get_raw_type_name(sn)
|
||||
# type_name 保留模块前缀(如 't.CUnsignedChar'),避免 T(0) 替换为
|
||||
# CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域而报
|
||||
# "Undefined function: 'CUnsignedChar'"。
|
||||
# t.CPtr 特殊处理:保留 'CPtr' 不带前缀,因为 cptr_params 检测依赖
|
||||
# _BUILTIN_TYPE_NAMES 中的 'CPtr' 来识别指针类型参数
|
||||
if isinstance(sn, ast.Attribute) and isinstance(sn.value, ast.Name):
|
||||
if sn.attr == 'CPtr':
|
||||
raw_name: str = 'CPtr'
|
||||
else:
|
||||
raw_name: str = f'{sn.value.id}.{sn.attr}'
|
||||
else:
|
||||
raw_name: str = self._get_raw_type_name(sn)
|
||||
return (type_str, raw_name)
|
||||
|
||||
def _ResolveGenericSlice(self, Sub: ast.Subscript) -> str | None:
|
||||
@@ -2823,7 +2977,13 @@ class ExprCallHandle(BaseHandle):
|
||||
while len(type_args) < len(type_param_names):
|
||||
type_args.append('int')
|
||||
type_names.append('CInt')
|
||||
return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names)
|
||||
# 类型注解解析(如 Float64Array: t.CTypedef = ndarray[t.CDouble])
|
||||
# 只需 struct 定义,不需方法体;使用 declare_only=True 避免过早触发
|
||||
# 完整特化(此时被引用的函数如 printf 可能尚未由 from X import Y 注册,
|
||||
# 导致 "Undefined function" 错误)。完整特化由后续类实例化
|
||||
# (_HandleClassNewLlvm → _specialize_generic_class(declare_only=False))
|
||||
# 触发,缓存机制会补发方法体。
|
||||
return self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names, declare_only=True)
|
||||
|
||||
@staticmethod
|
||||
def _AnnotationContainsCPtr(Node: ast.AST) -> bool:
|
||||
|
||||
@@ -71,6 +71,25 @@ class ExprUtils:
|
||||
FullMethodName: str = f'{ClassName}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{ClassName}.{op_name}__'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
# 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且
|
||||
# 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本
|
||||
# (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时,
|
||||
# var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。
|
||||
# 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。
|
||||
if '[' not in ClassName:
|
||||
SpecClass: str | None = None
|
||||
for CN in Gen.structs.keys():
|
||||
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'):
|
||||
SpecClass = CN
|
||||
break
|
||||
if SpecClass:
|
||||
FullMethodName = f'{SpecClass}.{op_name}'
|
||||
if not Gen._has_function(FullMethodName):
|
||||
FullMethodName = f'{SpecClass}.{op_name}__'
|
||||
if Gen._has_function(FullMethodName):
|
||||
func: Any = Gen._get_function(FullMethodName)
|
||||
call_args: list[Any] = [obj_val]
|
||||
|
||||
@@ -860,7 +860,10 @@ class FunctionHandle(BaseHandle):
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Name) and node.func.id in type_map:
|
||||
replacement: str = type_map[node.func.id]
|
||||
node.func = ast.Name(id=replacement, ctx=ast.Load())
|
||||
# 使用 _make_replacement_node 处理含点号的类型名(如 't.CUnsignedChar'),
|
||||
# 避免 T(0) 替换为 CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域
|
||||
# 而报 "Undefined function: 'CUnsignedChar'"
|
||||
node.func = self._make_replacement_node(replacement)
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map:
|
||||
replacement: str = type_map[node.func.value.id]
|
||||
@@ -874,7 +877,7 @@ class FunctionHandle(BaseHandle):
|
||||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||||
)
|
||||
else:
|
||||
node.func.value = ast.Name(id=replacement, ctx=ast.Load())
|
||||
node.func.value = self._make_name_node(replacement)
|
||||
else:
|
||||
self._apply_type_map_to_expr(node.func.value, type_map, cptr_params)
|
||||
for arg in node.args:
|
||||
@@ -1630,6 +1633,14 @@ class FunctionHandle(BaseHandle):
|
||||
saved_var_to_heap_ptr = dict(Gen._var_to_heap_ptr)
|
||||
Gen._local_heap_ptrs = []
|
||||
Gen._var_to_heap_ptr = {}
|
||||
# 治本修复:保存 var_struct_class / global_struct_class。
|
||||
# 当方法调用(如 a.delete())触发 _try_complete_generic_specialization 时,
|
||||
# 该路径走 _EmitFunctionLlvm 编译方法体,函数结尾会清空 var_struct_class。
|
||||
# 若不保存/恢复,外层函数中已设置的 var_struct_class(如 b='ndarray[double]')
|
||||
# 会被清空,导致后续方法调用 fallback 匹配 opaque 基础类型(如 ndarray),
|
||||
# 生成对 stub declare(无方法体)的调用 → 链接报 undefined reference。
|
||||
saved_var_struct_class = dict(Gen.var_struct_class) if Gen.var_struct_class else {}
|
||||
saved_global_struct_class = dict(Gen.global_struct_class) if getattr(Gen, 'global_struct_class', None) else {}
|
||||
# 函数内部定义的变量会在赋值时添加到 var_type_info 中
|
||||
# 这样函数内部定义的元类型变量(如 a = t.CInt32T)就能被正确处理
|
||||
for stmt in Node.body:
|
||||
@@ -1671,6 +1682,13 @@ class FunctionHandle(BaseHandle):
|
||||
if arg.annotation and isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
|
||||
param_name: str = ParamNames[i] if i < len(ParamNames) else arg.arg
|
||||
if param_name in Gen.variables:
|
||||
# 若 L1650-1657 已根据 param.type.pointee 匹配到正确的特化名
|
||||
# (如 ndarray[double]),不覆盖:FindStructNameInAnnotation 对
|
||||
# 泛型注解 ndarray[t.CDouble] 会构造 ndarray[CDouble](与实际
|
||||
# ndarray[double] 不匹配),回退到裸模板类名 ndarray(opaque),
|
||||
# 导致方法调用查找 ndarray.sum 而非 ndarray[double].sum。
|
||||
if param_name in Gen.var_struct_class:
|
||||
continue
|
||||
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
|
||||
if found_struct:
|
||||
Gen.var_struct_class[param_name] = found_struct
|
||||
@@ -1831,6 +1849,11 @@ class FunctionHandle(BaseHandle):
|
||||
# 恢复外层作用域的 _local_heap_ptrs / _var_to_heap_ptr
|
||||
Gen._local_heap_ptrs = saved_local_heap_ptrs
|
||||
Gen._var_to_heap_ptr = saved_var_to_heap_ptr
|
||||
# 恢复外层作用域的 var_struct_class / global_struct_class
|
||||
# (内层方法体编译不应污染外层函数的变量-类型映射)
|
||||
Gen.var_struct_class = saved_var_struct_class
|
||||
if hasattr(Gen, 'global_struct_class'):
|
||||
Gen.global_struct_class = saved_global_struct_class
|
||||
Gen._variadic_info = None
|
||||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||||
self.Trans.CurrentCReturnTypes = None
|
||||
|
||||
@@ -45,7 +45,15 @@ class ReturnHandle(BaseHandle):
|
||||
if Val.type != ExpectedType:
|
||||
if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < ExpectedType.width:
|
||||
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
|
||||
if Val.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
|
||||
else:
|
||||
is_unsigned: bool = Gen._check_node_unsigned(val) or id(Val) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}")
|
||||
else:
|
||||
Val = Gen.builder.sext(Val, ExpectedType, name=f"sext_ret_{i}")
|
||||
elif Val.type.width > ExpectedType.width:
|
||||
Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}")
|
||||
elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType):
|
||||
@@ -107,7 +115,15 @@ class ReturnHandle(BaseHandle):
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType):
|
||||
if Val.type.width < elem_type.width:
|
||||
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
|
||||
if Val.type.width == 1:
|
||||
# i1 是布尔值,无符号语义,必须 zext
|
||||
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
|
||||
else:
|
||||
is_unsigned: bool = (Node.value is not None and Gen._check_node_unsigned(Node.value)) or id(Val) in Gen._unsigned_results
|
||||
if is_unsigned:
|
||||
Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}")
|
||||
else:
|
||||
Val = Gen.builder.sext(Val, elem_type, name=f"sext_ret_{j}")
|
||||
elif Val.type.width > elem_type.width:
|
||||
Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}")
|
||||
result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}")
|
||||
|
||||
Reference in New Issue
Block a user