From 709c3570fb884135e896a85fa0381e1760a1ba80 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 8 Sep 2026 21:30:56 +0800 Subject: [PATCH] =?UTF-8?q?fix(tpv-class):=20REnum=20=E8=87=AA=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E5=AD=97=E6=AE=B5=E6=B3=A8=E5=86=8C=E5=90=8E=E5=9B=9E?= =?UTF-8?q?=E5=A1=AB=E5=88=AB=E5=90=8D=E7=B1=BB=E5=9E=8B=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20match=20=E7=BB=91=E5=AE=9A=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E9=80=80=E5=8C=96=E4=B8=BA=E6=95=B4=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/Class/ClassGenEnum.vp | 82 +++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/App/lib/core/Gen/Class/ClassGenEnum.vp b/App/lib/core/Gen/Class/ClassGenEnum.vp index 076b232..29b0af7 100644 --- a/App/lib/core/Gen/Class/ClassGenEnum.vp +++ b/App/lib/core/Gen/Class/ClassGenEnum.vp @@ -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