fix(tpv-class): REnum 自引用字段注册后回填别名类型,修复 match 绑定变量退化为整数

This commit is contained in:
TermiNexus committed 2026-09-08 21:30:56 +08:00
1 parent ab814f55e6
commit 709c3570fb
1 file changed
+81 -1
+81 -1
View File
@@ -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