fix(transpyv): rawptr[T] / t.CPtr[T] 对裸类引用吸收一层指针(不再多包一层)
类别:a(编译器缺陷 —— TPV 注解解析与「联合写法 / TPC 两侧」口径分裂)
现场:includes/ast/tokens.vp:217
ptr: rawptr[Token] = pool.alloc(Token.__sizeof__())
CastError(TPV ExprGenBase.vp:746-753):指针层数不同(源 1 级 → 目标 2 级);
源类型 i8* → 目标类型 %"…Token"**。
根因链:
1. 本文件 Name 分支(:2269-2277):有 __new__ 的堆类裸名注解解析为 Ptr(struct)
(引用语义,注释明写「对齐 TPC」)⇒ Token → %"…Token"*。
2. rawptr[T] 分支(原 :2865-2871)与 t.CPtr[T] 分支(原 :2928-2939)只做
Ptr(resolve(T)),不含「裸类引用吸收一层」⇒ %"…Token"**(2 级)。
3. 同一语义的其余实现都有该规则,唯此两处缺失:
- 联合写法 X | t.CPtr 的 BinOp 分支(:2682-2684 的判据注释 + :2703-2720 回退)
得 1 级;
- TPC 侧 LLVMTypeMapper._rawptr_subscript_type_str(内层映射成 %…* 即吸收)
与 HandlesTypeMerge._MergeAllComponentTypes(IsStruct 时吸收一层)。
规则真源见 TPC SymbolUtils.IsPtrSubscriptNode 文档:「内层 T 为类引用时该层被
结构体自身吸收('<sha1>.X*'),其余(标量 / 已是指针的 typedef / 泛型容器特化 /
嵌套指针下标)逐层外包」。
改动:
1. 新增判据 _ptr_subscript_absorbs_class(slice, resolved):切片**非**用户写明的
指针包装(联合 BinOp / 嵌套 rawptr[...]、t.CPtr[...]、裸名 CPtr[...])且解析
结果已是 Ptr(已注册 struct)(find_struct_by_type 命中,与 BinOp 分支同一判据)
⇒ 返回 1(吸收该层)。纯判据,不发射类型。
2. rawptr[T] 与 t.CPtr[T] 两个分支接入该判据。
逐条核对保持不变的形态:rawptr[int]→i32*、rawptr[str]/rawptr[bytes]→i8**、
t.CPtr[t.CPtr]→i8**、rawptr[rawptr[X]]→X**、t.CPtr[int]→i32*、
rawptr[Point(无 __new__ 的栈类)]→Point*。
影响面:ABI 可见(字段 / 形参 / 局部变量类型),需 TPV 自举重建 + 整轮回归验证。
This commit is contained in:
1 parent
c2d7480f3d
commit
8e7d7feb57
1 file changed
+59
@@ -1599,6 +1599,57 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if nm.id is None or string.strcmp(nm.id, "t") != 0:
|
||||
return 0
|
||||
return 1
|
||||
def _ptr_subscript_absorbs_class(self, slice_node: ast.AST*,
|
||||
resolved: llvmlite.LLVMType*) -> int:
|
||||
"""`rawptr[T]` / `t.CPtr[T]` 的切片 T 是**裸类引用**时是否吸收该层指针(1=吸收)。
|
||||
|
||||
语义真源:`rawptr[T]` ≡ `t.CPtr[T]` ≡ 源码联合写法 `T | t.CPtr`
|
||||
(TPC 侧 SymbolUtils.IsPtrSubscriptNode 文档),三者必须得到**同一类型**。
|
||||
联合写法在本文件 BinOp 分支得到的是「裸类名先被丢弃、再按类名取 struct 包一层」
|
||||
⇒ `X*`(见 :2682-2684 的口径注释与 :2703-2720 的回退);而 rawptr/CPtr
|
||||
下标分支此前无脑 `Ptr(resolve(T))`,对「有 __new__ 的堆类」(本文件 Name 分支
|
||||
:2269-2277 已把裸类名解析为 Ptr(struct))就多包一层 ⇒ `X**`
|
||||
(现场:includes/ast/tokens.vp:217 `ptr: rawptr[Token] = pool.alloc(...)`
|
||||
目标 %"…Token"** vs 源 i8* → CastError)。
|
||||
|
||||
判据(两条件同时成立才吸收,与 BinOp 分支的"Ptr 的 pointee 是否为已注册
|
||||
struct,find_struct_by_type 命中即吸收"逐字同源):
|
||||
① 切片不是**用户写明的指针包装**——联合写法(BinOp)与嵌套指针下标
|
||||
(`rawptr[...]` / `t.CPtr[...]` / 裸名 `CPtr[...]`)的层数由用户指定,
|
||||
必须逐层外包(`rawptr[rawptr[X]] → X**`、`t.CPtr[t.CPtr] → i8**`);
|
||||
② 解析结果已是 `Ptr(已注册 struct)`——即切片本身就是类引用;
|
||||
`str`/`bytes`(Ptr(i8))与标量(非指针)不满足 ⇒ 保持
|
||||
`rawptr[int] → i32*`、`rawptr[str] → i8**`(与 TPC 同口径)。
|
||||
|
||||
纯判据:不发射类型、不改动任何已解析结果。
|
||||
"""
|
||||
if slice_node is None or resolved is None:
|
||||
return 0
|
||||
k_sl: int = slice_node.kind()
|
||||
if k_sl == ast.ASTKind.BinOp:
|
||||
return 0
|
||||
if k_sl == ast.ASTKind.Subscript:
|
||||
sub_sl: ast.Subscript* = ast.Subscript*(slice_node)
|
||||
if sub_sl.value is not None:
|
||||
vk_sl: int = sub_sl.value.kind()
|
||||
if vk_sl == ast.ASTKind.Name:
|
||||
vn_sl: ast.Name* = ast.Name*(sub_sl.value)
|
||||
if vn_sl.id is not None:
|
||||
if string.strcmp(vn_sl.id, "rawptr") == 0 \
|
||||
or string.strcmp(vn_sl.id, "CPtr") == 0:
|
||||
return 0
|
||||
elif vk_sl == ast.ASTKind.Attribute:
|
||||
va_sl: ast.Attribute* = ast.Attribute*(sub_sl.value)
|
||||
if va_sl.attr is not None and string.strcmp(va_sl.attr, "CPtr") == 0:
|
||||
return 0
|
||||
match resolved:
|
||||
case llvmlite.LLVMType.Ptr(pointee_ab):
|
||||
if pointee_ab is not None:
|
||||
if self.Gen.StructGen.find_struct_by_type(pointee_ab) is not None:
|
||||
return 1
|
||||
case _:
|
||||
pass
|
||||
return 0
|
||||
def _is_cvoid_marker(self, node: ast.AST*,
|
||||
imported_modules: str) -> int:
|
||||
"""检测节点是否为 CVoid 指针标记,返回 1=是 / 0=否"""
|
||||
@@ -2862,11 +2913,15 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# rawptr[T] 内建裸指针:等价 t.CPtr[T] → Ptr(T)(T 自身可含指针层级)。
|
||||
# 与 t.CPtr[T] 语义一致;不处理则泛型特化/builtins 兜底失败 →
|
||||
# "函数返回类型解析失败:注解不可解析"。
|
||||
# T 是**裸类引用**时(已是 Ptr(struct))吸收这一层:`rawptr[X]`
|
||||
# ≡ `X | t.CPtr` ≡ X*(不是 X**),见 _ptr_subscript_absorbs_class。
|
||||
if string.strcmp(gen_nm.id, "rawptr") == 0:
|
||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||
rp_elem: llvmlite.LLVMType* = self.resolve_annotation_type(pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
|
||||
if rp_elem is None:
|
||||
return None
|
||||
if self._ptr_subscript_absorbs_class(sub.slice, rp_elem) != 0:
|
||||
return rp_elem
|
||||
return llvmlite.Ptr(pool, rp_elem)
|
||||
return None
|
||||
gen_ty_nm: llvmlite.LLVMType* = self._resolve_generic_subscript_ty(pool, sub, gen_nm.id, trans,
|
||||
@@ -2925,6 +2980,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# 指针类型: t.CPtr[T] → Ptr(T)(T 自身可含指针层级):t.CPtr[t.CPtr] → i8**,
|
||||
# t.CPtr[int] → i32*(DeclarationGenerator.py L1014-1016 文档化语法)。
|
||||
# T 是**裸类引用**时(已是 Ptr(struct))吸收这一层:t.CPtr[X] ≡ X | t.CPtr
|
||||
# ≡ X*(不是 X**),见 _ptr_subscript_absorbs_class。
|
||||
if string.strcmp(arr_at.attr, "CPtr") == 0:
|
||||
if string.strcmp(arr_val_name.id, "t") != 0 and string.strcmp(arr_val_name.id, "c") != 0 \
|
||||
and self.Gen.ImportsGen.is_module_imported(imported_modules, arr_val_name.id) == 0:
|
||||
@@ -2936,6 +2993,8 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# Phase 1a 无 vpi 注入时依赖 typedef 的类会被跳过)。与裸名 CArray 路径及
|
||||
# ClassGenDef 字段 pending 机制一致;真实类型错误由 Phase A 收敛检查暴露。
|
||||
return None
|
||||
if self._ptr_subscript_absorbs_class(sub.slice, inner_cptr_ty) != 0:
|
||||
return inner_cptr_ty
|
||||
return llvmlite.Ptr(pool, inner_cptr_ty)
|
||||
if string.strcmp(arr_at.attr, "CArray") != 0:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "不支持的 Subscript 类型注解(仅支持 t.CArray / t.Callable)")
|
||||
|
||||
Reference in new issue
Block a user