fix(tpv-class): REnum 自引用字段注册后回填别名类型,修复 match 绑定变量退化为整数
This commit is contained in:
1 parent
ab814f55e6
commit
709c3570fb
1 file changed
+81
-1
@@ -797,9 +797,81 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
# 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造)
|
||||
self._register_renum_variants(pool, class_name, cd, variant_count)
|
||||
|
||||
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)
|
||||
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)。
|
||||
# 注意:遍历发生在 register_struct 之前,注解引用本类自身(如
|
||||
# LLVMType.Ptr.Pointee: rowptr[LLVMType])时类尚未注册 → 别名表类型槽
|
||||
# 为 0 → match 绑定回退槽位 i64 把指针字段读成整数。此处类已注册,
|
||||
# 补一遍字段类型解析回填 0 槽(详见 _refill_renum_field_types)。
|
||||
self._refill_renum_field_types(trans, pool, class_name, cd)
|
||||
|
||||
VLogger.info(f"registered {class_name} with {variant_count} variants, {total_positions} positions", "RENUM")
|
||||
return 0
|
||||
def _refill_renum_field_types(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
class_name: str,
|
||||
cd: ast.ClassDef | t.CPtr):
|
||||
"""REnum 注册完成后补解析变体字段类型(仅回填类型槽为 0 的别名记录)
|
||||
|
||||
第一遍变体字段遍历发生在 register_struct 之前:字段注解引用本 REnum 类
|
||||
自身(如 LLVMType.Ptr.Pointee: rowptr[LLVMType]、Array.ElemTy:
|
||||
rowptr[LLVMType]、Func.Ret: rowptr[LLVMType])时,find_struct 查不到
|
||||
正在注册的类 → resolve_annotation_type 返回 None → _register_renum_field_alias
|
||||
类型槽(RenumAliasTy)落 0。match 绑定时 _lookup_renum_member_ty 查不到
|
||||
成员类型 → 绑定变量按 payload 槽位(i64)读取,把指针字段读成整数 →
|
||||
递归传参/赋值给 rowptr[LLVMType] 形参被 int→ptr 显式拦截误报 CastError
|
||||
(llvmlite __types.vp L448 根因)。
|
||||
|
||||
本方法在 register_struct 完成(自身类已可查)后按与第一遍相同的位置
|
||||
顺序重遍历变体字段并重新解析注解;命中已存在的 (class, field) 别名
|
||||
记录且类型槽为 0 时回填真实类型(非 0 槽与解析失败均保持原状,不覆盖
|
||||
不误伤)。非自引用字段(ParamNode/str/int 等)第一遍已解析成功,去重
|
||||
命中类型槽非 0 → 直接跳过,行为不变。
|
||||
"""
|
||||
if trans is None or pool is None or class_name is None or cd is None:
|
||||
return
|
||||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
return
|
||||
cn: t.CSizeT = len(children)
|
||||
for ci in range(cn):
|
||||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||||
if stmt is None or stmt.kind() != ast.ASTKind.ClassDef:
|
||||
continue
|
||||
variant_cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt)
|
||||
if variant_cd is None or variant_cd.name is None \
|
||||
or variant_cd.children is None:
|
||||
continue
|
||||
vchildren: list[ast.AST | t.CPtr] | t.CPtr = variant_cd.children
|
||||
vcn: t.CSizeT = len(vchildren)
|
||||
field_idx: int = 0
|
||||
for vi in range(vcn):
|
||||
vstmt: ast.AST | t.CPtr = vchildren.get(vi)
|
||||
if vstmt is None:
|
||||
continue
|
||||
if vstmt.kind() != ast.ASTKind.AnnAssign:
|
||||
continue
|
||||
vaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(vstmt)
|
||||
if vaa is None or vaa.target is None or vaa.annotation is None:
|
||||
# 与第一遍同规则:无效 AnnAssign 不占用 payload 槽位
|
||||
continue
|
||||
if vaa.target.kind() != ast.ASTKind.Name:
|
||||
continue
|
||||
vnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(vaa.target)
|
||||
if vnm.id is None:
|
||||
# 与第一遍同规则:有效 AnnAssign 仍占用 payload 槽位
|
||||
field_idx += 1
|
||||
continue
|
||||
mem_ty_l: llvmlite.LLVMType | t.CPtr = \
|
||||
self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, vaa.annotation,
|
||||
trans._imported_modules,
|
||||
trans._from_imports, trans, 0)
|
||||
# 解析成功 → 触发别名表去重路径(类型槽为 0 时回填;非 0 跳过)
|
||||
if mem_ty_l is not None:
|
||||
self._register_renum_field_alias(
|
||||
pool, class_name, vnm.id, field_idx + 1,
|
||||
mem_ty_l, variant_cd.name)
|
||||
field_idx += 1
|
||||
def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
class_name: str,
|
||||
cd: ast.ClassDef | t.CPtr,
|
||||
@@ -980,6 +1052,14 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
fld_existing_ptr: str = (str | t.CPtr)(
|
||||
t.CVoid(self.RenumAliasField[i], t.CPtr))
|
||||
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
|
||||
# 已存在记录:首遍注册期解析失败(自引用字段,见
|
||||
# _refill_renum_field_types)类型槽为 0 时,本次解析成功则
|
||||
# 回填真实类型;非 0 槽保持原样(避免重复 DeepCopy 覆盖抖动)。
|
||||
if self.RenumAliasTy[i] == 0 and field_ty is not None:
|
||||
ty_copy_rf2: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.factory.PermPool, field_ty)
|
||||
if ty_copy_rf2 is not None:
|
||||
self.RenumAliasTy[i] = t.CSizeT(ty_copy_rf2)
|
||||
return
|
||||
|
||||
idx: int = self.RenumAliasCount
|
||||
|
||||
Reference in new issue
Block a user