refactor(type): 全面清理旧联合与 t/c 标记判断
审计并修复 23 个文件:类型注解中的 T1 | T2 一律 fail-fast;typedef/define/export/extern/static/const/volatile/attribute 优先读取 Markers/Attributes/ByteOrder/BitWidth;指针统一 CPtr/rawptr/CRef/CTempRef/CArrayPtr/CAutoPtr Subscript;stub 输出统一新语法。
This commit is contained in:
1 parent
a410de2cf7
commit
0bded58999
23 files changed
+887
-694
No files matched your search
@@ -10,7 +10,7 @@ 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 (
|
||||
FindStructNameInAnnotationWithContext, MangleTypeArgByRegistry,
|
||||
MangleTypeArgByRegistry,
|
||||
EnumClassIntWidth,
|
||||
EnumBodyMemberNames, EnumMemberCountMismatchError,
|
||||
ClassHasFuncLevelCVTable, IsVtableSlotMethod)
|
||||
@@ -27,6 +27,12 @@ _ENUM_PTR_ANNOTATION_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'CAutoPtr', 'CRef', 'CTempRef', 'rawptr', 'str', 'bytes',
|
||||
})
|
||||
|
||||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||||
# 新 AST 表示下指针是 Subscript,不再是 `T | CPtr` 联合的一翼。
|
||||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
|
||||
class ClassHandle(BaseHandle):
|
||||
def _is_exception_class(self, Node: ast.ClassDef) -> bool:
|
||||
@@ -177,7 +183,7 @@ class ClassHandle(BaseHandle):
|
||||
# 都不在类表里 → 天然判为值类型,无需名表。
|
||||
# 历史教训(名表判据的代价,保留以便回归时理解):`str` 曾漏在
|
||||
# "非类类型名"集合外 → `list[str]` 的类型参数被误判为类类型,特化后
|
||||
# 方法签名被额外包一层 `| CPtr`(append/set 形参 i8**、get/pop 返回
|
||||
# 方法签名被额外包一层 `CPtr[...]`(append/set 形参 i8**、get/pop 返回
|
||||
# i8**)→ 调用点多解一层 load(读字符串首 8 字节)→ ASan 崩溃。
|
||||
# 注意 _BUILTIN_TYPE_NAMES 本身仍保留:它用于 type_map 替换
|
||||
# 与 _from_import_aliases 注册,不能把 'str' 并进去
|
||||
@@ -194,7 +200,7 @@ class ClassHandle(BaseHandle):
|
||||
# (带 sha1 前缀 + ptr 后缀),避免模板内部嵌套注解被替换成裸短名
|
||||
# 后重新特化出只有 declare、无方法体的错误特化(list[AST].__len__
|
||||
# undefined symbol 根因)。_make_replacement_node 会把 mangled 名
|
||||
# 还原为 'sha1.AST | CPtr',重新解析时拼回一致的 mangled 名。
|
||||
# 还原为 'CPtr[sha1.AST]',重新解析时拼回一致的 mangled 名。
|
||||
tn_bare: str = tn.split('.')[-1] if '.' in tn else tn
|
||||
if tn_bare in _BUILTIN_TYPE_NAMES:
|
||||
type_map[tp_name] = tn
|
||||
@@ -204,10 +210,10 @@ class ClassHandle(BaseHandle):
|
||||
type_map[tp_name] = tn
|
||||
else:
|
||||
type_map[tp_name] = type_args[i]
|
||||
# 检测哪些类型参数在原始类型实参中带有指针语义(| CPtr / rawptr[T])
|
||||
# 检测哪些类型参数在原始类型实参中带有指针语义(CPtr[T] / rawptr[T] 等)
|
||||
# 当 type_arg 以 '*' 结尾(mangling 把每个 CPtr 层渲染为一层 '*')且对应的
|
||||
# type_name(去模块前缀后)不是内建类型名时,说明调用方写了
|
||||
# list[AST | CPtr] / list[rawptr[AST]]。注意用 tn_bare 判断:
|
||||
# list[CPtr[AST]] / list[rawptr[AST]]。注意用 tn_bare 判断:
|
||||
# 'CPtr' 去前缀后是 'CPtr'(内建),不算类类型参数。
|
||||
cptr_params: set[str] = set()
|
||||
for i, tp_name in enumerate(type_param_names):
|
||||
@@ -218,8 +224,8 @@ class ClassHandle(BaseHandle):
|
||||
if tn_bare_c not in _BUILTIN_TYPE_NAMES:
|
||||
cptr_params.add(tp_name)
|
||||
# Bug 2 修复:识别特化为 class 类型的类型参数
|
||||
# 这类参数在方法签名中是裸 T(无 | CPtr),特化后为裸 ClassName(值类型)
|
||||
# 需要加 | CPtr 使其成为指针类型(class 实例应按指针传递)
|
||||
# 这类参数在方法签名中是裸 T,特化后为裸 ClassName(值类型)
|
||||
# 需要加 CPtr[...] 使其成为指针类型(class 实例应按指针传递)
|
||||
# 判据 = "是否有类定义"(_HasClassDefinition),存**裸名**:注解侧的
|
||||
# 比较也用裸名(T 替换后的 'sha1.Param' 去前缀)——此前存带模块前缀的
|
||||
# tn(如 'ast.AST')而比较用裸名 'AST',前缀形态永不命中。
|
||||
@@ -886,7 +892,7 @@ class ClassHandle(BaseHandle):
|
||||
# 由 HandlesImports.py:2647/2654 与 FuncGen.py:1057 触发;该分支不受
|
||||
# "字段收集中"保护,见 HandlesImports.py:3299 的 `not force` 豁免)。
|
||||
# 此时本循环后面的 `append` 会把**嵌套帧已经登记过的同一字段**再写一条 ——
|
||||
# 现场:AST 的最后一个字段 `children: list[rawptr[AST]] | CPtr` 是全类唯一
|
||||
# 现场:AST 的最后一个字段 `children: CPtr[list[rawptr[AST]]]` 是全类唯一
|
||||
# 触发泛型特化的注解,处理它时嵌套帧重填了 AST 表(7 项),本循环恢复后
|
||||
# 又追加一次 `children` ⇒ 表 8 项 / 去重 7 项,重名条目 `children@7`;
|
||||
# 该表又被祖先块展平**原样拷贝**给 AST 的每个子类(_FlattenInherited 只按
|
||||
@@ -901,6 +907,11 @@ class ClassHandle(BaseHandle):
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||||
continue
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
Line: int = getattr(item.annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
@@ -913,39 +924,13 @@ class ClassHandle(BaseHandle):
|
||||
# FieldEntry.IsConst/IsVolatile/PointeeVolatile 同口径。
|
||||
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
|
||||
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 = FindStructNameInAnnotationWithContext(
|
||||
item.annotation, self.Trans, Gen)
|
||||
# Fallback: FindStructNameInAnnotation 不处理 Subscript slice 为 BinOp 的情况
|
||||
# (如 list[AST | CPtr] | CPtr),使用 TypeInfo.Name 作为回退。
|
||||
# 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
|
||||
if element_class:
|
||||
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] | 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 = 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] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = spec_in_anno
|
||||
# Subscript 容器字段(list[X] / rawptr[list[X]]):非 BinOp 联合,
|
||||
# 上面的 i8*/BinOp 分支不命中 → 容器身份丢失 → 字段方法调用
|
||||
# (get/len…)分派失败 "Undefined method 'get' in class 'rawptr'"
|
||||
# (Converter.vp L190)。与 HandlesImports 对称,用与特化生成端
|
||||
# 同源的 _resolve_type_arg_str 记录 element_class。
|
||||
# Subscript 容器/指针字段(list[X] / CPtr[list[X]] /
|
||||
# rawptr[GSList[X]]):记录容器/特化名,供字段方法分派与
|
||||
# 泛型特化结构体指针字段解析使用;身份丢失会导致
|
||||
# "Undefined method 'get' in class 'rawptr'"(Converter.vp L190)。
|
||||
# 旧联合写法(如 `GSList[BasicBlock] | CPtr`)已由循环入口
|
||||
# fail-fast 拦截,不再走合并路径。与 HandlesImports 对称,
|
||||
# 用与特化生成端同源的 _resolve_type_arg_str 记录 element_class。
|
||||
if isinstance(item.annotation, ast.Subscript):
|
||||
_ann_sub_c: ast.Subscript = item.annotation
|
||||
_subv_c: ast.AST = _ann_sub_c.value
|
||||
@@ -953,7 +938,7 @@ class ClassHandle(BaseHandle):
|
||||
_elem_slice_c: ast.AST | None = None
|
||||
if _subname_c == 'list':
|
||||
_elem_slice_c = _ann_sub_c.slice
|
||||
elif _subname_c == 'rawptr':
|
||||
elif _subname_c in _PTR_SUBSCRIPT_NAMES:
|
||||
_slice_c: ast.AST = _ann_sub_c.slice
|
||||
if isinstance(_slice_c, ast.Subscript):
|
||||
# rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]):
|
||||
@@ -980,8 +965,8 @@ class ClassHandle(BaseHandle):
|
||||
else:
|
||||
# rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复
|
||||
# struct 身份走 char*→struct cast。HEAD 态 `Token | CPtr` 联合
|
||||
# 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# struct 身份走 char*→struct cast。指针统一为 Subscript
|
||||
# (`rawptr[Token]` / `CPtr[Token]`),由本分支登记。
|
||||
# 与 HandlesImports 的 rawptr 分支对称。
|
||||
_slc_name_c: str | None = None
|
||||
if isinstance(_slice_c, ast.Name):
|
||||
@@ -1549,8 +1534,8 @@ class ClassHandle(BaseHandle):
|
||||
variant_names: list[str] = []
|
||||
|
||||
# 预注册 REnum opaque 结构体到 Gen.structs 和 SymbolTable,
|
||||
# 使自引用成员(如 LLVMType | CPtr)在收集成员时能正确解析为 %LLVMType*。
|
||||
# 若不预注册,GetCTypeInfo 找不到 LLVMType → 回退到 IsEnum → i32 → | CPtr → i32*(错误)。
|
||||
# 使自引用成员(如 CPtr[LLVMType] / rawptr[LLVMType])在收集成员时能正确解析为 %LLVMType*。
|
||||
# 若不预注册,GetCTypeInfo 找不到 LLVMType → 回退到 IsEnum → i32 → 再加一层指针 → i32*(错误)。
|
||||
PreRenumType: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, ClassName)
|
||||
Gen.structs[ClassName] = PreRenumType
|
||||
PreTypeInfo: CTypeInfo = CTypeInfo()
|
||||
@@ -1560,7 +1545,7 @@ class ClassHandle(BaseHandle):
|
||||
PreTypeInfo.IsEnum = True
|
||||
# REnum 在内存布局上是 struct({ i32 __tag, <max_payload> }),
|
||||
# 必须设置 IsStruct=True 才能让 HandlesTypeMerge 的 CPtr 吸收逻辑生效:
|
||||
# `REnumType | CPtr` 应得到 REnumType*(PtrCount=1)而非 REnumType**(PtrCount=2)。
|
||||
# `CPtr[REnumType]` 应得到 REnumType*(PtrCount=1)而非 REnumType**(PtrCount=2)。
|
||||
# 否则 include-imported 函数返回类型会出现双指针,与声明单指针不匹配 → 运行时崩溃。
|
||||
PreTypeInfo.IsStruct = True
|
||||
PreTypeInfo.RenumVariants = []
|
||||
@@ -1695,7 +1680,7 @@ class ClassHandle(BaseHandle):
|
||||
PreTypeInfo.RenumVariants = variant_names
|
||||
|
||||
def _EnumMemberAnnotationIsPtr(self, annotation: ast.AST | None) -> bool:
|
||||
"""枚举成员注解是否含指针形态(逐层下标 + 联合类型逐边),True=含指针
|
||||
"""枚举成员注解是否含指针形态(逐层下标),True=含指针
|
||||
|
||||
与 VPC 侧 ClassGenEnum._enum_member_annotation_is_ptr 同口径。枚举值是
|
||||
整数常量,指针成员语义不成立,必须明确报错(fail-fast)而非静默接受:
|
||||
@@ -1706,8 +1691,10 @@ class ClassHandle(BaseHandle):
|
||||
if annotation is None:
|
||||
return False
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
return (self._EnumMemberAnnotationIsPtr(annotation.left)
|
||||
or self._EnumMemberAnnotationIsPtr(annotation.right))
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
return self._EnumMemberAnnotationIsPtr(annotation.value)
|
||||
name: str | None = None
|
||||
|
||||
Reference in new issue
Block a user