Files
ViperC/App/lib/core/Gen/Class/ClassGenEnum.vp
T
TermiNexus aa52cf157d revert(transpyv): 回滚跨模块链表 Next 改访问器(改由编译器沿继承链解析字段名)
回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。

理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
  · e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
    展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
  · 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。

注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
2026-09-28 21:48:53 +08:00

1512 lines
80 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import lib.core.Gen.GenTypes as GenTypes
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HT
import lib.core.CompilerFactory as CompilerFactory
from . import ClassGenBase
# ============================================================
# 本地常量副本(原 HandlesEnum/HandlesClassDef 定义,拆分时随文件删除而丢失——
# 未定义名在常量上下文被 TPV 折叠为 0,会导致枚举成员收集被静默跳过、
# register_enum 永不调用 → 所有 CEnum 注册失败 → 裸名枚举访问 NameError)
# ============================================================
define ENUM_MEMBER_MAX_LOCAL = 128
define RENUM_CLASS_MAX = 64
define RENUM_VARIANT_PER_CLASS = 32
define RENUM_ALIAS_MAX = 512
# ============================================================
# ClassGenEnum - ClassGenMixin 拆分(阶段 D):enum/union/renum 定义与变体表
# ============================================================
novirtual class ClassGenEnum(ClassGenBase.ClassGenBase):
"""enum/union/renum 定义与变体表"""
def _resolve_enum_member_type(self, pool: memhub.MemBuddy*,
ann_node: ast.AST*,
imported_modules: str,
from_imports: str) -> llvmlite.LLVMType*:
"""解析枚举成员的类型注解为 LLVM 整数类型"""
if ann_node is None:
return llvmlite.Int32(pool)
k: int = ann_node.kind()
# Attribute 节点: t.State / int / int8 等
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(ann_node)
if at.attr is None:
# [S4 fail-fast] Attribute 缺失成员名(AST 损坏),不再静默回退 i32
self.Gen.TypeGenErr.fatal_error(ann_node, "枚举成员类型注解 Attribute 缺失成员名", "TypeError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
# t.State → 默认 i32
if string.strcmp(at.attr, "State") == 0:
return llvmlite.Int32(pool)
# [枚举侧 bool 口径] `t.CBool` 与裸名 `bool` 同宽(8 位),否则同一
# 枚举成员两种写法会分裂出 i1 / i8 两种宽度。全局 `t.CBool` = i1
# (map_t_type L1447-1449)保持不变,仅在**枚举成员注解**这一处按
# 8 位物化(枚举存储须可按字节寻址;TPC 侧 t.CBool.Size = 8 同口径)。
if string.strcmp(at.attr, "CBool") == 0:
return llvmlite.Int8(pool)
# 其他 t.CXxx 类型:统一口径(CTypedef 动态表优先,miss 回退 map_t_type)
ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, at.attr, imported_modules, from_imports)
if ty is not None: return ty
# [S4 fail-fast] 有注解但解析失败 → 不再静默回退 i32
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: t.{at.attr}", "NameError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
# Name 节点: from-import 形式(State / CInt)
if k == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(ann_node)
if nm.id is None:
# [S4 fail-fast] Name 缺失标识符(AST 损坏),不再静默回退 i32
self.Gen.TypeGenErr.fatal_error(ann_node, "枚举成员类型注解 Name 缺失标识符", "TypeError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
if string.strcmp(nm.id, "State") == 0:
return llvmlite.Int32(pool)
# 内建裸名整数类型(与 resolve_annotation_type 的 Name 分支同口径,
# TypeGenResolve.vp L2189-2203):枚举成员是整数常量,`int` / `char` /
# `bool` 裸名直通。其余裸名(含 str/bytes 指针形态与未知名)仍走
# typedef / builtins 表,miss 即下方 fail-fast(不静默当 int);
# 指针与非整数成员的统一拦截见 _translate_enum_def。
if string.strcmp(nm.id, "int") == 0:
return llvmlite.Int32(pool)
if string.strcmp(nm.id, "char") == 0:
return llvmlite.Int8(pool)
if string.strcmp(nm.id, "bool") == 0:
# [枚举侧 bool 口径] 枚举存储必须是可按字节寻址的整数类型,
# i1 不能作为独立枚举宽度 ⇒ 枚举成员注解的 bool 一律 8 位。
# **不改**全局 bool = i1(TypeGenResolve.vp L2201-2203 与
# map_t_type 的 CBool,用于普通变量/形参/字段)。
# 两侧一致:TPC 侧枚举成员 bool 经 t.CBool.Size 亦为 8。
return llvmlite.Int8(pool)
ty2: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, nm.id, imported_modules, from_imports)
if ty2 is not None:
return ty2
# [S4 fail-fast] 有注解但解析失败 → 不再静默回退 i32
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {nm.id}", "NameError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
# BinOp 节点: t.State | int8(递归查找实际类型)
if k == ast.ASTKind.BinOp:
bop: ast.BinOp* = ast.BinOp*(ann_node)
if bop.op == ast.OpKind.BitOr:
left_ty: llvmlite.LLVMType* = self._resolve_enum_member_type(pool, bop.left, imported_modules, from_imports)
# 跳过 t.State(i32 默认),优先返回具体类型
left_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(left_ty)
if left_bits != 0 and not self._is_state_annotation(bop.left):
return left_ty
right_ty: llvmlite.LLVMType* = self._resolve_enum_member_type(pool, bop.right, imported_modules, from_imports)
if right_ty is not None and not self._is_state_annotation(bop.right):
return right_ty
# 两边都是 State 或无法确定,返回较宽的
right_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(right_ty)
if left_bits >= right_bits:
return left_ty
return right_ty
# fail-fast:BinOp 但非 BitOr(未知联合运算),不再静默回退 i32
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
# fail-fast:未知注解节点 kind,不再静默回退 i32
self.Gen.TypeGenErr.fatal_error(ann_node, f"枚举成员类型注解解析失败: {self.Gen.TypeGenResolve.annotation_to_str(ann_node)}", "TypeError")
return llvmlite.Int32(pool) # 不可达(fatal_error 已退出)
def _is_state_annotation(self, node: ast.AST*) -> int:
"""检查注解节点是否为 t.State,返回 1=是 / 0=否"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
if at.attr is not None and string.strcmp(at.attr, "State") == 0:
return 1
return 0
if k == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(node)
if nm.id is not None and string.strcmp(nm.id, "State") == 0:
return 1
return 0
return 0
def _enum_annotation_name_is_ptr(self, node: ast.AST*) -> int:
"""注解节点本身(Name/Attribute/Subscript 顶名)是否指针形态,1=是 / 0=否
指针标记名集合与 resolve_annotation_type / map_t_type 的指针产出点同源:
CPtr(= rawptr/str/bytes 的底层,map_t_type L1407)、CNeedPtr / CAutoPtr
(map_t_type L1421-1424 均为 i8*)、rawptr(内建指针,_lookup_builtins_typedef
L921-923 恒返回 t.CPtr)、str / bytes(resolve_annotation_type L2190-2200 → i8*)。
"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
if at.attr is not None:
if string.strcmp(at.attr, "CPtr") == 0:
return 1
if string.strcmp(at.attr, "CNeedPtr") == 0:
return 1
if string.strcmp(at.attr, "CAutoPtr") == 0:
return 1
if string.strcmp(at.attr, "rawptr") == 0:
return 1
if string.strcmp(at.attr, "str") == 0:
return 1
if string.strcmp(at.attr, "bytes") == 0:
return 1
return 0
if k == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(node)
if nm.id is not None:
if string.strcmp(nm.id, "CPtr") == 0:
return 1
if string.strcmp(nm.id, "CNeedPtr") == 0:
return 1
if string.strcmp(nm.id, "CAutoPtr") == 0:
return 1
if string.strcmp(nm.id, "rawptr") == 0:
return 1
if string.strcmp(nm.id, "str") == 0:
return 1
if string.strcmp(nm.id, "bytes") == 0:
return 1
return 0
if k == ast.ASTKind.Subscript:
sub: ast.Subscript* = ast.Subscript*(node)
if sub.value is not None:
return self._enum_annotation_name_is_ptr(sub.value)
return 0
return 0
def _enum_member_annotation_is_ptr(self, ann_node: ast.AST*) -> int:
"""枚举成员注解(**含联合类型逐边**)是否含指针类型,1=是 / 0=否
联合形态必须逐边检查:`t.CInt | t.CPtr` 在 _resolve_enum_member_type 的
BinOp 分支会"优先返回具体整数类型"(源码 L94-105)——只看解析结果会把
含指针的联合静默当整数,故在解析前按注解树拦。
"""
if ann_node is None:
return 0
if ann_node.kind() == ast.ASTKind.BinOp:
bop: ast.BinOp* = ast.BinOp*(ann_node)
if bop.op != ast.OpKind.BitOr:
return 0
if self._enum_member_annotation_is_ptr(bop.left) == 1:
return 1
return self._enum_member_annotation_is_ptr(bop.right)
return self._enum_annotation_name_is_ptr(ann_node)
def _extract_int_value(self, node: ast.AST*) -> int64:
"""从 AST 节点提取整数值,失败返回 0"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Constant:
cn: ast.Constant* = ast.Constant*(node)
if cn.const_kind == ast.CONST_INT:
return cn.int_val
return 0
if k == ast.ASTKind.UnaryOp:
uo: ast.UnaryOp* = ast.UnaryOp*(node)
if uo.op == ast.OpKind.USub:
inner: int64 = self._extract_int_value(uo.operand)
return -inner
return 0
return 0
# ========================================================
# 枚举成员"可见名 vs 登记名"兜底判据(与 TPC 侧
# SymbolUtils.EnumBodyMemberNames 同口径、同规则源)
#
# 背景:`enum` 成员行一旦出现"注册器不认的写法",成员会被**静默丢弃**
# (ASTKind 71→3、OpKind 32→2;与 Debugger/enum-semantics.md §15、
# rawptr-migration-and-fastfail.md §27 同族,这是第三次复发)。取全口径而非
# 逐个白名单化"已知可展开形态":成员名必然落在 Assign 的 targets / AnnAssign
# 的 target / Expr 语句的表达式这三类"名字位置"之一,把它们**全部**数进来,
# 任何漏登记的写法都会表现为"可见名数 > 登记数" ⇒ 注册处 fail-fast。
# ========================================================
def _enum_elts_visible_names(self, elts: list[ast.AST*]*) -> int:
"""元素表里的"可见名"计数(Tuple/List 共用)。"""
if elts is None:
return 0
n: int = 0
for i in range(len(elts)):
n += self._enum_target_visible_names(elts.get(i))
return n
def _enum_target_visible_names(self, node: ast.AST*) -> int:
"""成员名位置的"可见名"计数(Name / Tuple / List 逐项、Starred 解引用递归)。
与 TPC 侧 SymbolUtils._EnumMemberNameNodes 同口径:把"注册器不认的成员
写法"(逗号组 Tuple、元组目标、Starred)里的成员名照样数进来。
"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Name:
return 1
if k == ast.ASTKind.Tuple:
tup: ast.Tuple* = ast.Tuple*(node)
return self._enum_elts_visible_names(tup.elts)
if k == ast.ASTKind.List:
lst: ast.List* = ast.List*(node)
return self._enum_elts_visible_names(lst.elts)
if k == ast.ASTKind.Starred:
st: rawptr[ast.Starred] = rawptr[ast.Starred](node)
return self._enum_target_visible_names(st.value)
return 0
def _enum_body_visible_names(self, children: list[ast.AST*]*) -> int:
"""枚举类体内"源码可见的成员名"总数(含注册器不认的写法)。
Assign 的每个 target / AnnAssign 的 target / Expr 语句的表达式;
不含成员名的语句(docstring / pass / 方法定义 / 嵌套类)计 0,不误报。
"""
if children is None:
return 0
n: int = 0
for ci in range(len(children)):
stmt: ast.AST* = children.get(ci)
if stmt is None:
continue
sk: int = stmt.kind()
if sk == ast.ASTKind.Assign:
ag: ast.Assign* = ast.Assign*(stmt)
if ag.targets is not None:
for ti in range(len(ag.targets)):
n += self._enum_target_visible_names(ag.targets.get(ti))
elif sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
n += self._enum_target_visible_names(aa.target)
elif sk == ast.ASTKind.Expr:
ex: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
n += self._enum_target_visible_names(ex.value)
return n
def _enum_first_unregistered_node(self, children: list[ast.AST*]*) -> ast.AST*:
"""第一个"含可见成员名但注册器不认"的语句(供 fail-fast 定位真行号);无则 None。"""
if children is None:
return None
for ci in range(len(children)):
stmt: ast.AST* = children.get(ci)
if stmt is None:
continue
sk: int = stmt.kind()
if sk == ast.ASTKind.Expr:
ex: rawptr[ast.Expr] = rawptr[ast.Expr](stmt)
if self._enum_target_visible_names(ex.value) > 0:
return stmt
elif sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa.target is not None and aa.target.kind() != ast.ASTKind.Name \
and self._enum_target_visible_names(aa.target) > 0:
return stmt
elif sk == ast.ASTKind.Assign:
ag: ast.Assign* = ast.Assign*(stmt)
if ag.targets is not None:
for ti in range(len(ag.targets)):
tgt: ast.AST* = ag.targets.get(ti)
if tgt is not None and tgt.kind() != ast.ASTKind.Name \
and self._enum_target_visible_names(tgt) > 0:
return stmt
return None
def _translate_enum_def(self, trans: HT.Translator*,
cd: ast.ClassDef*) -> int:
"""翻译枚举类定义,返回 0"""
if cd is None or cd.name is None or trans is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
class_name: str = cd.name
# 不按全局同名跳过:跨模块可能同名枚举(includes/w32/fileio.vp 的
# FRESULT 与 fat32_types.vp 的 FRESULT),跳过会导致后注册模块的
# 成员缺失(FR_OK 找不到)。register_enum 幂等返回已有 entry,
# add_enum_member 成员名去重,重复处理安全合并。
children: list[ast.AST*]* = cd.children
if children is None:
VLogger.warning(f"{class_name} has no body", "ENUM")
return 0
cn: sizet = len(children)
# 临时数组存储成员信息
member_names_buf: sizet* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
member_types_buf: sizet* = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
member_values_buf: int64 | t.CPtr = pool.alloc(8 * ENUM_MEMBER_MAX_LOCAL)
if member_names_buf is None or member_types_buf is None or member_values_buf is None:
return 0
string.memset(member_names_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
string.memset(member_types_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
string.memset(member_values_buf, 0, 8 * ENUM_MEMBER_MAX_LOCAL)
member_count: int = 0
next_val: int64 = 0
for ci in range(cn):
stmt: ast.AST* = children.get(ci)
if stmt is None:
continue
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa is None or aa.target is None:
continue
# 获取成员名
if aa.target.kind() != ast.ASTKind.Name:
continue
tgt: ast.Name* = ast.Name*(aa.target)
if tgt.id is None:
continue
# [枚举规格 fail-fast] 成员不允许指针类型:t.CPtr / CNeedPtr /
# CAutoPtr / rawptr[...] / str / bytes,以及**联合类型里夹带指针**
# 的形态(t.CInt | t.CPtr)。必须先于类型解析——联合分支会优先返回
# 具体整数类型、rawptr[...] 又是 Subscript(非 Name/Attribute/BinOp)
# 会在解析里报笼统的"注解解析失败",两者都盖不住"指针成员"这个真因。
if self._enum_member_annotation_is_ptr(aa.annotation) == 1:
self.Gen.TypeGenErr.fatal_error(aa, f"枚举成员 '{tgt.id}' 不能是指针类型(枚举值只支持整数成员类型)", "TypeError")
return 0 # 不可达(fatal_error 已退出)
# 解析成员类型
member_ty: llvmlite.LLVMType* = self._resolve_enum_member_type(pool, aa.annotation, trans._imported_modules, trans._from_imports)
# [枚举规格 fail-fast] 成员类型必须是整数类型:浮点/void/结构体/
# 数组的位宽均为 0,无法参与"枚举宽度 = 最宽成员类型"的推导,
# 静默接受会让寄存器宽度与访问侧常量类型不一致。禁止静默降级。
member_bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(member_ty)
if member_bits <= 0:
self.Gen.TypeGenErr.fatal_error(aa, f"枚举成员 '{tgt.id}' 的类型必须为整数类型(不允许指针/浮点/void/结构体/数组),无法推导枚举宽度", "TypeError")
return 0 # 不可达(fatal_error 已退出)
# 解析成员值
has_value: int = 0
cur_val: int64 = 0
if aa.value is not None:
cur_val = self._extract_int_value(aa.value)
has_value = 1
else:
cur_val = next_val
# 下一个自动值
next_val = cur_val + 1
# 存储
if member_count < ENUM_MEMBER_MAX_LOCAL:
member_names_buf[member_count] = sizet(tgt.id)
member_types_buf[member_count] = sizet(member_ty)
member_values_buf[member_count] = cur_val
member_count += 1
elif sk == ast.ASTKind.Assign:
# 处理 Assign 形式的枚举成员: DEBUG = 0, INFO = 1 等
# CEnum 子类中无类型注释的赋值也视为枚举成员。
# 每个 Name target 都是成员(`A = B = 1` 两个名字都登记——与 TPC
# HandlesClassDef._RegisterEnumMembers 的逐 target 口径一致;此前
# 只取 targets[0] 会让后续 target 静默漏成员)。
ag: ast.Assign* = ast.Assign*(stmt)
if ag is None or ag.targets is None:
continue
tgts: list[ast.AST*]* = ag.targets
tn: sizet = len(tgts)
if tn == 0:
continue
# Assign 无类型注释,默认使用 i32
member_ty_a: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 解析成员值(同一语句的所有 target 共享该值,next_val 只推进一次)
cur_val_a: int64 = 0
if ag.value is not None:
cur_val_a = self._extract_int_value(ag.value)
else:
cur_val_a = next_val
next_val = cur_val_a + 1
# 存储(逐 target;非 Name target 由注册处兜底判据拦住)
for ti in range(tn):
t0: ast.AST* = tgts.get(ti)
if t0 is None or t0.kind() != ast.ASTKind.Name:
continue
tgt_a: ast.Name* = ast.Name*(t0)
if tgt_a.id is None:
continue
if member_count < ENUM_MEMBER_MAX_LOCAL:
member_names_buf[member_count] = sizet(tgt_a.id)
member_types_buf[member_count] = sizet(member_ty_a)
member_values_buf[member_count] = cur_val_a
member_count += 1
# [兜底判据 fail-fast] "源码里可见的成员名字数" vs "实际登记成员数"。
# 任何注册器不认的成员写法(逗号组带值 `A, B = 1`、逗号组带注解
# `A, B: T`、单名尾随逗号 `A,`、元组目标,以及未来出现的新形态)都会让
# 可见名数 > 登记数——此前是**静默丢成员**(ASTKind 71→3、OpKind 32→2;
# 与 Debugger/enum-semantics.md §15、rawptr-migration-and-fastfail.md §27
# 同族,这是第三次复发),此处一律 fail-fast,不再静默跳过。
# 判据口径与 TPC HandlesClassDef._RegisterEnumMembers 完全一致(同规则源)。
visible_count: int = self._enum_body_visible_names(children)
if visible_count != member_count:
diff_count: int = visible_count - member_count
bad: ast.AST* = self._enum_first_unregistered_node(children)
bad_desc: str = "(无法定位到具体语句,请检查枚举体)"
if bad is not None:
bad_desc = bad.type_name()
self.Gen.TypeGenErr.fatal_error(
bad if bad is not None else cd,
f"枚举 '{class_name}' 成员登记数不一致:源码里可见的成员名 {visible_count} 个,"
f"实际只登记 {member_count} 个(差额 {diff_count} 个会被静默丢弃)。"
f"未识别的成员写法(首个): {bad_desc} 形态的语句——如逗号组带值 `A, B = 1`、"
f"逗号组带注解 `A, B: T`、单名尾随逗号 `A,`。"
f"期望形态: 每行一个 `Name` / `Name: T` / `Name = 值`,"
f"或多个简单标识符用逗号分隔(`A, B, C`,可带尾随逗号)。"
f"修法: 把该行改写为逐个成员一行,或改写为纯标识符逗号组(去掉 `= 值` / `: T`)。"
f"(本判据在注册处比对『可见名数 vs 登记数』,任何未识别形态都会命中,"
f"不再静默丢成员)",
"TypeError")
return 0
if member_count == 0:
VLogger.warning(f"{class_name} has no members", "ENUM")
return 0
# 确定基准类型:所有成员类型中 Bits 最大的
base_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
max_bits: int = 0
for mi in range(member_count):
ty_addr: sizet = member_types_buf[mi]
if ty_addr == 0:
continue
mty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(ty_addr)
bits: int = self.Gen.TypeGenErr.get_llvm_type_bits(mty)
if bits > max_bits:
max_bits = bits
base_ty = mty
# 注册枚举
entry: rawptr[GenTypes.EnumEntry] = self.Gen.StmtGenDecl.register_enum(pool, class_name, base_ty)
if entry is None:
VLogger.error("failed to register {class_name}", "ENUM")
return 0
# 添加成员
for mi in range(member_count):
fname_addr: sizet = member_names_buf[mi]
if fname_addr == 0:
continue
mname: str = rawptr(fname_addr)
fty_addr2: sizet = member_types_buf[mi]
if fty_addr2 == 0:
continue
mty2: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr2)
mval: int64 = member_values_buf[mi]
if mname is not None and mty2 is not None:
self.Gen.StmtGenDecl.add_enum_member(pool, entry, mname, mval, mty2)
VLogger.info(f"registered {class_name} with {member_count} members, base_bits={max_bits}", "ENUM")
return 0
def _get_type_size(self, ty: llvmlite.LLVMType*) -> int:
"""计算 LLVM 类型的字节大小(含对齐 padding)"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Int(bits):
return (bits + 7) // 8
case llvmlite.LLVMType.Float(bits):
return bits // 8
case llvmlite.LLVMType.Ptr(pointee):
return 8
case llvmlite.LLVMType.Array(elem_ty, count):
return self._get_type_size(elem_ty) * count
case llvmlite.LLVMType.Struct(fields, fcount, name):
# 计算结构体大小,考虑字段对齐 padding
# 规则: 每个字段的对齐 = 该字段类型的自然对齐
# 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1
# 结构体总大小需对齐到最大字段对齐的倍数
# packed(@c.Attribute(t.attr.packed))结构体无字段填充:
# 大小 = 字段尺寸之和(LLVM packed struct 语义)。
is_packed: int = self.Gen.StructGen.struct_type_is_packed(ty)
total: int = 0
max_align: int = 1
cur: rawptr[llvmlite.ParamNode] = fields
i: int = 0
while cur is not None and i < fcount:
if cur.Ty is not None:
fty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(cur.Ty)
fsize: int = self._get_type_size(fty)
falign: int = self._get_type_align(fty)
# 对齐当前偏移到字段对齐边界(packed 不插填充)
if is_packed == 0 and falign > 0:
rem: int = total % falign
if rem != 0:
total += falign - rem
total += fsize
if is_packed == 0 and falign > max_align:
max_align = falign
cur = cur.Next
i += 1
# packed 无尾部对齐;非 packed 总大小对齐到最大字段对齐的倍数
if is_packed != 0:
return total
rem2: int = total % max_align
if rem2 != 0:
total += max_align - rem2
return total
case _:
return 8
def _get_type_align(self, ty: llvmlite.LLVMType*) -> int:
"""返回类型的自然对齐(字节)"""
if ty is None:
return 1
match ty:
case llvmlite.LLVMType.Int(bits):
if bits <= 8:
return 1
elif bits <= 16:
return 2
elif bits <= 32:
return 4
else:
return 8
case llvmlite.LLVMType.Float(bits):
if bits <= 32:
return 4
else:
return 8
case llvmlite.LLVMType.Ptr(pointee):
return 8
case llvmlite.LLVMType.Array(elem_ty, count):
return self._get_type_align(elem_ty)
case llvmlite.LLVMType.Struct(fields, fcount, name):
# packed 结构体整体按字节对齐(对齐 1,无填充)
if self.Gen.StructGen.struct_type_is_packed(ty) != 0:
return 1
# 结构体的对齐 = 最大字段对齐
max_align: int = 1
cur: rawptr[llvmlite.ParamNode] = fields
i: int = 0
while cur is not None and i < fcount:
if cur.Ty is not None:
fty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(cur.Ty)
fa: int = self._get_type_align(fty)
if fa > max_align:
max_align = fa
cur = cur.Next
i += 1
return max_align
case _:
return 8
def _translate_union_def(self, trans: HT.Translator*,
cd: ast.ClassDef*) -> int:
"""翻译联合体定义,返回 0"""
if cd is None or cd.name is None or trans is None: return 0
pool: memhub.MemBuddy* = trans.Pool
class_name: str = cd.name
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前)
self.Gen.StructGen.add_visible_struct(pool, class_name)
# 检查是否已注册(用 SHA1 区分跨模块同名类)
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
if existing is not None:
# Phase B: 将已存在的命名结构体注册到当前模块
if existing.Ty is not None:
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
# SHA1 已在 register_struct 时设置,无需再补
return 0
children: list[ast.AST*]* = cd.children
if children is None:
VLogger.warning("{class_name} has no body", "UNION")
return 0
cn: sizet = len(children)
# 临时数组存储字段信息
field_names_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
field_types_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
if field_names_buf is None or field_types_buf is None:
return 0
string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX)
string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX)
field_count: int = 0
max_size: int = 0
for ci in range(cn):
stmt: ast.AST* = children.get(ci)
if stmt is None: continue
sk: int = stmt.kind()
if sk == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
if aa is None or aa.target is None: continue
# 获取字段名
if aa.target.kind() != ast.ASTKind.Name: continue
tgt: ast.Name* = ast.Name*(aa.target)
if tgt.id is None: continue
# 解析字段类型
field_ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
if field_ty is None:
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
# 静默 return 1 让多遍收敛机制生效(renum 返回 1=跳过该类)
if trans._declare_only == 1: return 1
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止
type_name: str = self.Gen.TypeGenResolve.annotation_to_str(aa.annotation)
self.Gen.TypeGenErr.fatal_error(aa, f"'{type_name}' is not defined", "NameError")
field_ty = llvmlite.Int32(pool)
# 计算字段大小,更新 max_size
fsize: int = self._get_type_size(field_ty)
if fsize > max_size:
max_size = fsize
# 存储到数组
if field_count < GenTypes.FIELD_MAX:
field_names_buf[field_count] = sizet(tgt.id)
field_types_buf[field_count] = sizet(field_ty)
field_count += 1
if field_count == 0:
VLogger.warning(f"{class_name} has no fields", "UNION")
return 0
if max_size < 1:
max_size = 1
# 创建联合体的 LLVM 类型: Struct([Array(Int8, max_size)])
# 即 { [max_size x i8] }
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
array_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, max_size)
# 构建 ParamNode 链表(单字段:字节数组)
pnode: rawptr[llvmlite.ParamNode] = pool.alloc(llvmlite.ParamNode.__sizeof__())
if pnode is None:
return 0
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
pnode.Ty = array_ty
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
union_type_name: str = class_name
if trans.ModuleSha1 is not None:
union_name_buf: str = pool.alloc(64)
if union_name_buf is not None:
viperlib.snprintf(union_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
union_type_name = union_name_buf
union_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, pnode, 1, union_type_name)
if union_ty is None:
VLogger.error(f"failed to create type for {class_name}", "UNION")
return 0
# Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活)
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc 预注册
# includes 时 declare_only=1,若仍用 pool struct_ty,reset_to(mark2) 后
# entry.Ty 悬空 → 后续文件 opaque 扫描跨模块引用遍历悬空 fields 崩溃
# (LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0:
union_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, union_ty)
if union_copy is not None:
union_ty = union_copy
# 注册命名结构体到模块
llvmlite.module_add_named_type(trans.Module, pool, union_ty)
# 注册到 HandlesStruct(传递 SHA1 在注册时直接设置,避免跨模块同名找错 entry)
entry: GenTypes.StructEntry* = self.Gen.StructGen.register_struct(pool, class_name, union_ty, trans.ModuleSha1)
if entry is None:
VLogger.error(f"failed to register {class_name}", "UNION")
return 0
# 标记为当前文件可见(命名空间隔离)
self.Gen.StructGen.add_visible_struct(pool, class_name)
# 标记为联合体(直接用 entry,规避跨模块同名 find_struct 找错)
entry.IsUnion = 1
# 添加字段信息(所有字段 Index=0,因为共享偏移 0)
for fi in range(field_count):
fname_addr: sizet = field_names_buf[fi]
if fname_addr == 0:
continue
fname: str = rawptr(fname_addr)
fty_addr2: sizet = field_types_buf[fi]
if fty_addr2 == 0:
continue
fty2: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr2)
if fname is not None and fty2 is not None:
self.Gen.StructGen.add_field(pool, entry, fname, fty2, None, None)
VLogger.info(f"registered {class_name} with {field_count} fields, max_size={max_size}", "UNION")
return 0
def _get_annotation_field_size(self, pool: memhub.MemBuddy*,
annotation: ast.AST*) -> int:
"""计算注解类型的字节大小,用于 REnum 布局计算"""
if annotation is None:
return 8
k: int = annotation.kind()
# 联合类型 A | B → 指针大小 8
if k == ast.ASTKind.BinOp:
return 8
# Name(id) 或 Attribute(attr) → 解析类型名
type_name: str = None
if k == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(annotation)
if nm is not None:
type_name = nm.id
elif k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(annotation)
if at is not None:
type_name = at.attr
if type_name is None:
return 8
# [阶段3] 统一尺寸口径:库 typedef(BYTE/DWORD 等)先经正常库分析解析,
# miss 才走下方硬编码尺寸表(t/c 核心原语)。
dyn_sz: int = self.Gen.TypeGenResolve.get_type_size_bytes(pool, type_name, None, None)
if dyn_sz > 0:
return dyn_sz
# 内置类型
if string.strcmp(type_name, "int") == 0: return 4
if string.strcmp(type_name, "CInt") == 0: return 4
if string.strcmp(type_name, "CInt8T") == 0: return 1
if string.strcmp(type_name, "CInt16T") == 0: return 2
if string.strcmp(type_name, "CInt32T") == 0: return 4
if string.strcmp(type_name, "CInt64T") == 0: return 8
if string.strcmp(type_name, "CChar") == 0: return 1
if string.strcmp(type_name, "CDouble") == 0: return 8
if string.strcmp(type_name, "CFloat") == 0: return 4
if string.strcmp(type_name, "CPtr") == 0: return 8
if string.strcmp(type_name, "CSizeT") == 0: return 8
if string.strcmp(type_name, "str") == 0: return 8
if string.strcmp(type_name, "bytes") == 0: return 8
if string.strcmp(type_name, "bool") == 0: return 1
# 已注册的结构体类型
struct_ty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(type_name)
if struct_ty is not None:
sz: int = self._get_type_size(struct_ty)
if sz > 0:
return sz
# 未注册类型 → 默认指针大小 8(可能是自引用或前向引用)
return 8
def _translate_renum_def(self, trans: HT.Translator*,
cd: ast.ClassDef*) -> int:
"""翻译 REnum 类定义,返回 0"""
if cd is None or cd.name is None or trans is None: return 0
pool: memhub.MemBuddy* = trans.Pool
class_name: str = cd.name
# 命名空间隔离:标记为当前文件可见
self.Gen.StructGen.add_visible_struct(pool, class_name)
# 检查是否已注册(用 SHA1 区分跨模块同名类)
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
if existing is not None:
# existing 只保证 struct entry 在,不保证 REnum 语义(变体表)在:struct entry
# 由 register_struct 写 StructTable,跨 Phase 存活(perm_pool);而变体表是 gen
# 实例字段(InitClassGen 每个 Generator 重置)。无条件早退会使
# _register_renum_variants 永不再执行 ⇒ 变体表缺该类 ⇒ _is_renum_class_name
# 恒 0 ⇒ match 走 _handle_simple_match(无变体绑定)⇒ case 绑定名未定义。
if self._is_renum_class_name(class_name) != 0:
if existing.Ty is not None:
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
return 0
# 变体表缺失:中和旧 entry(对齐 ClassGenDef needs_rereg 先例),使
# find_struct_by_module 不再命中(按 Name 精确匹配),走下方完整注册路径
# 以同时修正 struct 布局 + 变体表。
if existing.Name is not None:
existing.Name[0] = '\0'
existing.Ty = None
existing.FieldCount = 0
children: list[ast.AST*]* = cd.children
if children is None:
# [D32 fail-fast] 此前只 warning + return 0:变体表**静默不注册** →
# _is_renum_class_name 恒 0、变体构造拿不到 tag(__types.vp L703
# `LLVMType.Metadata()` 被当外部函数根因)。禁止静默跳过。
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类 '{class_name}' 缺少类体(children 为 None),无法注册变体表", "TypeError")
return 0
cn: sizet = len(children)
# 变体最多 32 个,每个变体最多 16 个字段
# variant_field_sizes[i][j] = 变体 i 的第 j 个字段大小
variant_field_sizes: sizet* = pool.alloc(8 * 64 * 16)
if variant_field_sizes is None:
return 0
string.memset(variant_field_sizes, 0, 8 * 64 * 16)
variant_count: int = 0
max_field_count: int = 0 # 所有变体中最大字段数
for ci in range(cn):
stmt: ast.AST* = children.get(ci)
if stmt is None:
continue
sk: int = stmt.kind()
if sk == ast.ASTKind.ClassDef:
# 嵌套变体类
variant_cd: ast.ClassDef* = ast.ClassDef*(stmt)
if variant_cd is None or variant_cd.children is None:
variant_count += 1
continue
variant_children: list[ast.AST*]* = variant_cd.children
vcn: sizet = len(variant_children)
field_idx: int = 0
for vi in range(vcn):
vstmt: ast.AST* = variant_children.get(vi)
if vstmt is None:
continue
vk: int = vstmt.kind()
if vk != ast.ASTKind.AnnAssign:
continue
vaa: ast.AnnAssign* = ast.AnnAssign*(vstmt)
if vaa is None or vaa.target is None or vaa.annotation is None:
continue
if vaa.target.kind() != ast.ASTKind.Name:
continue
# 提取字段名
vnm: ast.Name* = ast.Name*(vaa.target)
# 计算字段大小
fsize: int = self._get_annotation_field_size(pool, vaa.annotation)
if variant_count < 32 and field_idx < 16:
# variant_field_sizes[variant_count][field_idx] = fsize
offset: sizet = variant_count * 16 + field_idx
variant_field_sizes[offset] = sizet(fsize)
# 直接注册变体字段名别名(避免 CSizeT→str 转换问题)
# 同时解析成员实际类型(对齐 TPC class_members,供 match
# 绑定 bitcast 槽位地址用)。自引用注解(如
# LLVMType|t.CPtr 引用自身类)此时解析失败返回 None →
# 不存类型,绑定回退槽位类型。variant_cd.name 在 1a reset
# 后悬空,注册内部会 strcpy 到 perm_pool。
if vnm is not None and vnm.id is not None:
mem_ty_l: llvmlite.LLVMType* = None
if trans is not None:
mem_ty_l = self.Gen.TypeGenResolve.resolve_annotation_type(pool, vaa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
self._register_renum_field_alias(pool, class_name, vnm.id, field_idx + 1, mem_ty_l, variant_cd.name)
field_idx += 1
if field_idx > max_field_count:
max_field_count = field_idx
variant_count += 1
elif sk == ast.ASTKind.Assign:
# Assign 形式的**无载荷变体**(如 `Empty = 1` / `None_ = 0`):与 TPC
# HandlesClassDef._EmitREnumLlvm 同口径——它同样是变体(占一个变体序号),
# 只是无字段。不认则 variant_count 与变体表都漏掉该变体 ⇒ match 的
# `case Option.Empty():` 查表失配 tag=-1 → 硬校验 fail-fast。
# tag 值由 _register_renum_variants 按同一口径分配(显式值优先)。
ag_v: ast.Assign* = ast.Assign*(stmt)
if ag_v is None or ag_v.targets is None:
continue
tgts_v: list[ast.AST*]* = ag_v.targets
if len(tgts_v) == 0:
continue
t0_v: ast.AST* = tgts_v.get(0)
if t0_v is None or t0_v.kind() != ast.ASTKind.Name:
continue
tgt_v: ast.Name* = ast.Name*(t0_v)
if tgt_v.id is None:
continue
variant_count += 1
if variant_count == 0:
# [D32 fail-fast] 同上:变体数为 0 时此前静默 return → 变体表不注册。
# 对 `class X(t.REnum)` 而言变体数必 > 0,为 0 说明 AST 变体类丢失。
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类 '{class_name}' 的变体数为 0(嵌套变体类丢失),无法注册变体表", "TypeError")
return 0
# 计算每个位置的最大字段大小
# 位置 0 = __tag (i32, 4 字节)
# 位置 1+ = 变体字段
total_positions: int = max_field_count + 1 # +1 for tag
if total_positions < 2:
total_positions = 2 # 至少 {i32, i32}
position_max_sizes: sizet* = pool.alloc(8 * total_positions)
if position_max_sizes is None:
return 0
string.memset(position_max_sizes, 0, 8 * total_positions)
# 位置 0 = tag = 4 字节
position_max_sizes[0] = sizet(4)
# 位置 1+ = 每个位置取所有变体的最大字段大小
for pos in range(1, total_positions):
pos_max: int = 0
for vi in range(variant_count):
if vi >= 64:
break # variant_field_sizes 64 类槽上限,防读越界
field_pos: int = pos - 1 # 变体字段从位置 0 开始
if field_pos >= 16:
continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过
offset2: sizet = vi * 16 + field_pos
fsize_val: sizet = variant_field_sizes[offset2]
if fsize_val > pos_max:
pos_max = fsize_val
position_max_sizes[pos] = sizet(pos_max)
# 构建 ParamNode 链表
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
first_node: llvmlite.ParamNode* = None
tail_node: llvmlite.ParamNode* = None
for pos in range(total_positions):
psize: int = position_max_sizes[pos]
field_ty: llvmlite.LLVMType* = i32_ty
if psize > 4:
field_ty = i64_ty
pnode: llvmlite.ParamNode* = llvmlite.new_param_node(pool, field_ty)
if pnode is None:
continue
tail_node = llvmlite.param_list_append(first_node, tail_node, pnode)
if first_node is None:
first_node = tail_node
if first_node is None:
VLogger.error(f"failed to build field list for {class_name}", "RENUM")
return 0
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
renum_type_name: str = class_name
if trans.ModuleSha1 is not None:
renum_name_buf: str = pool.alloc(64)
if renum_name_buf is not None:
viperlib.snprintf(renum_name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
renum_type_name = renum_name_buf
renum_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, first_node, total_positions, renum_type_name)
if renum_ty is None:
VLogger.error(f"failed to create type for {class_name}", "RENUM")
return 0
# Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活,
# 与 entry.Ty 保持同一指针,find_struct_by_type 匹配不失效)
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:同 union 的悬空根因。
if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0:
renum_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, renum_ty)
if renum_copy is not None:
renum_ty = renum_copy
# 注册命名结构体到模块
llvmlite.module_add_named_type(trans.Module, pool, renum_ty)
# 注册到 HandlesStruct
entry: GenTypes.StructEntry* = self.Gen.StructGen.register_struct(pool, class_name, renum_ty, trans.ModuleSha1)
if entry is None:
VLogger.error(f"failed to register {class_name}", "RENUM")
return 0
# 添加 __tag 字段(位置 0,i32)
self.Gen.StructGen.add_field(pool, entry, "__tag", i32_ty, None, None)
# 添加 payload 字段(位置 1+,i32 或 i64)
for pos in range(1, total_positions):
psize2: int = position_max_sizes[pos]
payload_ty: llvmlite.LLVMType* = i32_ty
if psize2 > 4:
payload_ty = i64_ty
field_name_buf: str = pool.alloc(16)
if field_name_buf is not None:
viperlib.snprintf(field_name_buf, 16, "_p%d", pos)
self.Gen.StructGen.add_field(pool, entry, field_name_buf, payload_ty, None, None)
# 注册变体名到全局变体表(供 translate_call 检测 REnum 变体构造)
self._register_renum_variants(pool, class_name, cd, variant_count)
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)。
# 注意:遍历发生在 register_struct 之前,注解引用本类自身(如
# LLVMType.Ptr.Pointee: rawptr[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*,
pool: memhub.MemBuddy*,
class_name: str,
cd: ast.ClassDef*):
"""REnum 注册完成后补解析变体字段类型(仅回填类型槽为 0 的别名记录)
第一遍变体字段遍历发生在 register_struct 之前:字段注解引用本 REnum 类
自身(如 LLVMType.Ptr.Pointee: rawptr[LLVMType]、Array.ElemTy:
rawptr[LLVMType]、Func.Ret: rawptr[LLVMType])时,find_struct 查不到
正在注册的类 → resolve_annotation_type 返回 None → _register_renum_field_alias
类型槽(RenumAliasTy)落 0。match 绑定时 _lookup_renum_member_ty 查不到
成员类型 → 绑定变量按 payload 槽位(i64)读取,把指针字段读成整数 →
递归传参/赋值给 rawptr[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*]* = cd.children
if children is None:
return
cn: sizet = len(children)
for ci in range(cn):
stmt: ast.AST* = children.get(ci)
if stmt is None or stmt.kind() != ast.ASTKind.ClassDef:
continue
variant_cd: ast.ClassDef* = ast.ClassDef*(stmt)
if variant_cd is None or variant_cd.name is None \
or variant_cd.children is None:
continue
vchildren: list[ast.AST*]* = variant_cd.children
vcn: sizet = len(vchildren)
field_idx: int = 0
for vi in range(vcn):
vstmt: ast.AST* = vchildren.get(vi)
if vstmt is None:
continue
if vstmt.kind() != ast.ASTKind.AnnAssign:
continue
vaa: ast.AnnAssign* = ast.AnnAssign*(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* = ast.Name*(vaa.target)
if vnm.id is None:
# 与第一遍同规则:有效 AnnAssign 仍占用 payload 槽位
field_idx += 1
continue
mem_ty_l: llvmlite.LLVMType* = 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*,
class_name: str,
cd: ast.ClassDef*,
variant_count: int):
"""注册 REnum 类的变体名和 tag 值到全局变体表"""
if pool is None or class_name is None or cd is None: return
if variant_count == 0: return
children: list[ast.AST*]* = cd.children
if children is None: return
# 懒初始化表(首次注册时分配)
# 注意: 必须用 stdlib 分配——这些表在 1b 阶段(mark1 之后)首次分配,
# 若用 pool 会被 reset_to(mark1) 回收导致悬空(LLVMType 的 match 在
# parser.vp 等后续文件翻译时访问已回收的表 → 崩溃)。
if self.RenumClassNames is None:
self.RenumClassNames = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX)
self.RenumClassVariantCounts = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX)
self.RenumVariantNames = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
self.RenumVariantTags = CompilerFactory.factory.PermPool.alloc(8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
if (self.RenumClassNames is None or self.RenumClassVariantCounts is None
or self.RenumVariantNames is None or self.RenumVariantTags is None):
# A None table means the perm-pool request failed (size 0 or pool
# exhausted). Returning here left the table empty while the caller
# still reported "registered", so match dispatch silently lost every
# REnum case.
self.RenumClassNames = None
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 变体表分配失败(class='{class_name}'):PermPool 返回 NULL,变体表不可用", "InternalCompilerError")
return
string.memset(self.RenumClassNames, 0, 8 * RENUM_CLASS_MAX)
string.memset(self.RenumClassVariantCounts, 0, 8 * RENUM_CLASS_MAX)
string.memset(self.RenumVariantNames, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
self.RenumClassCount = 0
# [D30 根治] 首次分配后把指针登记到编译期单例 factory(与 struct entry
# 同寿命);后续新建的 Generator 由 InitClassGen 从此处恢复,不再清零。
CompilerFactory.factory.RenumClassNames = self.RenumClassNames
CompilerFactory.factory.RenumClassVariantCounts = self.RenumClassVariantCounts
CompilerFactory.factory.RenumVariantNames = self.RenumVariantNames
CompilerFactory.factory.RenumVariantTags = self.RenumVariantTags
CompilerFactory.factory.RenumClassCount = self.RenumClassCount
#rcv_chk: uint64 = uint64(self.RenumClassVariantCounts)
#if rcv_chk == 0 or rcv_chk < 4096:
# VLogger.error(f"[RENUM-FAIL] RCV={rcv_chk} 异常(lazy init 后应为 perm_pool 地址),RenumClassCount={self.RenumClassCount} class={class_name}", "RENUM")
# stdlib.exit(1)
# 检查是否已注册(避免重复注册)
for i in range(self.RenumClassCount):
existing: str = str(self.RenumClassNames[i])
if existing is not None and string.strcmp(existing, class_name) == 0:
return
# 表已满
if self.RenumClassCount >= RENUM_CLASS_MAX:
# Silently dropping the class made its later `match` lose every case; a
# real limit breach must be reported instead.
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类数超过上限 {RENUM_CLASS_MAX}:无法注册 class='{class_name}'", "InternalCompilerError")
return
# 注册类名(strcpy 到 perm_pool:1a 每文件 reset 后 AST 裸指针悬空,
# _lookup_renum_variant/_is_renum_class_name 的 strcmp 会读毒化内存)
idx: int = self.RenumClassCount
cn_len_rv: sizet = string.strlen(class_name)
cn_buf_rv: str = CompilerFactory.factory.PermPool.alloc(cn_len_rv + 1)
if cn_buf_rv is None:
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 类名副本分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
return
string.strcpy(cn_buf_rv, class_name)
self.RenumClassNames[idx] = sizet(cn_buf_rv)
self.RenumClassVariantCounts[idx] = variant_count
# 遍历 children,提取变体名与 tag 并注册。变体两种书写形态(对齐 TPC
# HandlesClassDef._EmitREnumLlvm L1294-1335、SymbolExtractor L225-250):
# 1) `class Some: ...` → 带载荷类变体,tag 从 max(显式值)+1 起顺序编号
# 2) `Empty = 1` → 无载荷 Assign 变体,tag = 显式整数值
# 1) 从显式值上界之后起编号是必须的:Test\EdgeCaseTest\App\main.vp:42-44
# `class Some: val / None_ = 0` 若按声明序给 Some 编 0 就与 None_ 撞号
# (match 两臂同 tag ⇒ 后写臂恒不可达)。
cn: sizet = len(children)
# 第一遍:扫出 Assign 变体的显式整数值上界(无显式值时保持 -1)
max_explicit: int = -1
for ci in range(cn):
stmt_p: ast.AST* = children.get(ci)
if stmt_p is None or stmt_p.kind() != ast.ASTKind.Assign:
continue
ag_p: ast.Assign* = ast.Assign*(stmt_p)
if ag_p is None or ag_p.targets is None or ag_p.value is None:
continue
tgts_p: list[ast.AST*]* = ag_p.targets
if len(tgts_p) == 0:
continue
t0_p: ast.AST* = tgts_p.get(0)
if t0_p is None or t0_p.kind() != ast.ASTKind.Name:
continue
if ag_p.value.kind() != ast.ASTKind.Constant:
continue
ev_v: int = int(self._extract_int_value(ag_p.value))
if ev_v > max_explicit:
max_explicit = ev_v
# 第二遍:按声明序写表。slot = 表中连续槽位序号(0..variant_count-1,
# 查找侧 _lookup_renum_variant_in_class 按槽位顺序遍历),槽内存该变体的
# tag 值——两者不再恒等,故不能再共用一个计数器(原实现 tag 兼作槽号)。
slot: int = 0
next_class_tag: int = max_explicit + 1
variant_index: int = 0
for ci in range(cn):
if slot >= variant_count:
break
if slot >= RENUM_VARIANT_PER_CLASS:
# 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错
VLogger.error(f"REnum 变体数超过上限 {RENUM_VARIANT_PER_CLASS}: {class_name}", "RENUM")
break
stmt: ast.AST* = children.get(ci)
if stmt is None:
continue
sk_rv: int = stmt.kind()
vname_ptr: sizet = 0
tag_val: int = 0
if sk_rv == ast.ASTKind.ClassDef:
vcd: ast.ClassDef* = ast.ClassDef*(stmt)
if vcd is None or vcd.name is None:
continue
vname_ptr = sizet(vcd.name)
tag_val = next_class_tag
next_class_tag += 1
elif sk_rv == ast.ASTKind.Assign:
# Assign 形式无载荷变体(与 _translate_renum_def 首遍同过滤口径)
ag_rv: ast.Assign* = ast.Assign*(stmt)
if ag_rv is None or ag_rv.targets is None:
continue
tgts_rv: list[ast.AST*]* = ag_rv.targets
if len(tgts_rv) == 0:
continue
t0_rv: ast.AST* = tgts_rv.get(0)
if t0_rv is None or t0_rv.kind() != ast.ASTKind.Name:
continue
tgt_rv: ast.Name* = ast.Name*(t0_rv)
if tgt_rv.id is None:
continue
vname_ptr = sizet(tgt_rv.id)
if ag_rv.value is not None and ag_rv.value.kind() == ast.ASTKind.Constant:
tag_val = int(self._extract_int_value(ag_rv.value))
else:
# 无显式值:用独立计数器(与类变体计数器分离,对齐 TPC
# `variant_index`),避免与 next_class_tag 交叉撞号
tag_val = variant_index
variant_index += 1
else:
continue
name_offset: sizet = idx * RENUM_VARIANT_PER_CLASS + slot
# 变体名同样 strcpy 到 perm_pool(1a 每文件 reset 后 AST 名悬空)
vname_src: str = str(vname_ptr)
vn_len_rv: sizet = string.strlen(vname_src)
vn_buf_rv: str = CompilerFactory.factory.PermPool.alloc(vn_len_rv + 1)
if vn_buf_rv is None:
# Breaking here registered a partial variant table: the class would
# keep some variants and silently lose every later one.
self.Gen.TypeGenErr.fatal_error(cd, f"REnum 变体名副本分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
break
string.strcpy(vn_buf_rv, vname_src)
self.RenumVariantNames[name_offset] = sizet(vn_buf_rv)
self.RenumVariantTags[name_offset] = tag_val
slot += 1
self.RenumClassCount = idx + 1
# [D30 根治] 回写计数到编译期单例(新建 Generator 靠它恢复;不回写会导致
# 新 Generator 只看到旧计数 → 后续注册的变体不可见)
CompilerFactory.factory.RenumClassCount = self.RenumClassCount
def _lookup_renum_variant(self, variant_name: str) -> str:
"""查找变体名所属的 REnum 类名
返回: class_name (str),或 None
"""
if variant_name is None or self.RenumClassNames is None:
return None
for i in range(self.RenumClassCount):
vcount: int = self.RenumClassVariantCounts[i]
for j in range(vcount):
name_offset: sizet = i * RENUM_VARIANT_PER_CLASS + j
vname: str = str(self.RenumVariantNames[name_offset])
if vname is not None and string.strcmp(vname, variant_name) == 0:
cls_nm: str = str(self.RenumClassNames[i])
return cls_nm
return None
def RenumTableDump(self) -> str:
"""诊断用:变体表摘要(类数 / 首类名 / 该变体数 / 变体首项)
用于区分「类根本没注册」与「类在但变体名没注册」两类失败。
"""
buf: str = CompilerFactory.factory.PermPool.alloc(256)
if buf is None:
return "-"
buf[0] = '\0'
cls_first: str = "-"
v_first: str = "-"
n_first_v: int = 0
if self.RenumClassNames is not None and self.RenumClassCount > 0:
cls_first = str(self.RenumClassNames[0])
if self.RenumVariantNames is not None \
and self.RenumClassVariantCounts is not None:
n_first_v = self.RenumClassVariantCounts[0]
if n_first_v > 0:
v_first = str(self.RenumVariantNames[0])
viperlib.snprintf(buf, 256, "count=%d first=%s vcount=%d vfirst=%s",
self.RenumClassCount, cls_first, n_first_v, v_first)
return buf
def _is_renum_by_entry(self, class_name: str) -> int:
"""不依赖变体表的 REnum 判定:struct 定义里带 `__tag` 字段即为 REnum
`_translate_renum_def` 必定 `add_field(entry, "__tag", i32)`,故 struct
定义本身即持久凭证(perm_pool)。用途:变体表因**任何**原因缺失时,
match 分派仍能走带变体绑定的 `_handle_renum_match` 路径,避免退化为
`_handle_simple_match`(不绑定)→ case 绑定名 NameError
(includes/llvmlite/__types.vp L407 `bits` 根因)。
"""
if class_name is None:
return 0
st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(class_name)
if st is None:
return 0
if self.Gen.StructGen.lookup_field(st, "__tag") is None:
return 0
return 1
def _is_renum_class_name(self, class_name: str) -> int:
"""检查名称是否是已注册的 REnum 类名,返回 1=是 / 0=否"""
if class_name is None or self.RenumClassNames is None:
return 0
for i in range(self.RenumClassCount):
existing: str = str(self.RenumClassNames[i])
if existing is not None and string.strcmp(existing, class_name) == 0:
return 1
return 0
def _lookup_renum_variant_in_class(self, class_name: str, variant_name: str) -> int:
"""在指定 REnum 类中查找变体,返回 tag 值或 -1"""
if class_name is None or variant_name is None or self.RenumClassNames is None:
return -1
for i in range(self.RenumClassCount):
existing: str = str(self.RenumClassNames[i])
if existing is None or string.strcmp(existing, class_name) != 0:
continue
vcount: int = self.RenumClassVariantCounts[i]
for j in range(vcount):
name_offset: sizet = i * RENUM_VARIANT_PER_CLASS + j
vname: str = str(self.RenumVariantNames[name_offset])
if vname is not None and string.strcmp(vname, variant_name) == 0:
return self.RenumVariantTags[name_offset]
return -1
return -1
def _register_renum_field_alias(self, pool: memhub.MemBuddy*,
class_name: str,
field_name: str,
payload_idx: int,
field_ty: llvmlite.LLVMType* = None,
variant_name: str = None):
"""注册 REnum 变体字段名别名到全局表
field_ty: 变体成员的实际 LLVM 类型(可选;自引用类型如
LLVMType|t.CPtr 在注册期解析失败时为 None,match 绑定回退槽位类型)。
variant_name: 所属变体名(可选;match 绑定按 (class, 变体, 位置) 定位成员)
"""
if pool is None or class_name is None or field_name is None:
return
if payload_idx < 1:
return
# 懒初始化表(perm_pool:1a 每文件 reset 后表本体不被回收)
if self.RenumAliasClass is None:
alias_pool_rfa: memhub.MemBuddy* = CompilerFactory.factory.PermPool
self.RenumAliasClass = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
self.RenumAliasField = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
self.RenumAliasIndex = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
self.RenumAliasTy = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
self.RenumAliasVariant = alias_pool_rfa.alloc(8 * RENUM_ALIAS_MAX)
if (self.RenumAliasClass is None or self.RenumAliasField is None
or self.RenumAliasIndex is None or self.RenumAliasTy is None
or self.RenumAliasVariant is None):
# Same as the variant table: a silent bail left the alias table empty,
# so match bindings later failed with an unrelated NameError.
self.RenumAliasClass = None
self.Gen.TypeGenErr.fatal_error(None, f"REnum 字段别名表分配失败(class='{class_name}'):PermPool 返回 NULL", "InternalCompilerError")
return
string.memset(self.RenumAliasClass, 0, 8 * RENUM_ALIAS_MAX)
string.memset(self.RenumAliasField, 0, 8 * RENUM_ALIAS_MAX)
string.memset(self.RenumAliasIndex, 0, 8 * RENUM_ALIAS_MAX)
string.memset(self.RenumAliasTy, 0, 8 * RENUM_ALIAS_MAX)
string.memset(self.RenumAliasVariant, 0, 8 * RENUM_ALIAS_MAX)
self.RenumAliasCount = 0
# [D30 根治] 同上:别名表指针登记到编译期单例,跨 Generator 存活
CompilerFactory.factory.RenumAliasClass = self.RenumAliasClass
CompilerFactory.factory.RenumAliasField = self.RenumAliasField
CompilerFactory.factory.RenumAliasIndex = self.RenumAliasIndex
CompilerFactory.factory.RenumAliasTy = self.RenumAliasTy
CompilerFactory.factory.RenumAliasVariant = self.RenumAliasVariant
CompilerFactory.factory.RenumAliasCount = self.RenumAliasCount
if self.RenumAliasCount >= RENUM_ALIAS_MAX:
# Dropping the record silently made the variant field bind to a wrong-typed
# slot (or fail with NameError) instead of reporting the limit breach.
self.Gen.TypeGenErr.fatal_error(None, f"REnum 字段别名数超过上限 {RENUM_ALIAS_MAX}:无法注册 {class_name}.{field_name}", "InternalCompilerError")
return
# 去重检查(去指针化):class 槽位存 perm_pool 字符串拷贝,用 strcmp 内容比较——
# 不再依赖指针值统一(注册用 AST 指针、查找用 entry.Name 池拷贝,指针恒不等)。
for i in range(self.RenumAliasCount):
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
fld_existing_ptr: str = rawptr(self.RenumAliasField[i])
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* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, field_ty)
if ty_copy_rf2 is not None:
self.RenumAliasTy[i] = sizet(ty_copy_rf2)
return
idx: int = self.RenumAliasCount
# class_name 同样 strcpy 到 perm_pool(去指针化:查找方任何来源的
# class_name 字符串都可用 strcmp 命中,无需 _update_renum_alias_class_ptr)
cls_len_rfa: sizet = string.strlen(class_name)
cls_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(cls_len_rfa + 1)
if cls_buf_rfa is None:
return
string.strcpy(cls_buf_rfa, class_name)
self.RenumAliasClass[idx] = sizet(cls_buf_rfa)
# field_name 存 AST 裸指针,1a 每文件 reset 后悬空;_lookup_renum_field_alias
# 用 strcmp 内容比较 → strcpy 到 perm_pool 不影响查找。
fn_len_rfa: sizet = string.strlen(field_name)
fn_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(fn_len_rfa + 1)
if fn_buf_rfa is None:
return
string.strcpy(fn_buf_rfa, field_name)
self.RenumAliasField[idx] = sizet(fn_buf_rfa)
self.RenumAliasIndex[idx] = sizet(payload_idx)
# 成员类型深拷贝到 perm_pool(1a 每文件 reset 后 pool 类型悬空;
# 未解析成功(自引用等)存 0,绑定回退槽位类型)
self.RenumAliasTy[idx] = 0
if field_ty is not None:
ty_copy_rfa: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, field_ty)
if ty_copy_rfa is not None:
self.RenumAliasTy[idx] = sizet(ty_copy_rfa)
# 变体名同样 strcpy 到 perm_pool(1a reset 后 variant_cd.name 悬空)
self.RenumAliasVariant[idx] = 0
if variant_name is not None:
vn_len_rfa: sizet = string.strlen(variant_name)
vn_buf_rfa: str = CompilerFactory.factory.PermPool.alloc(vn_len_rfa + 1)
if vn_buf_rfa is not None:
string.strcpy(vn_buf_rfa, variant_name)
self.RenumAliasVariant[idx] = sizet(vn_buf_rfa)
self.RenumAliasCount = idx + 1
# [D30 根治] 回写计数到编译期单例(新建 Generator 靠它恢复)
CompilerFactory.factory.RenumAliasCount = self.RenumAliasCount
def _lookup_renum_field_alias(self, class_name: str, field_name: str) -> int:
"""查找 REnum 变体字段名的 payload 索引,返回索引或 -1
class_name/field_name 均用 strcmp 内容比较(去指针化:槽位存 perm_pool
字符串拷贝,任何来源的 class_name 字符串都可命中)
"""
if class_name is None or field_name is None or self.RenumAliasClass is None:
return -1
for i in range(self.RenumAliasCount):
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
# field_name 用 strcmp 内容比较(指针不同但内容相同)
fld_existing_ptr: str = rawptr(self.RenumAliasField[i])
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
return self.RenumAliasIndex[i]
return -1
def _lookup_renum_field_alias_ty(self, class_name: str,
field_name: str) -> llvmlite.LLVMType*:
"""查找 REnum 变体成员的实际 LLVM 类型,返回类型或 None
与 _lookup_renum_field_alias 同表同键(class/field 均 strcmp 内容比较)。
注册期未解析成功(自引用类型等)槽位为 0 → 返回 None,绑定回退槽位类型。
"""
if class_name is None or field_name is None or self.RenumAliasTy is None:
return None
for i in range(self.RenumAliasCount):
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
if cls_existing_ptr is not None and string.strcmp(cls_existing_ptr, class_name) == 0:
fld_existing_ptr: str = rawptr(self.RenumAliasField[i])
if fld_existing_ptr is not None and string.strcmp(fld_existing_ptr, field_name) == 0:
if self.RenumAliasTy[i] == 0:
return None
return (llvmlite.LLVMType*)(self.RenumAliasTy[i])
return None
def _lookup_renum_member_ty(self, class_name: str,
variant_name: str,
payload_idx: int) -> llvmlite.LLVMType*:
"""按 (class, 变体名, payload 位置) 查找变体成员的实际 LLVM 类型
match 绑定用:同一 payload 位置跨变体类型不同(Int.Bits=i32 vs
Struct.Fields=Ptr),必须带变体名定位。class/变体均 strcmp 内容比较。
返回类型或 None(未注册/未解析成功 → 绑定回退槽位类型)。
"""
if class_name is None or variant_name is None or self.RenumAliasVariant is None:
return None
if payload_idx < 1:
return None
for i in range(self.RenumAliasCount):
cls_existing_ptr: str = rawptr(self.RenumAliasClass[i])
if cls_existing_ptr is None or string.strcmp(cls_existing_ptr, class_name) != 0:
continue
if self.RenumAliasVariant[i] == 0:
continue
vnt_ptr: str = rawptr(self.RenumAliasVariant[i])
if vnt_ptr is None or string.strcmp(vnt_ptr, variant_name) != 0:
continue
if self.RenumAliasIndex[i] != payload_idx:
continue
if self.RenumAliasTy[i] == 0:
return None
return (llvmlite.LLVMType*)(self.RenumAliasTy[i])
return None