修复了一些错误
This commit is contained in:
1 parent
6af2dea917
commit
2cc816ac13
16 files changed
+1155
-230
No files matched your search
@@ -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] = {}
|
||||
|
||||
Reference in new issue
Block a user