修复了一些错误

This commit is contained in:
TermiNexus committed 2026-09-18 20:00:59 +08:00
1 parent 6af2dea917
commit 2cc816ac13
16 files changed
+1155 -230

No files matched your search

+139 -55
View File
@@ -8,7 +8,9 @@ import llvmlite.ir as ir
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode
from lib.core.SymbolUtils import (
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode,
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr)
class DeclarationGenerator:
@@ -40,6 +42,13 @@ class DeclarationGenerator:
self.typedef_map: dict[str, ast.AST] = typedef_map or {}
self._pyi_tree: ast.Module | None = None
self._t_alias_map: dict[str, type] = {}
# 泛型模板类名(PEP 695 `class Box[T]`):声明端特化判定用,与定义端
# HandlesClassDef._generic_class_templates 同源(ClassDef 的 type_params
# 标记),generate() 里从本模块 pyi 与 class_def_map 收集
self._generic_class_names: set[str] = set()
# t/c 导入名表(from t import CInt as myint → 'myint' → ('t','CInt')),
# 与定义端 Trans._t_c_imported_names 同口径,供泛型实参串解析使用
self._t_c_imported_names: dict[str, tuple[str, str]] = {}
# 跨模块类定义映射:{class_name: ClassDef_node},供 _get_inherited_members
# 查找其他模块定义的父类(如 exprs.py 的 Name(AST) 查找 base.py 的 AST)
self._cross_module_class_defs: dict[str, ast.ClassDef] = class_def_map or {}
@@ -50,6 +59,16 @@ class DeclarationGenerator:
self._DefineConstants: dict[str, int | str] = {}
self._pyi_tree = tree
# 泛型模板类名(PEP 695 `class Box[T]`):class_def_map 覆盖所有已生成
# .vpi 的模块(含本模块),本模块 pyi 直接解析的 ClassDef 优先,
# 与定义端 HandlesClassDef 注册 _generic_class_templates 的判据一致
# (都只看 ClassDef.type_params 是否非空,不看类名白名单)。
self._generic_class_names = {
node.name for node in ast.iter_child_nodes(tree)
if isinstance(node, ast.ClassDef) and getattr(node, 'type_params', None)}
for _gc_name, _gc_node in self._cross_module_class_defs.items():
if getattr(_gc_node, 'type_params', None):
self._generic_class_names.add(_gc_name)
global_typedef_map: dict[str, ast.AST] = self.typedef_map
self.typedef_map: dict[str, ast.AST] = {}
if global_typedef_map:
@@ -57,12 +76,14 @@ class DeclarationGenerator:
# 构建 t/c 类型别名映射(from t import CInt as myint)
self._t_alias_map: dict[str, type] = {}
self._t_c_imported_names: dict[str, tuple[str, str]] = {}
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.ImportFrom):
if node.module in ('t', 'c'):
for alias in node.names:
name: str = alias.name
asname: str = alias.asname or name
self._t_c_imported_names[asname] = (node.module, name)
if node.module == 't':
t_cls: type | None = getattr(t, name, None)
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
@@ -1036,6 +1057,45 @@ class DeclarationGenerator:
"""
return base_type + '*' * self._ptr_level_of(cptr_sub_type)
def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str:
"""指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T],判据见
SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。
与定义端同源:SymbolUtils.DesugarPtrSubscriptToUnion 把三者折叠为等价
联合写法 `T | t.CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由
_MergeAllComponentTypes 的"struct 基类型吸收一层 CPtr"决定 —— 裸类引用
的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被吸收 → 结果
就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 /
联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 t.CPtr[...] 共用本条
规则(此前 t.CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得
list[X]*,同一指针语义两种结果)。
"""
inner: ast.AST = annotation.slice
inner_type: str = self._get_type_str(inner)
if self._is_bare_class_ref_annotation(inner, inner_type):
return inner_type
if inner_type in ('', 'void', 'void*'):
return 'i8*'
return f'{inner_type}*'
def _is_bare_class_ref_annotation(self, inner: ast.AST, inner_type: str) -> bool:
"""节点是否为"裸类引用"(本身即指针 → 吸收一层 t.CPtr)。
与 _get_type_str 的既有约定一致:类引用的**非** embedded 形式本身就是
指针('%"sha1.X"*'),所以 `AST | t.CPtr` 合并后仍是该指针(定义端
_MergeAllComponentTypes 的 struct 吸收)。联合写法(ast.BinOp)与指针
下标(rawptr[...] / t.CPtr[...])不是裸类引用——它们已自带指针层数,
须逐层外包(rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr
→ AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。
"""
if not inner_type:
return False
if isinstance(inner, ast.BinOp):
return False
if isinstance(inner, ast.Subscript):
return not (IsRawPtrSubscriptNode(inner) or IsCPtrSubscriptNode(inner))
return inner_type.startswith('%') and inner_type.endswith('*')
def _get_type_str(self, annotation: ast.AST | None, embedded: bool = False) -> str:
if annotation is None:
return 'i8*'
@@ -1164,13 +1224,23 @@ class DeclarationGenerator:
# t.CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的
# "first CPtr absorption" 语义:struct | t.CPtr → struct*(吸收,struct 变量默认是指针)。
# 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | t.CPtr → i8**(不吸收)。
# 例外:泛型特化类型(含 '[')回退为 i8*,避免引用未定义的特化结构体。
# 例外:LLVM 聚合数组([N x T],字符串以 '[' 开头)不可再外包指针层 → i8*。
# 注:具名泛型特化(%"mod.list[X]"*)**不**走此回退——stub 已由
# _collect_undefined_type_decls 为其补 opaque 声明,保留名字才能与 define 端
# 的 %"mod.list[ast.ASTptr]"* 逐字一致(原 `'[' in left_type` 会把
# list[X] | t.CPtr 一并退化成 i8*,与定义端 %"mod.list[X]"* 不一致)。
if right_type == 'i8*':
if '[' in left_type:
if left_type[:1] == '[':
return 'i8*'
if left_type in ('', 'void'):
return 'i8*'
if left_type.startswith('%"') and left_type.endswith('*'):
# 吸收仅对"裸类引用"成立(其非 embedded 形式本身即指针):
# ast.AST | t.CPtr → %"sha1.AST"*。已自带指针层数的左值
# (rawptr[...] / t.CPtr[...] 下标 / 联合写法)须逐层外包:
# rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr → AST**
# ——与定义端 _CollectAllOperandTypes 整体拉平、只吸收一次 CPtr
# (_MergeAllComponentTypes 的 base_ptr_count>0 分支)一致。
if self._is_bare_class_ref_annotation(annotation.left, left_type):
return left_type
if '*' in left_type:
return f'{left_type}*'
@@ -1185,27 +1255,40 @@ class DeclarationGenerator:
return self._merge_cptr_subscript(left_type, right_type)
if IsCPtrSubscriptNode(annotation.left) and right_type[:1] not in ('[', '{'):
return self._merge_cptr_subscript(right_type, left_type)
# t.CPtr 裸标记在左侧(t.CPtr | X):与右侧写法(X | t.CPtr,见上)
# 完全对称。缺此分支时左值 i8* 会吞掉右侧的指针层数:
# t.CPtr | rawptr[Node] 声明端曾得 i8*,而定义端为 %"sha1.Node"**(差一层)。
# 仅对裸标记 t.CPtr 生效(left 为 t.CPtr[T] 下标走上一条分支;
# str/bytes 等其它 i8* 左值不受影响)。
if IsCPtrNode(annotation.left) and right_type[:1] not in ('[', '{'):
if self._is_bare_class_ref_annotation(annotation.right, right_type):
return right_type
return f'{right_type}*'
if '*' in left_type:
return left_type
if '*' in right_type:
return right_type
return left_type
elif isinstance(annotation, ast.Subscript):
base: str = self._get_type_str(annotation.value)
if base == 'i8*' and isinstance(annotation.slice, ast.Constant):
return f'[{self._get_const_int(annotation.slice)} x i8]'
# 处理 t.CPtr[Type] 语法(指向 Type 的指针)
# 例如: t.CPtr[t.CPtr] -> i8** (void**), t.CPtr[t.CInt] -> i32* (int*)
# t.CPtr[t.CPtr[t.CInt]] -> i32** (int**)
# 指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带
# 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | t.CPtr`:与定义端
# **同一判据**(SymbolUtils.IsPtrSubscriptNode,别名经本模块的
# _t_c_imported_names 表解析 X→CPtr)+ 同一层数规则
# (_ptr_subscript_type_str:裸类引用吸收一层、其余逐层外包),内层 T
# 照常解析(跨模块类由 struct_sha1_map 补 SHA1 前缀)。此前 rawptr[T]
# 在此退化成 i8*,t.CPtr[T] 走的是"embedded + 追加一层"的独立分支:
# 非同一规则,且对泛型容器特化多出一层(t.CPtr[list[X]] 得 list[X]**,
# 而 rawptr[list[X]] 得 list[X]*)。
ValueIsCPtr: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
)
if ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)):
slice_type: str = self._get_type_str(annotation.slice, embedded=True)
if slice_type and slice_type != 'void':
return f'{slice_type}*'
return 'i8*'
if (IsPtrSubscriptNode(annotation, TCAliasMap=self._t_c_imported_names)
or (ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)))):
return self._ptr_subscript_type_str(annotation)
base: str = self._get_type_str(annotation.value)
if base == 'i8*' and isinstance(annotation.slice, ast.Constant):
return f'[{self._get_const_int(annotation.slice)} x i8]'
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
return f'[{annotation.slice.value} x {base}]'
# 处理 t.CArray[elem_type, count] / rawarray[elem_type, count] 注解 → [count x elem_type]
@@ -1235,49 +1318,50 @@ class DeclarationGenerator:
else:
elem_types = [self._get_type_str(slice_node, embedded=True)]
return '{ ' + ', '.join(elem_types) + ' }'
# 处理泛型类类型注解(如 list[str])
# 处理泛型类类型注解(如 list[str] / list[rawptr[ast.AST]] /
# 用户泛型类 Box[Node])
# 实参串走 SymbolUtils.ResolveGenericTypeArgStr(与定义端
# _mangle_generic_class_name 同一规则源):此前只认 Name / Name-Tuple
# 实参,Attribute(ast.AST)/ Subscript(rawptr[...])/ BinOp
# (X | t.CPtr)/ 混合 Tuple 一律退回未特化的 %"...list"*,
# 与 define 端发射的 %"<mod>.list[ast.ASTptr]" 不一致
# (Undefined method / 签名错位)。
# 内建容器(non_struct_types)之外,**用户泛型类**同样特化:判据
# _generic_class_names(ClassDef.type_params,与定义端
# HandlesClassDef._generic_class_templates 同源),此前只有内建容器名
# 会特化 → Box[Node] 字段在 stub 端是 %"<mod>.Box"*、定义端是
# %"<mod>.Box[<已解析实参>]"*(Holder 字段布局两侧不一致)。
if isinstance(annotation.value, ast.Name):
gc_name: str = annotation.value.id
if gc_name in non_struct_types and gc_name != 'tuple':
if (gc_name in non_struct_types or gc_name in self._generic_class_names) \
and gc_name != 'tuple':
gc_slice: ast.AST = annotation.slice
gc_args: list[str] = []
if isinstance(gc_slice, ast.Name):
gc_args.append(gc_slice.id)
elif isinstance(gc_slice, ast.Tuple):
gc_valid: bool = True
for gc_elt in gc_slice.elts:
if isinstance(gc_elt, ast.Name):
gc_args.append(gc_elt.id)
else:
gc_valid = False
break
if not gc_valid:
gc_args = []
if gc_args:
gc_mangled: list[str] = []
for gc_ta in gc_args:
# t.CPtr/CPtr → 'ptr'(与 _resolve_type_arg_str 的
# 泛型 mangling 一致);NameToLLVM('CPtr') 返回 'i8*'
# 会导致声明端 'list[i8*]' 与特化端 'list[ptr]' 不匹配
if gc_ta == 'CPtr':
gc_mangled.append('ptr')
continue
gc_llvm: str | None = CTypeRegistry.NameToLLVM(gc_ta)
if gc_llvm:
if gc_llvm in ('float', 'double', 'half', 'fp128'):
gc_cls: type | None = CTypeRegistry.GetClassByName(gc_ta)
gc_sz: int = gc_cls().Size if gc_cls else 0
gc_mangled.append('f' + str(gc_sz))
else:
gc_mangled.append(gc_llvm)
else:
gc_mangled.append(gc_ta)
gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']'
gc_sha1: str | None = self.module_sha1
gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}'
if embedded:
return gc_sname
return f'{gc_sname}*'
# 多参数泛型(dict[K, V]):'][' 分隔,与
# _mangle_generic_class_name 一致
gc_nodes: list[ast.AST] = (
list(gc_slice.elts) if isinstance(gc_slice, ast.Tuple) else [gc_slice])
gc_mangled: list[str] = [
ResolveGenericTypeArgStr(
gc_node,
TCAliasMap=self._t_c_imported_names,
StructSha1Map=self.struct_sha1_map)
for gc_node in gc_nodes]
gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']'
# 特化名前缀取**泛型模板类定义模块**的 SHA1(list → includes/_list.vp、
# Box → 定义 Box 的模块,查 struct_sha1_map 即"类名 → 定义模块"表),
# 与定义端 HandlesClassDef._specialize_generic_class 的
# Gen.module_sha1 = template['sha1']、调用点
# Gen._struct_sha1_map[spec_name] 同一条规则源。
# 此前用 self.module_sha1(使用方模块):同一特化在 declare(使用方前缀)
# 与 define/call(模板模块前缀)两侧不一致 → 跨模块 undefined symbol。
gc_sha1: str | None = self.struct_sha1_map.get(gc_name, self.module_sha1)
gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}'
# 一律以指针引用(不区分 embedded):定义端对嵌入式泛型容器
# (字段 / t.CArray 元素)用不透明指针(实测字段 i8*,见
# FieldForms/FieldBox/FieldOrder),嵌入 unsized opaque
# 结构体值会让字段/元素偏移错位;非 embedded(参数/返回)
# 亦与定义端同为指针
return f'{gc_sname}*'
return f'{base}'
elif isinstance(annotation, ast.Constant):
if annotation.value is None:
+7 -4
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, IsCPtrNode
from lib.core.SymbolUtils import IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotationWithContext, AnnotationContainsName, IsCPtrNode
def _IsGenericTpName(name: str) -> bool:
@@ -492,7 +492,8 @@ class AnnAssignHandle(BaseHandle):
self._HandleGenericListLiteralAssign(VarName, Node, Gen, list_sub)
return
if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp):
found: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
found: str | None = FindStructNameInAnnotationWithContext(
Node.annotation, self.Trans, Gen)
if found:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CStruct(name=found)
@@ -547,7 +548,8 @@ class AnnAssignHandle(BaseHandle):
# FindStructNameInAnnotation 以 attr/短名命中,找回真实类名。
if (isinstance(Node.annotation, ast.BinOp)
and isinstance(Node.annotation.op, ast.BitOr)):
_union_struct_name2: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
_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 通过并登记错误类名 → 字段
@@ -876,7 +878,8 @@ class AnnAssignHandle(BaseHandle):
Gen.local_var_byteorders[VarName] = 'big'
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
found_struct: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
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',
+113 -2
View File
@@ -13,6 +13,7 @@ from lib.constants import config as _config
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
from lib.core.SymbolUtils import IsPtrSubscriptNode, IsListAnnotation
from lib.core.VLogger import get_logger as _vlog
@@ -754,6 +755,17 @@ class BaseHandle:
"""解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。
统一处理函数返回类型和参数类型的 BinOp 联合类型解析。
指针下标(rawptr[T] 内置裸指针 / t.CPtr[T] / 裸名 CPtr[T],三者等价
`T | t.CPtr`)同样交给 TypeMerge 解析:内层 T 走通用类型解析(含跨模块
类经 Gen.structs 反查 SHA1 前缀),指针层数与源码 `T | t.CPtr` 一致;
若交给 CTypeInfo.FromNode(TypeAnnotationResolver)解析,
rawptr[ast.AST] 会退化成 CVoid/1(i8*)、t.CPtr[ast.AST] 亦退化成
CVoid/1(其 Subscript-CPtr 分支不带 Gen.structs 反查),与 declare 端
%"<sha1>.AST"* 分裂。
命中泛型模板的泛型容器下标(list[X] / rawptr[list[X]] 等)同样交
TypeMerge:字段(embedded)位置与参数/返回注解**同一解析**,否则
CTypeInfo.FromNode 把容器折叠成 i8*,字段类型与 declare/stub 端
的特化名指针不一致(同一结构体在定义端/声明端布局描述不同)。
"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
@@ -761,7 +773,90 @@ class BaseHandle:
info: CTypeInfo | None = merger.MergeTypes(annotation)
if info is not None and isinstance(info, CTypeInfo):
return info
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
merger = getattr(self.Trans, 'TypeMergeHandler', None)
if merger:
info = merger.GetCTypeInfo(annotation)
if isinstance(info, CTypeInfo) and info.BaseType is not None:
return info
if (isinstance(annotation, ast.Subscript)
and self._SubscriptHitsGenericTemplate(annotation)
and getattr(self.Trans, 'TypeMergeHandler', None) is not None):
gci: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
if isinstance(gci, CTypeInfo) and gci.BaseType is not None:
return gci
if isinstance(annotation, ast.Attribute):
return self._ResolveAttributeAnnotationType(annotation)
Fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
return self._ResolveStackArrayElementFallback(annotation, Fallback)
def _ResolveStackArrayElementFallback(
self, annotation: ast.expr, Fallback: CTypeInfo | None) -> CTypeInfo | None:
"""固定数组注解(`t.CArray[T, N]` / `list[T, N]`)元素类型兜底解析。
CTypeInfo.FromNode(TypeAnnotationResolver 的 IsListAnnotation 分支)只
会用自身解析元素类型:元素命中泛型模板时(list[X] / list[rawptr[X]])解
析为空 → 整个注解 BaseType=None → 调用方(CollectAnnAssignMember)把
VoidType 换成 i8*,字段即塌成 i8*,与声明端
DeclarationGenerator._get_type_str 的 ValueIsCArray 分支给出的
`[N x <元素>]` 布局不一致(规则 4:能不变 i8* 的就不变 i8*)。
此处仅在该元素解析为空时兜底:用**与参数注解同一解析**
(ResolveAnnotationType 递归,泛型容器因此走 TypeMerge 特化,跨模块类
经 Gen.structs 反查 SHA1)解析元素,再套上数组维度(维度序与
TypeAnnotationResolver 的 `insert(0, count)` 一致)。
元素可解析的形态(t.CArray[t.CInt, 8] / t.CArray[Node, 4] / 嵌套 CArray)
保持 FromNode 结果原样,避免改动既有布局。
"""
if isinstance(Fallback, CTypeInfo) and Fallback.BaseType is not None:
return Fallback
if not (isinstance(annotation, ast.Subscript) and IsListAnnotation(annotation)):
return Fallback
SliceNode: ast.AST = annotation.slice
if not (isinstance(SliceNode, ast.Tuple) and len(SliceNode.elts) == 2):
return Fallback
ElemInfo: CTypeInfo | None = self.ResolveAnnotationType(SliceNode.elts[0])
if not isinstance(ElemInfo, CTypeInfo) or ElemInfo.BaseType is None:
return Fallback
CountVal: int | None = CTypeInfo.TryEvalConstExpr(SliceNode.elts[1], self.Trans.SymbolTable)
if not isinstance(CountVal, int) or CountVal <= 0:
return Fallback
Result: CTypeInfo = ElemInfo.Copy()
Result.ArrayDims = [str(CountVal)] + list(ElemInfo.ArrayDims)
return Result
def _ResolveAttributeAnnotationType(self, annotation: ast.Attribute) -> CTypeInfo | None:
"""Attribute 注解(`t.CInt` / `ast.AST` / `<sha1>.CLS`)解析。
先走 CTypeInfo.FromNode(TypeAnnotationResolver,覆盖 t/c 内建与已在本模块
SymbolTable 注册的类):其 BaseType 已解析时语义不变。
**仅在 FromNode 解析不出来时**(BaseType 为 None,即该类未随本模块
import/预扫描注册)按类名查 `Gen.structs` / `Gen._struct_sha1_map` 后交
TypeMerge(HandlesTypeMerge 的 Attribute 分支,与声明端
DeclarationGenerator._get_type_str 的 `attr_name in struct_names`、名称域
SymbolUtils._ResolveAttributeArgStr 同一条"类名 → SHA1"规则)。
不修此路时跨模块类 Attribute(`rawptr[<sha1>.CLS]` 脱糖后的
`<sha1>.CLS | t.CPtr`、泛型 T 替换出的裸 `<sha1>.CLS`、`list[ast.AST]`
特化的 `append(item: T)`)在定义端判为"无法识别的参数类型注解"抛
SyntaxError,被上层 broad except 吞掉后退化为 i32/i8*,而声明端给
`%"<sha1>.CLS"*`,字段/签名两侧不一致。
"""
fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
if fallback is not None and fallback.BaseType is not None:
return fallback
attr_name: str = getattr(annotation, 'attr', '') or ''
gen: Any = getattr(self.Trans, 'LlvmGen', None)
if not attr_name or gen is None:
return fallback
if (attr_name not in getattr(gen, 'structs', {})
and attr_name not in getattr(gen, '_struct_sha1_map', {})):
return fallback
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
if merger is not None:
info: CTypeInfo | None = merger.GetCTypeInfo(annotation)
if isinstance(info, CTypeInfo) and info.BaseType is not None:
return info
return fallback
def ResolveParamAnnotation(self, annotation: ast.expr) -> CTypeInfo | None:
"""函数参数注解解析(阻塞 B 同根第三处修复)。
@@ -781,6 +876,13 @@ class BaseHandle:
info: CTypeInfo | None = merger.MergeTypes(annotation)
if info is not None and isinstance(info, CTypeInfo):
return info
# 指针下标参数注解(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T],含
# rawptr[list[X]] 等容器:_SubscriptHitsGenericTemplate 也命中,但统一交
# ResolveAnnotationType 处理更简单——它已把指针下标路由到 TypeMerge)。
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
info = self.ResolveAnnotationType(annotation)
if isinstance(info, CTypeInfo) and info.BaseType is not None:
return info
if isinstance(annotation, ast.Subscript) and getattr(self.Trans, 'TypeMergeHandler', None):
if self._SubscriptHitsGenericTemplate(annotation):
try:
@@ -789,7 +891,16 @@ class BaseHandle:
return _gci
except Exception:
pass
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
# Attribute 参数注解(`<sha1>.CLS` 裸引用 / 泛型 T 替换出的 `<sha1>.CLS`)
# 与 ResolveAnnotationType 共用同一条规则(_ResolveAttributeAnnotationType →
# TypeMergeHandler.GetCTypeInfo 的 Attribute 分支查 Gen.structs /
# Gen._struct_sha1_map),不在此复制第二套查表;否则 list[X] 特化方法
# `append(item: T)` 的参数 T(= 裸 `<sha1>.CLS`)解析为空 → VoidType →
# 抛"无法识别的参数类型注解" → 特化模板方法未注册。
if isinstance(annotation, ast.Attribute):
return self.ResolveAnnotationType(annotation)
Fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
return self._ResolveStackArrayElementFallback(annotation, Fallback)
def _SubscriptHitsGenericTemplate(self, annotation: ast.Subscript) -> bool:
"""判断 Subscript 是否命中泛型模板:裸模板名(list[X]/GSList[X]),
+133 -54
View File
@@ -8,7 +8,8 @@ import copy
import llvmlite.ir as ir
from lib.core.Exportable import EnumMember as ExportEnumMember
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.SymbolUtils import IsTModule, FindStructNameInAnnotation
from lib.core.SymbolUtils import (
IsTModule, FindStructNameInAnnotationWithContext, MangleTypeArgByRegistry)
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.includes import t
@@ -66,19 +67,52 @@ class ClassHandle(BaseHandle):
return False
def _mangle_generic_class_name(self, class_name: str, type_args: list[str]) -> str:
mangled_args: list[str] = []
for ta in type_args:
llvm_str: str | None = CTypeRegistry.NameToLLVM(ta)
if llvm_str:
if llvm_str in ('float', 'double', 'half', 'fp128'):
mangled: str = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size)
else:
mangled = llvm_str
else:
mangled = ta
mangled_args.append(mangled)
"""泛型类特化名:class_name + '[arg1][arg2]'。
单项 mangling 走 SymbolUtils.MangleTypeArgByRegistry(声明端
DeclarationGenerator 的泛型分支以 ResolveGenericTypeArgStr 调用同一函数,
两侧拼名规则唯一),'][' 分隔与 HandlesTypeMerge / DeclarationGenerator 一致。
"""
mangled_args: list[str] = [MangleTypeArgByRegistry(ta) for ta in type_args]
return class_name + '[' + ']['.join(mangled_args) + ']'
def _HasClassDefinition(self, Name: str, Gen: LlvmGeneratorMixin) -> bool:
"""类型名是否有类定义——泛型"类类型参数"的唯一判据。
数据来源就是"是否存在类定义"这一事实本身:Gen._struct_sha1_map
(类名 → 定义模块 SHA1,Phase2 从各 .vpi 扫描构建)与 Gen.structs
(本模块已发射的 struct 名,键形如 '{sha1}.{名}')。
因此内建值类型(int/CInt/…,LLVM 映射 i32 等)与语言内建 `str`
(LLVM 映射 i8*)都不在两张表里 → 自然判为值类型,不需要任何
内建名白名单/黑名单参与判定。
"""
if not Name:
return False
if Name in Gen._struct_sha1_map or Name in Gen.structs:
return True
for Sha1 in Gen._struct_sha1_map.values():
if f'{Sha1}.{Name}' in Gen.structs:
return True
return False
@staticmethod
def _BareClassAnnotationName(Node: ast.AST) -> str | None:
"""取注解节点的裸类名(供 class_type_names 判定),非类名形态返回 None。
T 替换后的两种形态都要认:
- ast.Name:'AST'(未注册类)或 'sha1.AST'(旧式点号名)→ 去前缀;
- ast.Attribute:'sha1.AST' 经 _make_replacement_node/_make_name_node
产出的 Attribute 链(Name('sha1').AST)→ attr 名。
其余(Union `X | t.CPtr`、Subscript `list[T]`、内建)→ None,不追加
指针层(已显式写了 `| t.CPtr` 的注解不再重复加层)。
"""
if isinstance(Node, ast.Name):
Name: str = Node.id
return Name.split('.')[-1] if '.' in Name else Name
if isinstance(Node, ast.Attribute):
return Node.attr
return None
def _specialize_generic_class(self, ClassName: str, type_args: list[str], Gen: LlvmGeneratorMixin, type_names: list[str] | None = None, declare_only: bool = False) -> str | None:
if not hasattr(self, '_generic_class_templates') or ClassName not in self._generic_class_templates:
return None
@@ -125,6 +159,17 @@ class ClassHandle(BaseHandle):
'int', 'double', 'float', 'i8', 'i16', 'i32', 'i64', 'void',
'half', 'fp128', 'char', 'bool',
}
# 值类型/类类型不再用"内建名白名单"判定:见下方 class_type_names,
# 唯一判据是"是否有类定义"(_HasClassDefinition:Gen._struct_sha1_map
# / Gen.structs)。内建(int/CInt/…)与语言内建 `str`(LLVM 映射 i8*)
# 都不在类表里 → 天然判为值类型,无需名表。
# 历史教训(名表判据的代价,保留以便回归时理解):`str` 曾漏在
# "非类类型名"集合外 → `list[str]` 的类型参数被误判为类类型,特化后
# 方法签名被额外包一层 `| t.CPtr`(append/set 形参 i8**、get/pop 返回
# i8**)→ 调用点多解一层 load(读字符串首 8 字节)→ ASan 崩溃。
# 注意 _BUILTIN_TYPE_NAMES 本身仍保留:它用于 type_map 替换
# 与 _t_c_imported_names 注册,不能把 'str' 并进去
# (否则 HandlesTypeMerge 会把注解 `str` 当 `t.str` 解析)。
type_map: dict[str, str] = {}
for i, tp_name in enumerate(type_param_names):
if type_names and i < len(type_names):
@@ -147,15 +192,15 @@ class ClassHandle(BaseHandle):
type_map[tp_name] = tn
else:
type_map[tp_name] = type_args[i]
# 检测哪些类型参数在原始类型实参中带有 | t.CPtr
# 当 type_arg 以 'ptr' 结尾(_resolve_type_arg_str 将 t.CPtr 规范化为 'ptr')
# 且对应的 type_name(去模块前缀后)不是内建类型名时,
# 说明调用方写了 list[AST | t.CPtr]。注意用 tn_bare 判断:
# 检测哪些类型参数在原始类型实参中带有指针语义(| t.CPtr / rawptr[T])
# 当 type_arg 以 '*' 结尾(mangling 把每个 CPtr 层渲染为一层 '*')且对应的
# type_name(去模块前缀后)不是内建类型名时,说明调用方写了
# list[AST | t.CPtr] / list[rawptr[AST]]。注意用 tn_bare 判断:
# 't.CPtr' 去前缀后是 'CPtr'(内建),不算类类型参数。
cptr_params: set[str] = set()
for i, tp_name in enumerate(type_param_names):
type_arg: str = type_args[i]
if type_arg.endswith('ptr'):
if type_arg.endswith('*'):
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
tn_bare_c: str = tn.split('.')[-1] if '.' in tn else tn
if tn_bare_c not in _BUILTIN_TYPE_NAMES:
@@ -163,12 +208,15 @@ class ClassHandle(BaseHandle):
# Bug 2 修复:识别特化为 class 类型的类型参数
# 这类参数在方法签名中是裸 T(无 | t.CPtr),特化后为裸 ClassName(值类型)
# 需要加 | t.CPtr 使其成为指针类型(class 实例应按指针传递)
# 判据 = "是否有类定义"(_HasClassDefinition),存**裸名**:注解侧的
# 比较也用裸名(T 替换后的 'sha1.Param' 去前缀)——此前存带模块前缀的
# tn(如 'ast.AST')而比较用裸名 'AST',前缀形态永不命中。
class_type_names: set[str] = set()
for i, tp_name in enumerate(type_param_names):
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
tn_bare_cls: str = tn.split('.')[-1] if '.' in tn else tn
if tn_bare_cls not in _BUILTIN_TYPE_NAMES:
class_type_names.add(tn)
if self._HasClassDefinition(tn_bare_cls, Gen):
class_type_names.add(tn_bare_cls)
# 仅对 t 模块内建类型名注册 _t_c_imported_names(如 CInt -> ('t','CInt'))
# 类名(如 AST)不应注册为 t.AST,否则会污染名称解析
if type_names:
@@ -189,30 +237,27 @@ class ClassHandle(BaseHandle):
if arg.annotation:
arg.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(arg.annotation, type_map, cptr_params)
# class 类型参数加指针语义:T -> GNode -> GNode | t.CPtr
# 去除 SHA1 前缀后检查(如 fc06023a9bcfc93a.AST -> AST)
if isinstance(arg.annotation, ast.Name):
raw_name: str = arg.annotation.id
if '.' in raw_name:
raw_name = raw_name.split('.')[-1]
if raw_name in class_type_names:
arg.annotation = ast.BinOp(
left=ast.Name(id=arg.annotation.id, ctx=ast.Load()),
op=ast.BitOr(),
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
)
if item.returns:
item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map, cptr_params)
# 返回类型也加指针语义
if isinstance(item.returns, ast.Name):
raw_name: str = item.returns.id
if '.' in raw_name:
raw_name = raw_name.split('.')[-1]
if raw_name in class_type_names:
item.returns = ast.BinOp(
left=ast.Name(id=item.returns.id, ctx=ast.Load()),
# T 替换后的真实形态是 Attribute 链('<sha1>.GNode' →
# Name('<sha1>').GNode,见 _make_replacement_node/_make_name_node),
# 不是 ast.Name:此前只认 ast.Name → 方法形参漏加 | t.CPtr,
# 特化后按值结构体传参(被调者栈帧副本地址入链 → 悬垂写)。
raw_name: str | None = self._BareClassAnnotationName(arg.annotation)
if raw_name is not None and raw_name in class_type_names:
arg.annotation = ast.BinOp(
left=arg.annotation,
op=ast.BitOr(),
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
)
if item.returns:
item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map, cptr_params)
# 返回类型也加指针语义(同一裸名判据,形态同上)
raw_name: str | None = self._BareClassAnnotationName(item.returns)
if raw_name is not None and raw_name in class_type_names:
item.returns = ast.BinOp(
left=item.returns,
op=ast.BitOr(),
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
)
self.Trans.FunctionHandler._apply_type_map_to_body(item.body, type_map, cptr_params)
saved_builder: ir.IRBuilder = Gen.builder
saved_func: ir.Function = Gen.func
@@ -228,7 +273,14 @@ class ClassHandle(BaseHandle):
# 切换 module_sha1 为泛型模板定义模块的 SHA1,
# 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀,
# 与调用端 _struct_sha1_map 查到的 SHA1 一致。
template_sha1: str | None = template.get('sha1')
template_sha1: str | None = template.get('sha1')
if not template_sha1:
# 模板注册表缺 sha1 时回退到"模板类定义模块"(_struct_sha1_map 即
# 类名 → 定义模块表,Phase2 从各 .vpi 扫描构建):与声明端
# DeclarationGenerator._get_type_str 的泛型前缀、调用点
# Gen._struct_sha1_map[spec_name] 同一条规则源;否则 declare/define
# 两侧前缀分裂(使用方模块 vs 模板模块)→ 跨模块 undefined symbol。
template_sha1 = Gen._struct_sha1_map.get(ClassName)
saved_gen_sha1: str | None = getattr(Gen, 'module_sha1', None)
saved_trans_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
if template_sha1:
@@ -507,6 +559,40 @@ class ClassHandle(BaseHandle):
ancestor = Gen.class_parent.get(ancestor)
return IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable
def _RegisterGenericClassTemplate(self, Node: ast.ClassDef) -> None:
"""注册泛型类模板到 `_generic_class_templates`(判据唯一:`_is_generic_class`)。
调用点两处:类处理阶段(_EmitClassLlvm)与前置声明之前的本模块预扫描
(PrescanModuleGenericClassTemplates)。注册内容唯一(node/type_params/
定义模块 SHA1),两个调用点不得各写一份。
"""
if not hasattr(self, '_generic_class_templates'):
self._generic_class_templates = {}
self._generic_class_templates[Node.name] = {
'node': Node,
'type_params': [tp.name for tp in Node.type_params],
# 记录泛型模板定义模块的 SHA1,用于特化时统一命名空间
'sha1': getattr(self.Trans, '_module_sha1', None),
}
def PrescanModuleGenericClassTemplates(self, ModuleBody: object) -> None:
"""前置声明之前预注册**本模块**泛型类模板。
判据与 includes 侧对泛型类的注册(HandlesImports._LoadModuleDeclarationsFromFile/
_EmitImportFromDeclarations 的 `node.type_params` 非空)**同源**,即
_is_generic_class,不看类名白名单。
类处理阶段(下方 _EmitClassLlvm)才注册本模块模板,而顶层函数前置声明
(GenerateLlvmDirect 的 _EmitFunctionForwardDeclLlvm)已需要它:模块级函数
参数/返回注解写自身泛型类(`def f(b: Box[Node])`)时
_SubscriptHitsGenericTemplate 判为不命中 → TypeAnnotationResolver 解析为空 →
VoidType → 抛"无法识别的参数类型注解";而同模块方法参数(类处理阶段之后)
却可用,二者分裂。预注册后两处走同一 _generic_class_templates。
"""
for Node in ModuleBody:
if isinstance(Node, ast.ClassDef) and self._is_generic_class(Node):
self._RegisterGenericClassTemplate(Node)
def _EmitClassLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, declare_only: bool = False) -> None:
ClassName: str = Node.name
# t.CType 及其子类(CChar/CInt/CVoid/CPtr/CTypeDefault 等)是"类型强转"标记,
@@ -515,16 +601,7 @@ class ClassHandle(BaseHandle):
if self._is_classname_ctype_marker(ClassName):
return
if self._is_generic_class(Node):
if not hasattr(self, '_generic_class_templates'):
self._generic_class_templates = {}
type_params: list[str] = [tp.name for tp in Node.type_params]
# 记录泛型模板定义模块的 SHA1,用于特化时统一命名空间
template_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
self._generic_class_templates[ClassName] = {
'node': Node,
'type_params': type_params,
'sha1': template_sha1,
}
self._RegisterGenericClassTemplate(Node)
return
if self._is_exception_class(Node):
self._RegisterExceptionClass(Node)
@@ -797,10 +874,11 @@ class ClassHandle(BaseHandle):
if TypeInfo:
if isinstance(MemberType, ir.PointerType) and isinstance(MemberType.pointee, ir.IntType) and MemberType.pointee.width == 8:
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
element_class: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
element_class: str | None = FindStructNameInAnnotationWithContext(
item.annotation, self.Trans, Gen)
# Fallback: FindStructNameInAnnotation 不处理 Subscript slice 为 BinOp 的情况
# (如 list[AST | t.CPtr] | t.CPtr),使用 TypeInfo.Name 作为回退。
# TypeInfo.Name 由 _HandleSubscript 设置为特化名(如 'list[sha1.ASTptr]'),
# TypeInfo.Name 由 _HandleSubscript 设置为特化名(如 'list[sha1.AST*]'),
# 经 _MergeCTypeInfoInto 传播后保留。
if not element_class and TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs:
element_class = TypeInfo.Name
@@ -816,7 +894,8 @@ class ClassHandle(BaseHandle):
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)
spec_in_anno: str | None = FindStructNameInAnnotationWithContext(
item.annotation, self.Trans, Gen)
if spec_in_anno and '[' in spec_in_anno:
if ClassName not in Gen.class_member_element_class:
Gen.class_member_element_class[ClassName] = {}
+9 -2
View File
@@ -547,8 +547,15 @@ class ExprAttrHandle(BaseHandle):
if self._is_char_pointer(ObjVal):
if ClassName in Gen.structs:
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):
# 二级指针解引用。模块级全局指针变量(如 _g_gen: rawptr[Generator.Generator])
# 的全局元素类型比实际存值多一层:写入端(main.vp `GenApi._g_gen = gen`)生成
# 为 bitcast T*→T** 后直接存值,未取地址;读取端必须做其逆运算 bitcast,绝不能
# 再 load——否则把 T* 当 T** 再解引用,接收者被取成对象首字段的位,方法内读
# self->Gen 即野指针(ASan: CallGenBase.SetTempDir 读悬空地址崩溃)。
if (isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType)
and isinstance(Node.value, ast.Name) and Node.value.id in Gen.module.globals):
ObjVal = Gen.builder.bitcast(ObjVal, ObjVal.type.pointee, name=f"cast_{VarName}_global")
elif isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
# 检查结构体匹配
+30 -62
View File
@@ -12,7 +12,9 @@ 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.includes.t import CTypeRegistry
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
from lib.core.SymbolUtils import (
IsTModule, ExtractTypeNameFromBinOp, IsPtrSubscriptNode, DesugarPtrSubscriptToUnion,
ResolveTypeArgStr, GenericArgRawName)
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
@@ -3684,46 +3686,18 @@ class ExprCallHandle(BaseHandle):
def _resolve_type_arg_str(self, node: ast.AST) -> str:
"""将类型参数 AST 节点解析为规范化的类型字符串(用于泛型特化的 mangling)。
走和普通类型签名同样的规范化路径(不单独创建规则):
- ast.Name: 若为已注册结构体,加 SHA1 前缀(如 'AST' → '9ada227b160c07a1.AST'),
与 DeclarationGenerator._get_type_str 对 ast.Name 的处理一致
- ast.Attribute: t.CPtr → 'ptr'(指针标记,等价于普通签名中 t.CPtr → i8* 的指针语义;
用 'ptr' 而非 '*' 是因为 _get_or_create_struct 的 clean_name 会移除 '*',
导致 Phase2 直接编译与 .stub.ll 加载路径的 mangled 名不一致);
其他 t 模块类型按 CTypeRegistry.NameToLLVM 解析
- ast.BinOp: 递归处理左右操作数并直接拼接(如 AST | t.CPtr → 'sha1.ASTptr'),
避免空格/管道符导致 _get_or_create_struct 的 clean_name 清洗不一致
规则本体在 SymbolUtils.ResolveTypeArgStr(定义端/声明端唯一规则源,
声明端 DeclarationGenerator 的泛型分支亦调用同一函数),此处仅注入
翻译器上下文:
- t/c 导入别名表(from t import CInt as myint → 't.CInt')
- 跨模块结构体 SHA1 表(ast.Name/Attribute 命中 → '{sha1}.{名}',与普通签名一致)
"""
if isinstance(node, ast.Name):
tn: str = node.id
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
if tn in t_c_imported:
src_module, src_name = t_c_imported[tn]
return f'{src_module}.{src_name}'
# 若为已注册结构体,加 SHA1 前缀(和普通签名路径一致)
Gen = self.Trans.LlvmGen
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {}
if tn in struct_sha1_map:
return f'{struct_sha1_map[tn]}.{tn}'
return tn
if isinstance(node, ast.Attribute):
if isinstance(node.value, ast.Name):
full_name: str = f'{node.value.id}.{node.attr}'
# t.CPtr → 'ptr'(指针标记,和普通签名中 t.CPtr 被解析为指针类型 i8* 语义一致)
if full_name == 't.CPtr':
return 'ptr'
# 其他 t 模块类型按 CTypeRegistry 解析(和普通签名路径一致)
llvm_str: str | None = CTypeRegistry.NameToLLVM(node.attr)
if llvm_str is not None:
return llvm_str
return full_name
return ast.unparse(node)
if isinstance(node, ast.BinOp):
left_str: str = self._resolve_type_arg_str(node.left)
right_str: str = self._resolve_type_arg_str(node.right)
# 直接拼接(如 'sha1.AST' + 'ptr' = 'sha1.ASTptr'),避免空格导致清洗不一致
return f'{left_str}{right_str}'
return ast.unparse(node)
Gen = self.Trans.LlvmGen
StructSha1Map: dict[str, str] = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {}
return ResolveTypeArgStr(
node,
TCAliasMap=getattr(self.Trans, '_t_c_imported_names', {}),
StructSha1Map=StructSha1Map)
def _get_raw_type_name(self, node: ast.AST) -> str:
"""获取类型节点的原始名称(不带模块前缀),用于泛型 T 替换。
@@ -3743,30 +3717,24 @@ class ExprCallHandle(BaseHandle):
def _resolve_generic_slice_type(self, sn: ast.AST) -> tuple[str, str] | None:
"""解析泛型 slice 中的单个类型参数节点,返回 (type_arg, type_name) 或 None。
type_arg: 用于 mangling,走和普通签名同样的规范化路径
(如 'AST | t.CPtr' → '9ada227b160c07a1.ASTptr',AST 加 SHA1 前缀,t.CPtr 处理为 ptr)
type_name: 用于替换泛型类型参数 T(如 'AST' 或 'CInt',_specialize_generic_class 会自动加 | t.CPtr 给类名)
type_arg: 用于 mangling,走**唯一规则源** _resolve_type_arg_str
(内层与参数注解同解析:'AST | t.CPtr' / 'rawptr[AST]' →
'{sha1}.AST*'、裸类名 'AST' → '{sha1}.AST'、标量按
NormalizeGenericArgName 归一)
type_name: 用于替换泛型类型参数 T(原始源码名,如 'AST' / 'CInt',
_specialize_generic_class 会自动给类名加 | t.CPtr)
指针下标 rawptr[T] 先折叠成等价的 `T | t.CPtr` 再解析,
与源码联合写法得到同一 (type_arg, type_name):否则 list[rawptr[ast.AST]]
会拼出 'rawptr[ast.AST]' 实参串(内层未混淆)→ 与 list[ast.AST | t.CPtr]
的 '<sha1>.AST*' 分裂成两个特化名(结构体/方法声明/调用点三端不一致)。
"""
if IsPtrSubscriptNode(sn, self.Trans.SymbolTable):
sn = DesugarPtrSubscriptToUnion(sn, self.Trans.SymbolTable)
if isinstance(sn, ast.Name):
tn: str = sn.id
ts: str = 'int'
if tn == 'int':
ts, tn = 'int', 'CInt'
elif tn == 'double':
ts, tn = 'double', 'CDouble'
elif tn == 'float':
ts, tn = 'float', 'CFloat'
elif tn == 'char':
ts, tn = 'i8', 'CChar'
elif tn == 'bool':
ts, tn = 'i8', 'CBool'
elif tn in ('CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'):
ts = 'int'
elif tn in ('CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'):
ts = 'double'
else:
ts = tn
return (ts, tn)
# type_arg 走唯一规则源(命中注册类加 SHA1 前缀,裸名与
# `list[X]`/`rawptr[X]` 内层收敛到同一名字);
# type_name 保留源码名供 T 替换与内建/类类型判定(两张表收拢在 SymbolUtils)
return (self._resolve_type_arg_str(sn), GenericArgRawName(sn.id))
# BinOp (如 AST | CPtr) 或 Attribute (如 t.CPtr / t.CInt)
type_str: str = self._resolve_type_arg_str(sn)
# type_name 保留模块前缀(如 't.CUnsignedChar'),避免 T(0) 替换为
+134 -19
View File
@@ -8,7 +8,9 @@ import copy
import traceback
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.SymbolUtils import IsTModule, FindStructNameInAnnotation, AnnotationContainsName
from lib.core.SymbolUtils import (
IsTModule, FindStructNameInAnnotationWithContext, AnnotationContainsName,
IsPtrSubscriptNode, DesugarPtrSubscriptToUnion)
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.includes import t
@@ -520,7 +522,8 @@ class FunctionHandle(BaseHandle):
if not isinstance(ReturnTypeInfo, CTypeInfo):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = t.CVoid()
if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2:
if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState)
or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)):
def _FindNonVoidCTypeInfo(node: ast.AST) -> Any:
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
results: list[Any] = []
@@ -557,7 +560,10 @@ class FunctionHandle(BaseHandle):
is_str_type: bool = False
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
is_str_type = True
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
# 走 ResolveAnnotationType 而非 CTypeInfo.FromNode:指针下标
# 返回注解(rawptr[T] / t.CPtr[T])需走 TypeMerge 通用解析,
# 否则内层跨模块类解析不出 → CVoid/1(i8*)。
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName)
if inferred:
@@ -637,9 +643,15 @@ class FunctionHandle(BaseHandle):
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
ReturnType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
if isinstance(ReturnType, ir.PointerType) and isinstance(ReturnType.pointee, ir.PointerType):
if isinstance(ReturnType.pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
ReturnType = ir.PointerType(ReturnType.pointee.pointee)
# 此处原有 "Ptr(Ptr(Struct)) → Ptr(Struct)" 的压层(历史遗留):会把已解析的
# 多层指针返回类型(`-> rawptr[rawptr[X]]` / `-> X | t.CPtr | t.CPtr`)
# 与泛型特化方法返回(`list[X**]` 的 get/pop/__getitem__/__next__)少算一层,
# 与同函数的形参(`append(item: T)` 保留 `X**`)、声明端
# DeclarationGenerator._get_type_str 的 BinOp 分支(同样不压层,见
# '_is_bare_class_ref_annotation' 为假时逐层外包)以及 _EmitFunctionLlvm
# 的定义体路径全部不一致。违反"多层指针已解析时照原样保留层数"。
# 实测(36 用例 A/B)删除后仅 `list[X**]` 的 4 个方法 declare 由 `X*` 变
# `X**`,与 append/set 的形参一致;stub 逐字节不变。
if isinstance(ReturnType, ir.IntType) and ReturnType.width == 8:
if RawFuncName == '__str__':
ReturnType = ir.PointerType(ir.IntType(8))
@@ -681,7 +693,12 @@ class FunctionHandle(BaseHandle):
if Arg.annotation:
try:
ParamTypeInfo: Any
ParamTypeInfo = self.ResolveAnnotationType(Arg.annotation)
# 走 ResolveParamAnnotation(= ResolveAnnotationType + 泛型模板
# 识别):参数注解中的泛型容器(list[X] / rawptr[list[X]])与
# 指针下标(rawptr[X])需走 TypeMerge 通用解析,否则
# TypeAnnotationResolver 解析不出 → VoidType → 报
# "无法识别的参数类型注解"。
ParamTypeInfo = self.ResolveParamAnnotation(Arg.annotation)
if ParamTypeInfo is None:
ParamTypeInfo = CTypeInfo()
ParamTypeInfo.BaseType = t.CInt()
@@ -820,20 +837,113 @@ class FunctionHandle(BaseHandle):
def _make_replacement_node(self, replacement: str) -> ast.AST:
"""将 type_map 中的替换字符串转换为 AST 节点。
mangled 名称如 'sha1.ASTptr' 需要还原为 AST | t.CPtr 结构,
mangled 名称如 '<sha1>.AST*' 需要还原为 AST | t.CPtr 结构,
否则类型解析会丢失 PtrCount 信息。
含点号的名称(如 'sha1.AST')需解析为 ast.Attribute 链。
含点号的名称(如 '<sha1>.AST')需解析为 ast.Attribute 链。
下标形态('rawptr[ast.AST]' / 'list[AST]' 等)必须整体解析为 Subscript:
_make_name_node 只按 '.' 切分会把 'rawptr[ast.AST]' 拆成
Name('rawptr[ast') + Attribute('AST]'),两段都不是有效类型名 →
参数/返回注解解析为空 → VoidType → "无法识别的参数类型注解"。
指针下标(rawptr[T] / t.CPtr[T])再折叠为等价的 `T | t.CPtr`,与源码
联合写法同解析路径(对齐 TPV TypeGenResolve._parse_type_string 的 '['
分支 + ClassGenGeneric._clone_annotation 的 T 替换)。
内层为已混淆名(数字开头,如 'rawptr[7565e081d88517ac.AST]')时
ast.parse 无法解析(数字开头的令牌),改用手工拆 base/slice(同 TPV
TypeGenResolve._parse_type_string 的数字开头手工拆分分支)。
尾部 '*'(泛型实参 '<sha1>.Node*' / '<sha1>.Node**',来自 rawptr[T] /
t.CPtr 的逐层 mangling)逐层还原为 `Node | t.CPtr [| t.CPtr]` → 对应
层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque
(item 类型与特化名 '<sha1>.Node**' 的语义不一致)。
尾部 'ptr'(旧规则 mangling,如 'Nodeptr' / 'ast.ASTptr')保留兼容:
.vpi/stub 缓存里仍是旧名时按同样方式还原。
"""
StarCount: int = len(replacement) - len(replacement.rstrip('*'))
if StarCount > 0:
BaseName: str = replacement[:len(replacement) - StarCount]
base_node: ast.AST
if BaseName in ('i8', 'void', 'void*'):
# i8*(void*)在源码侧写作 t.CPtr;再叠加 StarCount-1 层
base_node = ast.Attribute(
value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
StarCount -= 1
else:
base_node = self._make_name_node(BaseName)
node: ast.AST = base_node
for _ in range(StarCount):
node = ast.BinOp(
left=node,
op=ast.BitOr(),
right=ast.Attribute(
value=ast.Name(id='t', ctx=ast.Load()),
attr='CPtr', ctx=ast.Load()),
)
return node
if replacement.endswith('ptr'):
# 提取基础名称: 'sha1.ASTptr' -> 'sha1.AST'
base: str = replacement[:-3]
return ast.BinOp(
left=self._make_name_node(base),
op=ast.BitOr(),
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
)
# 提取基础名称:'sha1.ASTptr' → 'sha1.AST';'Nodeptrptr' → 'Node'(2 层)
base: str = replacement
levels: int = 0
while base.endswith('ptr') and len(base) > 3:
base = base[:-3]
levels += 1
node: ast.AST = self._make_name_node(base)
for _ in range(levels):
node = ast.BinOp(
left=node,
op=ast.BitOr(),
right=ast.Attribute(
value=ast.Name(id='t', ctx=ast.Load()),
attr='CPtr', ctx=ast.Load()),
)
return node
if '[' in replacement:
SubNode: ast.AST | None = None
try:
SubNode = ast.parse(replacement, mode='eval').body
except Exception:
SubNode = None
if not isinstance(SubNode, ast.Subscript):
SubNode = self._parse_subscript_manually(replacement)
if isinstance(SubNode, ast.Subscript):
if IsPtrSubscriptNode(SubNode, self.Trans.SymbolTable):
return DesugarPtrSubscriptToUnion(SubNode, self.Trans.SymbolTable)
return SubNode
return self._make_name_node(replacement)
def _parse_subscript_manually(self, replacement: str) -> ast.AST | None:
"""手工拆分单实参下标字符串(ast.parse 因数字开头标识符失败时使用)。
处理 `<base>[<inner>]`(整体以 ']' 结尾、单实参、无逗号;内层可为嵌套
单实参下标):'rawptr[7565e081d88517ac.AST]' → Subscript(Name('rawptr'),
Attribute(Name('7565e081d88517ac'), 'AST'));
'rawptr[rawptr[7565e081d88517ac.AST]]' → 外层 Subscript 的 slice 递归
拆出内层 Subscript(嵌套 rawptr 需两层指针)。带逗号等复杂形态返回
None(交调用方按普通名称处理),不做字符串猜测。
"""
open_idx: int = replacement.find('[')
if open_idx <= 0 or not replacement.endswith(']'):
return None
inner: str = replacement[open_idx + 1:-1]
if not inner or ',' in inner:
return None
base_name: str = replacement[:open_idx].strip()
inner_name: str = inner.strip()
if not base_name or not inner_name:
return None
slice_node: ast.AST | None
if '[' in inner_name or inner_name.endswith('*'):
# 嵌套单实参下标 / 指针层数内层(如 rawptr[rawptr[<sha1>.CLS]]、
# <sha1>.list[<sha1>.X*]):递归按同一还原规则拆解
slice_node = self._make_replacement_node(inner_name)
else:
try:
slice_node = ast.parse(inner_name, mode='eval').body
except Exception:
slice_node = self._make_name_node(inner_name)
if slice_node is None:
return None
return ast.Subscript(
value=self._make_name_node(base_name), slice=slice_node, ctx=ast.Load())
@staticmethod
def _make_name_node(name: str) -> ast.AST:
"""将可能含点号的名称转换为 ast.Name 或 ast.Attribute 链。
@@ -1323,7 +1433,8 @@ class FunctionHandle(BaseHandle):
if not isinstance(ReturnTypeInfo, CTypeInfo):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = t.CVoid()
if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2:
if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState)
or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)):
def _FindNonVoidCTypeInfo(node):
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
results = []
@@ -1359,7 +1470,10 @@ class FunctionHandle(BaseHandle):
is_str_type = False
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
is_str_type = True
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
# 与 _GetFunctionSignatureLlvm 同口径:指针下标返回注解
# (rawptr[T] / t.CPtr[T])走 ResolveAnnotationType 的
# TypeMerge 通用解析,避免内层跨模块类退化为 i8*。
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
inferred = self._infer_return_type_from_body(Node, Gen, ClassName)
if inferred:
@@ -1807,7 +1921,8 @@ class FunctionHandle(BaseHandle):
if not (_existing_ps == 'rawptr' or '.rawptr' in _existing_ps
or _existing_ps.startswith('rawptr[')):
continue
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
found_struct: str | None = FindStructNameInAnnotationWithContext(
arg.annotation, self.Trans, Gen)
if found_struct:
Gen.var_struct_class[param_name] = found_struct
# 普通类注解形参(非 BinOp 联合):rawptr[X] / t.CPtr[X] / X / t.X
+32 -4
View File
@@ -14,7 +14,7 @@ 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.includes.t import CTypeRegistry
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotation
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotationWithContext
# 注解里的存储类 / 限定符标记:这些名字**不是类名**(联合注解里与指针类混写,
@@ -1855,6 +1855,19 @@ class ImportHandle(BaseHandle):
Gen.class_requires[ClassName] = values
elif field_name == '__require_must__':
Gen.class_require_must[ClassName] = values
# 字段收集中保护(与 _EmitClassLlvm 的 _collecting_members_set 同源):
# 本节的成员解析会重入结构体发射 —— CollectAnnAssignMember →
# ResolveAnnotationType → HandlesTypeMerge._HandleSubscript → CollectAll →
# _ResolveGenericSlice → _specialize_generic_class → _EmitClassLlvm →
# _generate_structs(),而此刻 class_members[ClassName] 只含"已扫到的
# 自有字段"(继承字段展平尚未执行,见下方 _all_inherited 段),
# 且 llvmlite 的 set_body 只允许调用一次 → 残缺布局被永久固化:
# BasicBlock.Lines: rawptr[GSList[Line]] → body 只到 Name 即止
# Function.Params: rawptr[GSList[Param]] → body 只到 RetTy 即止
# Line/Param 等则整类丢失继承字段 Next(GEP 索引整体前移一位)。
# 置入保护后重入的 _generate_structs 会跳过本类(StructGen.py:461),
# 待本节收集+展平完成后由下方显式 _generate_structs() 一次性 set_body。
Gen._collecting_members_set.add(ClassName)
_existing_member_names = {m[0] for m in Gen.class_members[ClassName]}
for item in Node.body:
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
@@ -1884,7 +1897,8 @@ class ImportHandle(BaseHandle):
# 无法识别字段为 list → len() 误编译为 strlen → stdint 崩溃。
if isinstance(MemberType, ir.PointerType) and isinstance(MemberType.pointee, ir.IntType) and MemberType.pointee.width == 8:
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
element_class: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
element_class: str | None = FindStructNameInAnnotationWithContext(
item.annotation, self.Trans, Gen)
if not element_class and TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs:
element_class = TypeInfo.Name
if element_class:
@@ -1895,7 +1909,8 @@ class ImportHandle(BaseHandle):
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)
spec_in_anno: str | None = FindStructNameInAnnotationWithContext(
item.annotation, self.Trans, Gen)
if spec_in_anno and '[' in spec_in_anno:
if ClassName not in Gen.class_member_element_class:
Gen.class_member_element_class[ClassName] = {}
@@ -2255,6 +2270,13 @@ class ImportHandle(BaseHandle):
_inherited_ph: list[tuple] = [(f'__inherited_{i}', _st.elements[i]) for i in range(_num_inherited)]
# 占位符路径同样整体前置(继承字段在 struct 头部),与主路径保持一致
Gen.class_members[ClassName] = _inherited_ph + Gen.class_members[ClassName]
# 成员收集 + 继承展平完成 → 解除收集中保护,并用完整 class_members 设置 body。
# 必须在此显式触发一次 _generate_structs():保护期内(上方 add)所有重入的
# _generate_structs 都跳过了本类,若此处不再触发,本类 struct 将保持 opaque
# (opaque 结构体上的 GEP 是非法 IR,llvm-as 会直接报错),而残缺布局正是
# 本保护要消除的目标。
Gen._collecting_members_set.discard(ClassName)
Gen._generate_structs()
# ============================================================
# 跨模块 vtable 槽布局与定义模块一致:父类方法在前(子类覆盖放父类槽位),
# 子类新增方法在后。定义模块(HandlesClassDef)已按此合并,跨模块若只
@@ -3144,7 +3166,13 @@ class ImportHandle(BaseHandle):
return ir.ArrayType(elem_type, size)
typedef_names = {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]]+)"?', type_str)
# 类型名内允许 '*':泛型特化名可带指针层实参(如
# %"<模sha1>.list[<sha1>.AST*]"*)。此前字符集缺 '*' 会把名字截断在
# 内层 '*' 处(丢掉尾随 ']'),随后 gc_base/gc_args 重解析出
# list[<sha1>.AST](少一层指针)并 declare_only 特化出无方法体的
# 假类型 → 调用点引用未定义的 <模sha1>.list[<sha1>.AST].__len__
# (链接期 undefined symbol 根因)。
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]*]+)"?', type_str)
if struct_match:
raw_name = struct_match.group(1)
actual_source_sha1 = source_sha1
+37 -1
View File
@@ -4,7 +4,9 @@ if TYPE_CHECKING:
from lib.core.translator import Translator
from typing import List
from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
from lib.core.SymbolUtils import IsTModule, IsListAnnotation
from lib.core.SymbolUtils import (
IsTModule, IsListAnnotation, IsPtrSubscriptNode,
DesugarPtrSubscriptToUnion)
from lib.includes import t
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
import vast as ast
@@ -248,6 +250,24 @@ class HandlesTypeMerge(BaseHandle):
Result.PtrCount = 1
return Result
# 跨模块类引用(`<sha1>.CLS` / `ast.CLS`):按类名查 _struct_sha1_map,
# 与 ast.Name 路径(FromTypeName → _get_or_create_struct 的
# `clean_name in self._struct_sha1_map` 分支,BaseGen.py:421)、声明端
# DeclarationGenerator._get_type_str(`attr_name in struct_names`,
# DeclarationGenerator.py:1185)以及名称域 SymbolUtils._ResolveAttributeArgStr
# (SymbolUtils.py:491)**同一条"类名 → SHA1"规则**。
# 此前此处只查 Gen.structs(仅本模块已创建的结构体)→ 本模块未 import
# 的类(如 rawptr[e4c92b87b98424db.AST])落空 → 返回 BaseType=None →
# 裸引用抛"无法识别的参数类型注解"/脱糖合并后 CVoid/1(i8*),
# 与声明端 %"<sha1>.CLS"* 分裂。
if _Gen is not None and TypeName in getattr(_Gen, '_struct_sha1_map', {}):
Result = CTypeInfo()
Result.BaseType = t.CStruct(name=TypeName)
Result.IsStruct = True
Result.Name = TypeName
Result.PtrCount = 1
return Result
Entry = self.Trans.SymbolTable.lookup(TypeName)
if Entry and Entry.IsTypedef:
if isinstance(Entry, CTypeInfo) and Entry.BaseType:
@@ -436,6 +456,15 @@ class HandlesTypeMerge(BaseHandle):
t.CArrayPtr[t.CArrayPtr] -> void *(*)[]
t.CPtr[t.CArrayPtr[t.CArrayPtr]] -> void *(*(*))[]
"""
# 指针下标(rawptr[T] 内置裸指针 / t.CPtr[T] 下标指针,含裸名 CPtr[T])
# 折叠为等价的联合写法 `T | t.CPtr` 后交给 MergeTypes 统一解析:内层 T
# 因此走通用解析路径(含跨模块类经 Gen.structs 反查 SHA1 前缀),指针
# 层数与源码 `T | t.CPtr` 完全一致(此前 t.CPtr[ast.AST] 在此得
# AST**(比 declare/`AST | t.CPtr` 多一层)、rawptr[ast.AST] 退化为
# CVoid/1 → i8*)。
if IsPtrSubscriptNode(Node, self.Trans.SymbolTable):
return self.MergeTypes(DesugarPtrSubscriptToUnion(Node, self.Trans.SymbolTable))
def CollectAll(node: ast.AST, ParentIsArrayPtr: bool = False) -> CTypeInfo:
"""鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo"""
if isinstance(node, ast.Subscript):
@@ -789,6 +818,13 @@ class HandlesTypeMerge(BaseHandle):
"""递归收集所有操作数的类型(用于一次性合并)"""
Types = []
# 指针下标(rawptr[T] / t.CPtr[T])先折叠成等价的 `T | t.CPtr`:使
# `rawptr[T] | t.CPtr` 与 `T | t.CPtr | t.CPtr` 拉平成同一组操作数
# (否则折叠结果作为单个 Subscript 操作数参与合并,指针层数少算一层);
# t.CPtr[T] 与 rawptr[T] 同一条规则(见 SymbolUtils.IsPtrSubscriptNode)。
if IsPtrSubscriptNode(Node, self.Trans.SymbolTable):
Node = DesugarPtrSubscriptToUnion(Node, self.Trans.SymbolTable)
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
Types.extend(self._CollectAllOperandTypes(Node.left))
Types.extend(self._CollectAllOperandTypes(Node.right))
+20 -1
View File
@@ -280,8 +280,27 @@ class BaseGenMixin:
return prefix
return ''
@staticmethod
def _CleanStructName(name: str) -> str:
"""结构体名清洗:去掉指针标记/空格/修饰符(clean_name 既有行为)。
但**保留**泛型特化名 '[...]' 段内的原样文本:特化实参里的 '*' 是类型
身份的一部分('list[<sha1>.AST*]' 表示元素为指向 AST 的指针),若一并
移除会让声明端引用名('list[<sha1>.AST*]')与定义端注册名
('list[<sha1>.AST]')分裂成两个 struct。头部(首个 '[' 之前)行为不变;
'[' 开头(LLVM 数组串 '[4 x i8*]')走原清洗,保持既有语义。
"""
lb: int = name.find('[')
if lb > 0:
head, tail = name[:lb], name[lb:]
else:
head, tail = name, ''
head = (head.replace(' *', '').replace('*', '').replace(' ', '_')
.replace('const', 'const_').replace('volatile', 'volatile_'))
return head + tail
def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType:
clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_')
clean_name: str = self._CleanStructName(name)
# 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"),
# 先尝试用短名称(如 "zbit_writer")查找已注册的 struct,
# 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致
+49 -3
View File
@@ -487,10 +487,56 @@ class FuncGenMixin:
_members_final: list = self.class_members.get(ClassName, [])
_num_members_final: int = len(_members_final)
if _num_elements_final > _num_members_final:
_num_inherited_final: int = _num_elements_final - _num_members_final
# base 是 vtable 占位(struct[0] = i8*),不是继承字段,必须扣除:
# 不扣 base 时,凡"struct 元素数恰好多 1"的类,差值其实只是 vtable
# 本身(class_members 不含 vtable),却会对任意字段名返回 base+0。
# 实例:ast.ImportFrom 的 level/module → 静默返回偏移 1(=parent,
# %"…AST"*)→ 调用点把 AST* 当 i32 传入 _resolve_relative_module
# → llvmlite "Type of #4 arg mismatch: i32 != %"…AST"*"。
# 成员表与 struct 不一致(少一个非 vtable 槽)时,先强制按定义模块
# 的 .vpi 重载一次成员表再按名查:_TryLoadClassMembersFromPyi 的 guard
# 会永久跳过"已存在但不完整"的表,此处即该冻结的解除点。重载后仍缺
# 才走下方推断/fast-fail。每类只重载一次(避免递归与重复 IO)。
_ReloadKey: tuple = (id(self), ClassName)
_ReloadTried: set = getattr(self, '_MemberReloadTried', None)
if _ReloadTried is None:
_ReloadTried = set()
self._MemberReloadTried = _ReloadTried
if _ReloadKey not in _ReloadTried:
_ReloadTried.add(_ReloadKey)
_Sha1Final: str | None = getattr(self, 'class_sha1_map', {}).get(ClassName)
if _Sha1Final and self._Trans and hasattr(self._Trans, 'ImportHandler'):
_OldMembers = _members_final
try:
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(
ClassName, f"{_Sha1Final}.stub.ll", self, force=True)
except Exception:
pass
_ReloadedMembers: list = self.class_members.get(ClassName, [])
if len(_ReloadedMembers) < len(_OldMembers):
# 重载反而变少(.vpi 缺该类):回滚,避免丢字段
self.class_members[ClassName] = _OldMembers
_ReloadedMembers = _OldMembers
_members_final = _ReloadedMembers
_num_members_final = len(_members_final)
for _Ri, (_Rn, _Rt) in enumerate(_members_final):
if _Rn == field_name:
return base + _Ri
_num_inherited_final: int = _num_elements_final - _num_members_final - base
if _num_inherited_final == 1:
# 单继承字段,偏移 = base(vtable 之后第一个位置)
return base + 0
# 推断(缺失槽位 = 位于 base+0 的未展平继承字段)仅在成员表
# 尚未含展平继承字段时成立:若成员表首项本身就是任一已加载
# 祖先的字段名(如 ImportFrom 'parent' ← Stmt),说明继承字段
# 已展平、缺的是类自身字段,推断 base+0 必然读错槽位。
_ParentNamesFinal: set = set()
for _ParentF in (getattr(self, 'class_parents', {}).get(ClassName) or []):
for _Np, _Tp in self.class_members.get(_ParentF, []) or []:
_ParentNamesFinal.add(_Np)
if _members_final and _members_final[0][0] in _ParentNamesFinal:
pass # 已含展平继承字段 → 落入下方 fast-fail 暴露真实缺失
else:
# 单继承字段,偏移 = base(vtable 之后第一个位置)
return base + 0
# fast-fail(治本修复 2026-08-10):字段未找到不再静默返回 None。
# 静默 None 会让调用方(_gep_and_Load_member L26-27)直接 return None,
# AnnAssign InitValue 变 None → 变量 alloca 未初始化 → 运行期读垃圾指针
+19
View File
@@ -490,6 +490,25 @@ class TypeConvertMixin:
if IsPtr:
return ir.PointerType(opaque_struct)
return opaque_struct
# 类名与枚举成员/异常类同名时的判据统一:类型注解语境下,只要该名
# **有类定义**(Gen.structs 已建 / _struct_sha1_map 已登记类→模块),
# 就按结构体解析,而不是被同名枚举成员/异常类降级成 i32(rawptr[Function]
# → i32*:9 个模块 stub 里 LLVMModule.FuncHead/FuncTail、IRBuilder.Func
# 被写成 i32*)。与上方 IsStruct 分支(L479)、HandlesTypeMerge.
# _GetCTypeInfoInternal L241-251、StructGen 的"类名可能与 CEnum 成员名
# 冲突"守卫同一条规则源 —— 判据是"是否有类定义",不往白名单加名字。
if (type_str in self.structs
or type_str in getattr(self, '_struct_sha1_map', {})):
if type_str in self.structs:
if IsPtr:
return ir.PointerType(self.structs[type_str])
return self.structs[type_str]
_cls_sha1: str | None = self._get_source_sha1_from_type_str(type_str)
_cls_struct: ir.IdentifiedStructType = self._get_or_create_struct(
type_str, source_sha1=_cls_sha1)
if IsPtr:
return ir.PointerType(_cls_struct)
return _cls_struct
if _Entry and _Entry.IsEnum:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
if _Entry and _Entry.IsExceptionClass:
+25 -1
View File
@@ -18,7 +18,9 @@ if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
from lib.core.SymbolUtils import IsTModule, IsListAnnotation, IsCPtrNode, IsCPtrSubscriptNode
from lib.core.SymbolUtils import (
IsTModule, IsListAnnotation, IsCPtrNode, IsCPtrSubscriptNode,
IsRawPtrSubscriptNode)
from lib.includes import t as _t
from lib.includes.t import CTypeRegistry
@@ -253,6 +255,11 @@ class LLVMTypeMapper:
# t.CPtr[T] → Ptr(resolve(T))(对齐 TPV Subscript 分支
# TypeGenResolve.vp:2769-2790;void 首层归一化为 i8*)
return self._add_pointer_level(self.get_llvm_type_str(node.slice))
if IsRawPtrSubscriptNode(node):
# rawptr[T](内置裸指针下标)≡ `T | t.CPtr`:与定义端 TypeMerge 的
# 合并语义同口径(裸类引用自身即指针,吸收这一层;其余逐层外包)。
# 此前只认 IsCPtrSubscriptNode → rawptr[T] 落到下方 warn 并退化成 i32。
return self._rawptr_subscript_type_str(node)
if IsListAnnotation(node):
slice_node: ast.AST = node.slice
elem_type: str
@@ -309,6 +316,23 @@ class LLVMTypeMapper:
return ty + '*'
return ty + '*'
def _rawptr_subscript_type_str(self, node: ast.Subscript) -> str:
"""rawptr[T](内置裸指针下标)→ LLVM 类型串。
与定义端同口径(`T | t.CPtr` 的合并):裸类引用('%struct.X*' /
'%"sha1.X"*' / 泛型特化等以 '%' 开头的结构指针)自身即指针,吸收这一层;
其余(标量、已是指针的 typedef、联合写法、嵌套 rawptr / t.CPtr 下标)
逐层外包(void → i8*)。
"""
inner: ast.AST = node.slice
inner_type: str = self.get_llvm_type_str(inner)
if (not isinstance(inner, ast.BinOp)
and not IsRawPtrSubscriptNode(inner)
and not IsCPtrSubscriptNode(inner)
and inner_type.startswith('%') and inner_type.endswith('*')):
return inner_type
return self._add_pointer_level(inner_type)
def _add_pointer_levels(self, ty: str, count: int) -> str:
"""给类型字符串叠加 count 层指针(void/void* 首层归一化为 i8*)。"""
result: str = ty
+1 -1
View File
@@ -150,7 +150,7 @@ class TypeResolver:
# 会被 CTypeInfo.FromTypeName 当成 CStruct('ptr'),最终 _get_or_create_struct
# 建出 %"<模块sha>.ptr" 不透明结构体(VLogger._console_handle: win32base.HANDLE
# 报 "cannot store i8* to %"...ptr"*" 的根因)。按指针语义展开为 'void *',
# 与改前 `t.CVoid | t.CPtr` 联合分支等价(_InsertTypedefSymbol 同样把
# 与改前 `t.CPtr` 联合分支等价(_InsertTypedefSymbol 同样把
# 'CVoid *' 归一化为 'void *')。
if value_base_type == 'ptr':
td.original_type_kind = 'typedef'
+399 -21
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import vast as ast
import re
from lib.includes import t
from lib.includes.t import CTypeRegistry
_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__})
@@ -169,11 +170,16 @@ def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
return None
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None:
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set,
TCAliasMap: dict[str, tuple[str, str]] | None = None,
StructSha1Map: dict[str, str] | None = None) -> str | None:
"""递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。
检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。
支持泛型特化类型(如 GSList[Param]):特化名按**同一规则源**
(ResolveTypeArgStr:sha1 前缀 + rawptr/CPtr 的 '*' 逐层)构造后在
struct_names 中查找——查表键与 _mangle_generic_class_name 产物逐字一致,
否则同一注解在"注解查找"与"特化注册"两处解析出不同名字(opaque 副本)。
"""
if isinstance(node, ast.Name) and node.id in struct_names:
return node.id
@@ -191,33 +197,40 @@ def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str |
slice_node: ast.AST = node.slice
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
slice_node = slice_node.value
type_args: list[str] = []
if isinstance(slice_node, ast.Name):
# 裸 CPtr(i8*)与 t.CPtr 同规范化为 'ptr',与
# _resolve_type_arg_str/_mangle_generic_class_name 一致
type_args.append('ptr' if slice_node.id == 'CPtr' else slice_node.id)
elif isinstance(slice_node, ast.Attribute):
type_args.append('ptr' if slice_node.attr == 'CPtr' else slice_node.attr)
elif isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
if isinstance(elt, ast.Name):
type_args.append('ptr' if elt.id == 'CPtr' else elt.id)
elif isinstance(elt, ast.Attribute):
type_args.append('ptr' if elt.attr == 'CPtr' else elt.attr)
if type_args:
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
if spec_name in struct_names:
return spec_name
elem_nodes: list[ast.AST] = (
list(slice_node.elts) if isinstance(slice_node, ast.Tuple) else [slice_node])
type_args: list[str] = [
ResolveTypeArgStr(E, TCAliasMap, StructSha1Map) for E in elem_nodes]
spec_name: str = base_name + '[' + ']['.join(type_args) + ']'
if spec_name in struct_names:
return spec_name
if base_name in struct_names:
return base_name
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
result: str | None = FindStructNameInAnnotation(node.left, struct_names)
result: str | None = FindStructNameInAnnotation(
node.left, struct_names, TCAliasMap, StructSha1Map)
if result:
return result
return FindStructNameInAnnotation(node.right, struct_names)
return FindStructNameInAnnotation(
node.right, struct_names, TCAliasMap, StructSha1Map)
return None
def FindStructNameInAnnotationWithContext(Node: ast.AST, Trans: object, Gen: object,
StructNames: dict | set | None = None) -> str | None:
"""按 Gen/Trans 上下文注入规则表后查找结构体名。
规则本体唯一(FindStructNameInAnnotation),此处只做与
HandlesExprCall._resolve_type_arg_str 同口径的上下文注入,避免各调用点
各写一套拼名(查表键必须与 _mangle_generic_class_name 产物逐字一致)。
"""
Names: dict | set = StructNames if StructNames is not None else Gen.structs
return FindStructNameInAnnotation(
Node, Names,
TCAliasMap=getattr(Trans, '_t_c_imported_names', {}),
StructSha1Map=getattr(Gen, '_struct_sha1_map', {}))
def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
"""检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。
@@ -250,3 +263,368 @@ def IsCPtrSubscriptNode(node: ast.AST) -> bool:
"""
return (isinstance(node, ast.Subscript)
and IsCPtrNode(node.value))
# 指针下标的 base 名:rawptr 是编译器内置语法(TPC/TPV 双端保留字,见
# includes/builtins.vp 语义注释与 TypeAnnotationResolver._BUILTIN_ROWPTR_NAME),
# 单独 rawptr 等价 t.CPtr(void*)。
_RAWPTR_SUBSCRIPT_NAME: str = 'rawptr'
# 指针标记类型名(t.CPtr):裸名书写 `CPtr[T]` / 导入别名 `X`(from t import CPtr as X)
# 都归一到本名。
_CPTR_TYPE_NAME: str = 'CPtr'
def ResolveTCImportAliasName(NameId: str, symtable: object | None = None,
TCAliasMap: dict[str, tuple[str, str]] | None = None) -> str:
"""t/c 导入别名 → 原始类型名('X' → 'CPtr'、'myint' → 'CInt');未命中原样返回。
两张同源别名表(注册点唯一:HandlesImports._EmitImportFromDeclarationsLlvm /
_RegisterFromImportAliases,与 SymbolTable 序列化),调用方按手头有的表注入:
- TCAliasMap:{别名: (模块, 原名)}(Trans._t_c_imported_names /
DeclarationGenerator._t_c_imported_names 同结构)
- symtable._t_type_symbols:{别名: t.CType 子类}(from t import CPtr as X → t.CPtr)
非 t/c 模块的 from 导入别名(from ast import AST as A)不参与归一。
"""
if not NameId:
return NameId
if TCAliasMap:
Entry: tuple[str, str] | None = TCAliasMap.get(NameId)
if Entry:
SrcModule, SrcName = Entry
if IsTModule(SrcModule):
return SrcName
if symtable is not None:
Cls: object | None = getattr(symtable, '_t_type_symbols', {}).get(NameId)
if Cls is not None:
return getattr(Cls, '__name__', NameId)
return NameId
def IsRawPtrSubscriptNode(node: ast.AST) -> bool:
"""检查节点是否为内置裸指针下标 `rawptr[T]`(非裸标记 rawptr)。
`rawptr[T]` 语义 = `t.CPtr[T]` = 源码联合写法 `T | t.CPtr`(Ptr(T)),三者
必须走同一解析与拼名路径,否则同一类型的不同书写会分裂出不同特化名
(结构体/方法声明/调用点三处不一致)。
注意:本判据**只**认 `rawptr[T]`;`t.CPtr[T]` / 裸名 `CPtr[T]` 由
IsPtrSubscriptNode 判定(见下),二者共用同一条脱糖规则
(DesugarPtrSubscriptToUnion),此处保持 rawptr 专用以便仍需区分书写时使用。
"""
return (isinstance(node, ast.Subscript)
and isinstance(node.value, ast.Name)
and node.value.id == _RAWPTR_SUBSCRIPT_NAME)
def IsPtrSubscriptNode(node: ast.AST, symtable: object | None = None,
TCAliasMap: dict[str, tuple[str, str]] | None = None) -> bool:
"""检查节点是否为"指针下标类型":`rawptr[T]` / `t.CPtr[T]` / 裸名 `CPtr[T]`
/ 导入别名 `X[T]`(`from t import CPtr as X`)。
三者语义完全相同(= 源码联合写法 `T | t.CPtr` = Ptr(T),见
builtins.vp 与 t.py 的 CPtr 语义注释):内层 T 按**参数注解 `a: T` 的规则**
解析(跨模块类 → '<sha1>.X'),再包一层指针——T 为类引用时该层被结构体
自身吸收('<sha1>.X*'),其余(标量 / 已是指针的 typedef / 泛型容器特化 /
嵌套指针下标)逐层外包。
- 裸名 `CPtr[T]`(`from t import CPtr` / `from t import *`)与声明端
DeclarationGenerator._get_type_str 的 ValueIsCPtr 判据一致(那里同样接受
Attribute 'CPtr' 与 Name 'CPtr' 两种书写)。
- 传入 symtable 时,`import t as tt` 的 `tt.CPtr[T]` 一并命中(与声明端
"只看 attr 名"的 ValueIsCPtr 判据对齐,避免同一书写两端分裂);
不传(名称域 ResolveTypeArgStr 的字面名场景)时只认字面 't'。
- 导入名别名(`from t import CPtr as X` 的 `X[T]`)经别名表解析 X→CPtr
(TCAliasMap 或 symtable._t_type_symbols,见 ResolveTCImportAliasName),
定义端与声明端各自注入手头的同一批表,判据只有这一处。
"""
if IsRawPtrSubscriptNode(node):
return True
if not isinstance(node, ast.Subscript):
return False
value: ast.AST = node.value
if isinstance(value, ast.Name) and value.id == _CPTR_TYPE_NAME:
return True
return IsCPtrMarkerNode(value, symtable, TCAliasMap)
def DesugarPtrSubscriptToUnion(node: ast.AST, symtable: object | None = None,
TCAliasMap: dict[str, tuple[str, str]] | None = None) -> ast.AST:
"""把指针下标(`rawptr[T]` / `t.CPtr[T]` / 裸名 `CPtr[T]` / 别名 `X[T]`)
折叠成等价的联合写法 `T | t.CPtr`。
内层 T 递归折叠(`rawptr[rawptr[X]]` → `(X | t.CPtr) | t.CPtr`、
`t.CPtr[rawptr[X]]` → `(X | t.CPtr) | t.CPtr`),
与 TPV TypeGenResolve.resolve_annotation_type 的 Subscript 分支同语义
(T → Ptr(T),层数逐层外包);折叠后交给 HandlesTypeMerge 既有的
联合解析(_CollectAllOperandTypes 会把嵌套 BitOr 拉平成 [T, t.CPtr, ...],
struct 基类型吸收一层、其余逐层累加),从而:
- 内层 T 走通用类型解析(含跨模块类经 Gen.structs 反查 SHA1 前缀);
- `rawptr[X]` / `t.CPtr[X]` / `X[T]` / `X | t.CPtr` 得到同一 CTypeInfo
(PtrCount/BaseType 一致)与同一泛型实参串(逐层 '*')。
非指针下标节点原样返回(调用方无需先判类型);symtable/TCAliasMap 透传给
判据(识别 `import t as tt` 的 `tt.CPtr[T]` 与 `from t import CPtr as X` 的
`X[T]` 内层嵌套)。折叠产物统一用字面 `t.CPtr` 标记,与源码联合写法同形。
"""
if not IsPtrSubscriptNode(node, symtable, TCAliasMap):
return node
inner: ast.AST = DesugarPtrSubscriptToUnion(node.slice, symtable, TCAliasMap)
cptr_marker: ast.AST = ast.Attribute(
value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
union_node: ast.AST = ast.BinOp(left=inner, op=ast.BitOr(), right=cptr_marker)
try:
ast.copy_location(union_node, node)
except Exception:
pass
return union_node
# ---------------------------------------------------------------------------
# 泛型实参串(mangling):定义端与声明端唯一规则源
# ---------------------------------------------------------------------------
# 同一泛型特化(如 list[rawptr[ast.AST]])在 define 端发射的结构体名
# (HandlesClassDef._mangle_generic_class_name → %"<mod>.list[ast.ASTptr]")、
# 各端方法名、以及 declare/stub 端引用的类型名必须逐字一致,否则会出现
# Undefined method / 签名错位。此前 DeclarationGenerator._get_type_str 的泛型
# 分支自带第二套(只认 Name / Name-Tuple 实参的)规则,其余形态(Attribute /
# Subscript / BinOp / 混合 Tuple)退回未特化的 %"<mod>.list"*,与 define 端
# 不一致。故此处收拢唯一规则,两端皆调用本组函数。
# 定义端 _resolve_generic_slice_type 的 ast.Name 规范化表:
# 源码里的 C 定长类型名 → 喂给 _mangle_generic_class_name 的 type_arg。
_GENERIC_ARG_INT_NAMES: frozenset[str] = frozenset({
'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T',
'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong',
})
_GENERIC_ARG_FLOAT_NAMES: frozenset[str] = frozenset({
'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T',
})
# 源码名 → 泛型 T 替换用的原始类型名(_resolve_generic_slice_type 的第二返回值)
_GENERIC_ARG_RAW_NAMES: dict[str, str] = {
'int': 'CInt', 'double': 'CDouble', 'float': 'CFloat',
'char': 'CChar', 'bool': 'CBool',
}
# _mangle_generic_class_name 的浮点归一集合(LLVM 浮点串 → 'f' + Size)
_LLVM_FLOAT_STRINGS: frozenset[str] = frozenset({'float', 'double', 'half', 'fp128'})
def NormalizeGenericArgName(NameId: str) -> str:
"""ast.Name 泛型实参 → 定义端 type_arg(HandlesExprCall._resolve_generic_slice_type
的 ast.Name 分支,逐分支同构):
int/double/float 保留源码名('list[int]' 而非 'list[i32]')、
char/bool → 'i8'、C 整数族 → 'int'、C 浮点族 → 'double'、其余原名。
"""
if NameId in ('int', 'double', 'float'):
return NameId
if NameId in ('char', 'bool'):
return 'i8'
if NameId in _GENERIC_ARG_INT_NAMES:
return 'int'
if NameId in _GENERIC_ARG_FLOAT_NAMES:
return 'double'
return NameId
def GenericArgRawName(NameId: str) -> str:
"""ast.Name 泛型实参 → 替换模板 T 用的原始类型名(_resolve_generic_slice_type
的第二返回值):'int' → 'CInt'(内建类型须用源码名替换 T,见
HandlesClassDef._specialize_generic_class 的 _BUILTIN_TYPE_NAMES 判定),
其余原名。仅定义端 T 替换用;mangling 只用 NormalizeGenericArgName。
"""
return _GENERIC_ARG_RAW_NAMES.get(NameId, NameId)
def MangleTypeArgByRegistry(ArgStr: str) -> str:
"""实参串 → 最终 mangled 实参(HandlesClassDef._mangle_generic_class_name
的单项逻辑,逐分支同构):t 类型名经 NameToLLVM 归一(CInt32T → 'i32',
't.CInt'/'c.CInt' 先去模块前缀再归一),浮点按 Size 归一为 f{n}
(CDouble → 'f8'),未注册名原样保留(含指针层数与已解析的内层名)。
"""
LookupStr: str = ArgStr
if ArgStr.startswith('t.') or ArgStr.startswith('c.'):
LookupStr = ArgStr[2:]
LlvmStr: str | None = CTypeRegistry.NameToLLVM(LookupStr)
if not LlvmStr:
return ArgStr
if LlvmStr in _LLVM_FLOAT_STRINGS:
Cls: type | None = CTypeRegistry.GetClassByName(LookupStr)
Size: int = Cls().Size if Cls is not None else 0
return 'f' + str(Size)
return LlvmStr
# 指针层数的首层归一化(与 LLVMTypeMapper._add_pointer_level 同口径)
_POINTER_PLACEHOLDER_BASES: frozenset[str] = frozenset({'', 'void', 'void*'})
def AddPointerLayers(TypeStr: str, Layers: int) -> str:
"""给已解析的类型串追加 Layers 层指针(空/void/void* 的首层归一化为 i8*)。
与 LLVMTypeMapper._add_pointer_level 同口径;名称域与类型域因此对
rawptr[t.CVoid] 一致地给出 i8*(唯一允许的 void 兜底)。
"""
Result: str = TypeStr
for _ in range(Layers):
if Result in _POINTER_PLACEHOLDER_BASES:
Result = 'i8*'
else:
Result = Result + '*'
return Result
def IsCPtrMarkerNode(Node: ast.AST, symtable: object | None = None,
TCAliasMap: dict[str, tuple[str, str]] | None = None) -> bool:
"""`t.CPtr` 裸指针标记(含 `import t as tt` 与 `from t import CPtr as X` 别名):
联合写法里贡献一层 '*'。
与 IsCPtrNode 的区别:仅按 attr 名 + t 模块前缀判定,不看切片
(`t.CPtr[T]` 下标是**基类型**而非层数标记,见 ResolveTypeArgStr 的
Subscript 分支)。
- Attribute:`t.CPtr` / `tt.CPtr`(t 模块别名经 symtable.import_aliases 解析)。
- Name:经别名表归一为 'CPtr' 的书写名(`from t import CPtr as X` 的 `X`);
字面裸名 `CPtr` 是否算标记取决于该模块是否 `from t import CPtr`
(别名表命中一致:两端都由同一批表判定,不另设白名单)。
"""
if isinstance(Node, ast.Attribute):
return (Node.attr == _CPTR_TYPE_NAME
and isinstance(Node.value, ast.Name)
and IsTModule(Node.value.id, symtable))
if isinstance(Node, ast.Name):
return ResolveTCImportAliasName(Node.id, symtable, TCAliasMap) == _CPTR_TYPE_NAME
return False
def FlattenUnionOperands(Node: ast.AST) -> list[ast.AST]:
"""拉平嵌套 BitOr,按书写顺序返回操作数(`A | t.CPtr | t.CPtr` → [A, CPtr, CPtr])。"""
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
return FlattenUnionOperands(Node.left) + FlattenUnionOperands(Node.right)
return [Node]
def ResolveTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | None = None,
StructSha1Map: dict[str, str] | None = None) -> str:
"""将类型参数 AST 节点解析为规范化的类型字符串(泛型 mangling 用)。
规则(**与参数注解 `a: T` 完全同一套解析**,定义端/声明端唯一规则源):
- ast.Name: t/c 导入别名 → '{module}.{name}';已注册类 → '{sha1}.{名}'
(与参数注解的 %"{sha1}.X" 同前缀);其余按 NormalizeGenericArgName
归一('int'/'i32'/'str' 原名、'char'/'bool' → 'i8'、C 整数/浮点族 →
'int'/'double')
- ast.Attribute: t 模块类型按 CTypeRegistry.NameToLLVM 解析(t.CPtr → i8*、
t.CInt → i32);跨模块类引用 module.X → '{sha1}.X';其余 '{mod}.{attr}'
- ast.Subscript: 指针下标(`rawptr[T]` / `t.CPtr[T]` / 裸名 `CPtr[T]` /
导入别名 `X[T]`)已在入口脱糖为上面的联合写法(走同一规则),故此处只剩泛型容器:
'<容器名>[<已解析实参>]'(多实参 '][' 分隔),容器名的
模块前缀由调用方(_mangle_name / '%"{模sha1}.{特化名}"')统一加
- ast.BinOp(BitOr)(含指针下标脱糖而来): 取非 CPtr 侧为基类型,
每个 `t.CPtr` 标记追加一层 '*'(`X | t.CPtr` ≡ `rawptr[X]` ≡
`t.CPtr[X]` → '<sha1>.X*';`rawptr[rawptr[X]]` → '<sha1>.X**';
标量 `int | t.CPtr` → 'int*')
- 其余形态: ast.unparse
注意:名称域**不做**"裸类引用吸收一层 CPtr"(那是注解→LLVM 类型域的规则,
见 DeclarationGenerator._is_bare_class_ref_annotation):名称域描述的是类型
身份('X' = X 本身、'X*' = 指向 X 的指针),逐层累加,否则
`rawptr[X]` 与 `X | t.CPtr` 会分裂成两个名字。
"""
if IsPtrSubscriptNode(Node, TCAliasMap=TCAliasMap):
Node = DesugarPtrSubscriptToUnion(Node, TCAliasMap=TCAliasMap)
if isinstance(Node, ast.Name):
tn: str = Node.id
if TCAliasMap and tn in TCAliasMap:
# t 模块别名(from t import CInt as myint)按内建归一表解析到同一名字
# ('myint' 与 'CInt' 都 → 'int'),避免同义写法分裂特化名
SrcModule, SrcName = TCAliasMap[tn]
if IsTModule(SrcModule):
return NormalizeGenericArgName(SrcName)
return f'{SrcModule}.{SrcName}'
if StructSha1Map and tn in StructSha1Map:
return f'{StructSha1Map[tn]}.{tn}'
return NormalizeGenericArgName(tn)
if isinstance(Node, ast.Attribute):
return _ResolveAttributeArgStr(Node, TCAliasMap, StructSha1Map)
if isinstance(Node, ast.Subscript):
return _ResolveSubscriptArgStr(Node, TCAliasMap, StructSha1Map)
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
return _ResolveUnionArgStr(Node, TCAliasMap, StructSha1Map)
return ast.unparse(Node)
def _ResolveAttributeArgStr(Node: ast.Attribute, TCAliasMap: dict[str, tuple[str, str]] | None,
StructSha1Map: dict[str, str] | None) -> str:
"""Attribute 形态(t.CInt / ast.AST / <sha1>.AST)→ 实参串。"""
if not isinstance(Node.value, ast.Name):
return ast.unparse(Node)
ModName: str = Node.value.id
AttrName: str = Node.attr
if IsTModule(ModName) or (TCAliasMap and ModName in TCAliasMap):
LlvmStr: str | None = CTypeRegistry.NameToLLVM(AttrName)
if LlvmStr is not None:
return LlvmStr
return f'{ModName}.{AttrName}'
# 跨模块类引用(ast.AST / <sha1>.AST):与参数注解同一条 sha1 解析
if StructSha1Map and AttrName in StructSha1Map:
return f'{StructSha1Map[AttrName]}.{AttrName}'
return f'{ModName}.{AttrName}'
def _ResolveSubscriptArgStr(Node: ast.Subscript, TCAliasMap: dict[str, tuple[str, str]] | None,
StructSha1Map: dict[str, str] | None) -> str:
"""下标形态(t.CPtr[T] / 泛型容器 list[X] / dict[K,V])→ 实参串。
容器名('list' / 'dict' ...)**不带**模块前缀:它只是 _mangle_generic_class_name
的基名,特化名的模块前缀由调用方统一加(定义端 _mangle_name / 声明端
'%"{模sha1}.{特化名}"'),并保证 '_make_replacement_node' 能把实参串
重新解析成可用的注解 AST('<sha1>.list[...]' 会因数字开头而解析失败)。
"""
if IsCPtrSubscriptNode(Node):
Inner: str = ResolveTypeArgStr(Node.slice, TCAliasMap, StructSha1Map)
return AddPointerLayers(Inner, 1)
BaseName: str = ''
if isinstance(Node.value, ast.Name):
BaseName = Node.value.id
elif isinstance(Node.value, ast.Attribute):
BaseName = Node.value.attr
if not BaseName:
return ast.unparse(Node)
SliceNode: ast.AST = Node.slice
ElemNodes: list[ast.AST] = list(SliceNode.elts) if isinstance(SliceNode, ast.Tuple) else [SliceNode]
Resolved: list[str] = [ResolveTypeArgStr(E, TCAliasMap, StructSha1Map) for E in ElemNodes]
return f'{BaseName}[' + ']['.join(Resolved) + ']'
def _ResolveUnionArgStr(Node: ast.BinOp, TCAliasMap: dict[str, tuple[str, str]] | None,
StructSha1Map: dict[str, str] | None) -> str:
"""联合形态(X | t.CPtr | ...)实参串:非 CPtr 侧为基类型,CPtr 标记逐层加 '*'。
标记判据是同一处 IsCPtrMarkerNode(含 `from t import CPtr as X` 的裸标记别名),
别名经 TCAliasMap 解析;没带别名表的 `import t as tt` 的 `tt.CPtr` 在此域
不做模块别名解析(两端口径一致的既有缺口)。
"""
BaseType: str = ''
Layers: int = 0
for Operand in FlattenUnionOperands(Node):
if IsCPtrMarkerNode(Operand, TCAliasMap=TCAliasMap):
Layers += 1
elif not BaseType:
BaseType = ResolveTypeArgStr(Operand, TCAliasMap, StructSha1Map)
if not BaseType:
# 只有 CPtr 标记(如 `t.CPtr | t.CPtr`):等价 void* 逐层——首层 i8*
return AddPointerLayers('void', Layers)
return AddPointerLayers(BaseType, Layers)
def ResolveGenericTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | None = None,
StructSha1Map: dict[str, str] | None = None) -> str:
"""泛型实参的最终 mangled 串(喂给 _mangle_generic_class_name 的单参数)。
与定义端(HandlesExprCall._resolve_generic_slice_type + _mangle_generic_class_name)
对单个实参的实际结果同一套规则:
- ast.Name: NormalizeGenericArgName →(命中注册类则 '{sha1}.{名}')→ MangleTypeArgByRegistry
('int' → 'int'、'i32' → 'i32'、'str' → 'str'、'CInt32T' → 'int'、
'CFloat64T' → 'double'、'CChar' → 'i8')
- 其余形态(Attribute / Subscript(含 rawptr[...])/ BinOp / 混合 Tuple 元素):
ResolveTypeArgStr(rawptr[T] 脱糖 → 逐层 '*'、t.CPtr → 'i8*'、跨模块类 → sha1 前缀)
→ MangleTypeArgByRegistry
"""
return MangleTypeArgByRegistry(ResolveTypeArgStr(Node, TCAliasMap, StructSha1Map))
+8
View File
@@ -170,6 +170,14 @@ class LlvmGeneratorMixin:
line_info += ":\n %d | %s" % (lineno, source_line)
self._ErrorStack.append((type(e).__name__, str(e), line_info))
# 本模块泛型类模板必须在前置声明之前注册(与 includes 侧注册判据同源,
# 见 HandlesClassDef.PrescanModuleGenericClassTemplates):前置声明要解析
# 参数/返回注解里的泛型类下标(`def f(b: Box[Node])`),而类处理阶段
# (下方 _EmitClassLlvm)才注册模板 → 注解解析为空 → VoidType →
# "无法识别的参数类型注解"。放在 import 扫描之后,保证本地类覆盖同名
# 导入类(与 _EmitClassLlvm 的覆盖顺序一致)。
self.ClassHandler.PrescanModuleGenericClassTemplates(ast.iter_child_nodes(Tree))
# 前向声明所有顶层函数,确保全局变量初始化时能引用函数指针
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.FunctionDef):