修正了 TPC 的一些错误,包括 Test 维护后 TPV 无法重新编译或重编译后越界的部分问题

This commit is contained in:
2026-07-20 11:12:30 +08:00
parent ab73420b4f
commit a277ded8d4
476 changed files with 4000 additions and 3439 deletions

View File

@@ -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

View File

@@ -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}"

View File

@@ -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:

View File

@@ -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}")

View File

@@ -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 冲突 fallbackfind_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 是 FunctionBlocks 字段声明为 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)):

View File

@@ -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
# 检查方法是否已有 defineblocks 非空表示已编译方法体)
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:

View File

@@ -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]

View File

@@ -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] 不匹配),回退到裸模板类名 ndarrayopaque
# 导致方法调用查找 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

View File

@@ -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}")

View File

@@ -204,3 +204,11 @@ def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name)
return False
def IsCPtrNode(node: ast.AST) -> bool:
"""检查节点是否为 t.CPtr 属性引用。"""
return (isinstance(node, ast.Attribute)
and isinstance(node.value, ast.Name)
and node.value.id == 't'
and node.attr == 'CPtr')