fix(tpv): 修正 REnum 表按名查找与 match 分派,恢复 str() 指针强转
str() 对整数(sizet/i64)走 snprintf 十进制格式化(Python 语义),不是 i8* 强转;用它读 sizet|t.CPtr 联合表元素再 strcmp 永不相等 => _is_renum_class_name 恒 0、变体名查不到(__types.vp:407 bits / :159 Void 根因)。IR 实证 output/a8891afb66d3eda4.text.ll L5551-5558。 - ClassGenEnum: RenumClassNames/RenumVariantNames 读侧统一改 (str)(t.CVoid(x, t.CPtr));新增 _is_renum_by_entry 与 RenumTableDump;REnum 注册静默早退改 fail-fast - MatchGenMixin/CallGenMixin: match 分派 2a/2b 与变体构造入口并上 by_entry 判据 - TypeGenResolve: 泛型下标 Phase B 解析不出特化时 fail-fast - CallGenProp: 泛型特化名末段按括号外点切分 - CompilerFactory/ClassGenBase: REnum 注册表改挂编译期单例 - ClassGenDef: CEnum/REnum 分派歧义 fail-fast
This commit is contained in:
1 parent
e0e024ee93
commit
eef84657a1
10 files changed
+318
-30
No files matched your search
@@ -2095,6 +2095,36 @@ def _vpi_class_has_packed(decorator_list: list[ast.AST | t.CPtr] | t.CPtr) -> in
|
||||
return 0
|
||||
|
||||
|
||||
def _vpi_class_is_renum(class_cd: ast.ClassDef | t.CPtr) -> int:
|
||||
"""检查 vpi ClassDef 是否为 REnum(基类含 t.REnum),返回 1=是 / 0=否
|
||||
|
||||
vpi 文本保留原始基类(`class LLVMType(t.REnum):`),故可据此识别。
|
||||
REnum 布局 {i32 __tag, <max_variant_payload>} 由 ClassGenEnum.
|
||||
_translate_renum_def 在正式翻译时按变体计算;vpi 侧按普通 struct 注册
|
||||
会得到错误布局(变体字段都在嵌套类里,直接 AnnAssign 扫描得到 0 字段)。
|
||||
"""
|
||||
if class_cd is None or class_cd.bases is None:
|
||||
return 0
|
||||
bases: list[ast.AST | t.CPtr] | t.CPtr = class_cd.bases
|
||||
bn: sizet = len(bases)
|
||||
for bi in range(bn):
|
||||
base_node: ast.AST | t.CPtr = bases.get(bi)
|
||||
if base_node is None:
|
||||
continue
|
||||
bk: int = base_node.kind()
|
||||
# Attribute(t.REnum) 形式
|
||||
if bk == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node)
|
||||
if at.attr is not None and string.strcmp(at.attr, "REnum") == 0:
|
||||
return 1
|
||||
# Name(REnum) 形式(from t import REnum)
|
||||
elif bk == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "REnum") == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _inject_class_struct_declare - 从 vpi ClassDef 注册类为 struct 类型
|
||||
#
|
||||
@@ -2129,6 +2159,13 @@ def _inject_class_struct_declare(pool: rowptr[memhub.MemBuddy],
|
||||
if existing_c is not None and existing_c.Ty is not None:
|
||||
GenApi.add_visible_struct(pool, cls_name)
|
||||
return 1
|
||||
# REnum 类(class X(t.REnum))跳过:布局 {i32 __tag, <payload>} 由
|
||||
# ClassGenEnum._translate_renum_def 按变体计算;vpi 侧按普通 struct 注册
|
||||
# 会得到错误布局(变体字段都在嵌套类里,直接 AnnAssign 扫描得 0 字段)。
|
||||
# 留给源模块正式翻译注册。LLVMType 本就因 field_count==0 早退,此守卫把
|
||||
# 该行为显式化,避免将来 REnum 带直接字段时被误注册为普通 struct。
|
||||
if _vpi_class_is_renum(class_cd) != 0:
|
||||
return 0
|
||||
# 2. 收集字段类型(AnnAssign 子节点,仿 ClassGenDef.translate_class_def)
|
||||
field_names_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_types_buf: sizet | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
|
||||
@@ -10,6 +10,33 @@ class CompilerFactory:
|
||||
"""编译器结构体工厂(持有主池/永久池等共享对象)"""
|
||||
Pool: rowptr[memhub.MemBuddy] # 主内存池(瞬时数据,mark/reset 回收)
|
||||
PermPool: rowptr[memhub.MemBuddy] # 永久内存池(持久数据,从不 reset)
|
||||
|
||||
# ---- REnum 变体注册表(编译期单例持有,跨 Generator/Phase 存活)----
|
||||
# [D30 根治] 此前这 4 张表是 ClassGenBase 的**实例字段**,被 InitClassGen
|
||||
# 在每个 Generator 构造时清零;而 struct entry 在 perm_pool 跨 Phase 存活。
|
||||
# 两者寿命不对称 ⇒ 新 Generator 建好后表被清空、struct 仍在 ⇒
|
||||
# _translate_renum_def 命中 existing 早退 → 变体表永久缺该类 →
|
||||
# _is_renum_class_name 恒 0 → match 走 _handle_simple_match(无变体绑定)→
|
||||
# case 绑定名 NameError(includes/llvmlite/__types.vp L407 `bits` 根因)。
|
||||
# 表内存本就是 perm_pool 分配(设计上就是持久的),故把**指针与计数**
|
||||
# 一并挂到编译期单例 factory 上,与 struct entry 同寿命。
|
||||
RenumClassNames: sizet | t.CPtr
|
||||
RenumClassVariantCounts: sizet | t.CPtr
|
||||
RenumVariantNames: sizet | t.CPtr
|
||||
RenumVariantTags: sizet | t.CPtr
|
||||
RenumClassCount: int
|
||||
|
||||
# ---- REnum 变体字段别名表(同上,必须同寿命)----
|
||||
# _bind_variant_fields 靠 _lookup_renum_member_ty 查这些表拿到字段真实类型;
|
||||
# 表被清 → 类型槽 0 → 绑定回退 payload 槽位 i64 → 指针字段被当整数读 →
|
||||
# 递归传参/赋值 int→ptr 被拦(llvmlite __types.vp L448 CastError 根因)。
|
||||
RenumAliasClass: sizet | t.CPtr
|
||||
RenumAliasField: sizet | t.CPtr
|
||||
RenumAliasIndex: sizet | t.CPtr
|
||||
RenumAliasTy: sizet | t.CPtr
|
||||
RenumAliasVariant: sizet | t.CPtr
|
||||
RenumAliasCount: int
|
||||
|
||||
def __init__(self, pool: rowptr[memhub.MemBuddy], perm_pool: rowptr[memhub.MemBuddy]):
|
||||
if self is None: return
|
||||
self.Pool = pool
|
||||
|
||||
@@ -1239,7 +1239,9 @@ class AssignGenMixin:
|
||||
# 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。
|
||||
# PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的
|
||||
# get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。
|
||||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
# [D31 fail-fast] 泛型注解退化成裸基类 → 立即终止(暴露退化点)
|
||||
self._fail_on_degenerated_generic_annotation(aa, nm.id, annot, var_ty)
|
||||
else:
|
||||
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
@@ -1341,6 +1343,66 @@ class AssignGenMixin:
|
||||
#
|
||||
# 返回新增的变量数
|
||||
# ============================================================
|
||||
def _fail_on_degenerated_generic_annotation(self,
|
||||
aa: ast.AnnAssign | t.CPtr,
|
||||
var_name: str,
|
||||
annot: ast.AST | t.CPtr,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""fail-fast:泛型注解解析成了「裸泛型基类指针」(丢失类型实参)
|
||||
|
||||
场景:注解是泛型下标 `list[X]` 或 `list[X] | t.CPtr`,但
|
||||
`resolve_annotation_type` 退化成裸基类 `list*`(没有 `[...]`)
|
||||
⇒ 之后该变量的任何泛型方法调用(`.get()`/`.set()`/...)都会按**错误**
|
||||
元素类型特化(实测 `list[int].get` 返回 i32)⇒ `inttoptr` 把 i32 当
|
||||
指针 ⇒ 读垃圾 AST 节点(D21/D25/D31 崩溃族,ASan 现场
|
||||
`MatchGenMixin._handle_simple_match → StmtGenMixin._translate_stmt_impl`)。
|
||||
|
||||
与 D25 既有守卫的区别:那条守卫判「复用到的**旧 alloca** 是裸泛型基类」;
|
||||
本守卫判「**本次注解解析结果本身**就是裸泛型基类」,覆盖「旧 alloca 恰好
|
||||
也是裸类型 → 两边一致 → 既有守卫不触发」的漏网路径。
|
||||
|
||||
返回 0=未退化(继续);退化则 fatal_error 终止(不返回)。
|
||||
"""
|
||||
if aa is None or annot is None or var_ty is None:
|
||||
return 0
|
||||
# 取注解里的泛型 Subscript 一侧:Subscript 本身,或 A | t.CPtr 的 Subscript 分支
|
||||
ann_sub: ast.Subscript | t.CPtr = None
|
||||
if annot.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(annot)
|
||||
elif annot.kind() == ast.ASTKind.BinOp:
|
||||
bop_ff: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
if bop_ff.op == ast.OpKind.BitOr:
|
||||
if bop_ff.left is not None and bop_ff.left.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(bop_ff.left)
|
||||
elif bop_ff.right is not None and bop_ff.right.kind() == ast.ASTKind.Subscript:
|
||||
ann_sub = (ast.Subscript | t.CPtr)(bop_ff.right)
|
||||
if ann_sub is None or ann_sub.value is None \
|
||||
or ann_sub.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
base_nm_ff: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ann_sub.value)
|
||||
if base_nm_ff.id is None:
|
||||
return 0
|
||||
# 仅当该基名确实是泛型模板(list/GSList/...)才判定为退化
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(base_nm_ff.id) is None:
|
||||
return 0
|
||||
if var_ty.Pointee is None:
|
||||
return 0
|
||||
vt_nm_ff: str = llvmlite.get_struct_name(var_ty.Pointee)
|
||||
if vt_nm_ff is None:
|
||||
return 0
|
||||
vt_pf_ff: int = GenApi.sha1_prefix_len(vt_nm_ff)
|
||||
vt_short_ff: str = vt_nm_ff + vt_pf_ff if vt_pf_ff != 0 else vt_nm_ff
|
||||
if string.strchr(vt_short_ff, '[') is not None:
|
||||
return 0 # 带类型实参:未退化
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
aa,
|
||||
f"变量 '{var_name}' 的泛型注解 '{base_nm_ff.id}[...]' 解析成了裸基类 "
|
||||
f"'{vt_nm_ff}*'(丢失类型实参);后续 .get()/.set() 会按错误元素类型"
|
||||
f"特化(如 list[int].get 返回 i32)→ inttoptr 截断指针崩溃。"
|
||||
f"禁止静默继续——请检查该注解在 resolve_annotation_type 中的退化点。",
|
||||
"TypeError")
|
||||
return 0
|
||||
|
||||
def translate_annassign(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 AnnAssign(target=Name, annotation=..., value=expr)"""
|
||||
@@ -1551,6 +1613,8 @@ class AssignGenMixin:
|
||||
# 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca,
|
||||
# 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。
|
||||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||||
# [D31 fail-fast] 泛型注解退化成裸基类 → 立即终止(暴露退化点)
|
||||
self._fail_on_degenerated_generic_annotation(aa, nm.id, annot, var_ty)
|
||||
|
||||
# 普通局部变量
|
||||
# 创建 alloca
|
||||
|
||||
@@ -457,10 +457,24 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if rc_cls_node.id is not None:
|
||||
rc_cls_name: str = rc_cls_node.id
|
||||
# 检查 ClassName 是否是已注册的 REnum 类
|
||||
if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0:
|
||||
# [D32] 并上 _is_renum_by_entry(struct 带 __tag 即判 REnum):
|
||||
# 变体表因任何原因缺失时,入口至少不被表的空状态挡住;
|
||||
# 若 tag 仍查不到则下方 fail-fast 报出表状态(不再落到
|
||||
# "外部函数返回类型未登记 ... Metadata" 这种误导报错)。
|
||||
if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0 \
|
||||
or self.Gen.ClassGenEnum._is_renum_by_entry(rc_cls_name) != 0:
|
||||
# 在该 REnum 类中查找变体名 func_name
|
||||
rc_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(
|
||||
rc_cls_name, func_name)
|
||||
if rc_tag < 0:
|
||||
# [D32 fail-fast] 是 REnum 却查不到变体名 ⇒ 变体表不完整,
|
||||
# 继续走外部函数路径会报无关的 "外部函数返回类型未登记"。
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cl,
|
||||
f"REnum 类 '{rc_cls_name}' 的变体 '{func_name}' 未在变体表中找到"
|
||||
f"({self.Gen.ClassGenEnum.RenumTableDump()});"
|
||||
f"变体表未注册或变体名不匹配",
|
||||
"NameError")
|
||||
if rc_tag >= 0:
|
||||
return self.Gen.CallGenCtor._translate_renum_construct(
|
||||
pool, builder, mod, rc_cls_name, func_name,
|
||||
|
||||
@@ -170,9 +170,26 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
trans.SymTab, obj_nm.id)
|
||||
annot_val: str = self.Gen.VarGen.var_annot_class_name(var_entry)
|
||||
if annot_val is not None:
|
||||
dot_ptr: str = string.strrchr(annot_val, '.')
|
||||
if dot_ptr is not None:
|
||||
return dot_ptr + 1
|
||||
# [D32] 取「模块限定名」末段时只按**括号外**的 '.' 切分。
|
||||
# 此前用 string.strrchr 在整个串上找最后一个 '.':泛型特化名
|
||||
# "list[e94ef9e139461915.AST|t.CPtr]" 的 '.' 落在 '[' 内 ⇒
|
||||
# 返回 "AST|t.CPtr]" 这种垃圾短名 ⇒ 后续按它查表必落空,
|
||||
# 进而可能被兜底成任意特化(.get() 误分派)。
|
||||
n_av: sizet = string.strlen(annot_val)
|
||||
last_dot_av: sizet = n_av
|
||||
depth_av: int = 0
|
||||
ai_av: sizet = 0
|
||||
while ai_av < n_av:
|
||||
ch_av: int = annot_val[ai_av]
|
||||
if ch_av == '[':
|
||||
depth_av += 1
|
||||
elif ch_av == ']':
|
||||
depth_av -= 1
|
||||
elif ch_av == '.' and depth_av == 0:
|
||||
last_dot_av = ai_av
|
||||
ai_av += 1
|
||||
if last_dot_av < n_av:
|
||||
return annot_val + last_dot_av + 1
|
||||
return annot_val
|
||||
return None
|
||||
# ============================================================
|
||||
|
||||
@@ -1226,15 +1226,18 @@ class ClassGenBase:
|
||||
self.MethodMetaKeys = None
|
||||
self.MethodMetaFlags = None
|
||||
self.MethodMetaCount = 0
|
||||
self.RenumClassNames = None
|
||||
self.RenumClassVariantCounts = None
|
||||
self.RenumVariantNames = None
|
||||
self.RenumVariantTags = None
|
||||
self.RenumClassCount = 0
|
||||
self.RenumAliasClass = None
|
||||
self.RenumAliasField = None
|
||||
self.RenumAliasIndex = None
|
||||
self.RenumAliasCount = 0
|
||||
# [D30 根治] REnum 变体注册表挂在编译期单例 factory 上(perm_pool 后端),
|
||||
# 与 struct entry 同寿命:此处**恢复**而非清零。清零会让新 Generator
|
||||
# 丢掉前序已注册的 REnum 变体(`bits` NameError 根因),见 CompilerFactory。
|
||||
self.RenumClassNames = CompilerFactory.factory.RenumClassNames
|
||||
self.RenumClassVariantCounts = CompilerFactory.factory.RenumClassVariantCounts
|
||||
self.RenumVariantNames = CompilerFactory.factory.RenumVariantNames
|
||||
self.RenumVariantTags = CompilerFactory.factory.RenumVariantTags
|
||||
self.RenumClassCount = CompilerFactory.factory.RenumClassCount
|
||||
self.RenumAliasClass = CompilerFactory.factory.RenumAliasClass
|
||||
self.RenumAliasField = CompilerFactory.factory.RenumAliasField
|
||||
self.RenumAliasIndex = CompilerFactory.factory.RenumAliasIndex
|
||||
self.RenumAliasCount = CompilerFactory.factory.RenumAliasCount
|
||||
self.SpecKeys = None
|
||||
self.SpecNames = None
|
||||
self.SpecCount = 0
|
||||
@@ -1247,8 +1250,8 @@ class ClassGenBase:
|
||||
self.VtMethodNames = None
|
||||
self.VtParentSha1s = None
|
||||
self.VtMethodCount = 0
|
||||
self.RenumAliasTy = None
|
||||
self.RenumAliasVariant = None
|
||||
self.RenumAliasTy = CompilerFactory.factory.RenumAliasTy
|
||||
self.RenumAliasVariant = CompilerFactory.factory.RenumAliasVariant
|
||||
self.ClassMetaKinds = None
|
||||
self.ClassMetaClss = None
|
||||
self.ClassMetaFields = None
|
||||
|
||||
@@ -51,7 +51,18 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
self.Gen.StructGen.add_visible_struct(pool, class_name)
|
||||
|
||||
# 枚举类:交给 HandlesEnum 处理
|
||||
# [D32 fail-fast] 分派歧义检测:REnum 优先于 CEnum/CUnion。若某类同时被判
|
||||
# 为枚举,说明它被 `_is_enum_class` 抢先截胡 → 走 _translate_enum_def ⇒
|
||||
# **变体表永不注册** ⇒ `_is_renum_class_name` 恒 0、变体构造拿不到 tag
|
||||
# (includes/llvmlite/__types.vp L703 `LLVMType.Metadata()` 被当外部函数
|
||||
# 根因)。两者语义互斥,禁止静默按枚举处理。
|
||||
if self.Gen.ClassGenBase._is_enum_class(cd, trans) == 1:
|
||||
if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cd,
|
||||
f"类 '{class_name}' 同时被判定为 CEnum 与 REnum(分派歧义),"
|
||||
f"REnum 变体表将无法注册",
|
||||
"TypeError")
|
||||
return self.Gen.ClassGenEnum._translate_enum_def(trans, cd)
|
||||
|
||||
# 联合体类:交给联合体处理
|
||||
|
||||
@@ -633,13 +633,34 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module(
|
||||
class_name, trans.ModuleSha1)
|
||||
if existing is not None:
|
||||
if existing.Ty is not None:
|
||||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||||
return 0
|
||||
# [D30 契约修复] existing 只保证 struct entry 在,不保证 REnum 语义(变体表)在。
|
||||
# struct entry 由 register_struct 写 StructTable,跨 Phase 存活(perm_pool);
|
||||
# 而变体表是 gen 实例字段(InitClassGen 每个 Generator 重置)。
|
||||
# 若此处无条件早退,下方 L819 的 _register_renum_variants 永不再执行 ⇒
|
||||
# 变体表缺该类 ⇒ _is_renum_class_name 恒 0 ⇒ _translate_match_impl 走
|
||||
# _handle_simple_match(无变体绑定)⇒ case 绑定名未定义
|
||||
# (includes/llvmlite/__types.vp L407 `case LLVMType.Int(bits):` 的 bits 根因,
|
||||
# [RN] LLVMType -> 0 (scan count=1) 实证)。
|
||||
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 | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
VLogger.warning(f"{class_name} has no body", "RENUM")
|
||||
# [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)
|
||||
@@ -711,7 +732,11 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
variant_count += 1
|
||||
|
||||
if variant_count == 0:
|
||||
VLogger.warning(f"{class_name} has no variants", "RENUM")
|
||||
# [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
|
||||
|
||||
# 计算每个位置的最大字段大小
|
||||
@@ -923,6 +948,13 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
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:
|
||||
@@ -931,7 +963,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
# 检查是否已注册(避免重复注册)
|
||||
for i in range(self.RenumClassCount):
|
||||
existing: str = self.RenumClassNames[i]
|
||||
existing: str = (str)(t.CVoid(self.RenumClassNames[i], t.CPtr))
|
||||
if existing is not None and string.strcmp(existing, class_name) == 0:
|
||||
return
|
||||
|
||||
@@ -980,6 +1012,9 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
tag += 1
|
||||
|
||||
self.RenumClassCount = idx + 1
|
||||
# [D30 根治] 回写计数到编译期单例(新建 Generator 靠它恢复;不回写会导致
|
||||
# 新 Generator 只看到旧计数 → 后续注册的变体不可见)
|
||||
CompilerFactory.factory.RenumClassCount = self.RenumClassCount
|
||||
def _lookup_renum_variant(self, variant_name: str) -> str:
|
||||
"""查找变体名所属的 REnum 类名
|
||||
|
||||
@@ -992,17 +1027,58 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
vcount: int = self.RenumClassVariantCounts[i]
|
||||
for j in range(vcount):
|
||||
name_offset: sizet = i * RENUM_VARIANT_PER_CLASS + j
|
||||
vname: str = self.RenumVariantNames[name_offset]
|
||||
vname: str = (str)(t.CVoid(self.RenumVariantNames[name_offset], t.CPtr))
|
||||
if vname is not None and string.strcmp(vname, variant_name) == 0:
|
||||
cls_nm: str = self.RenumClassNames[i]
|
||||
cls_nm: str = (str)(t.CVoid(self.RenumClassNames[i], t.CPtr))
|
||||
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)(t.CVoid(self.RenumClassNames[0], t.CPtr))
|
||||
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)(t.CVoid(self.RenumVariantNames[0], t.CPtr))
|
||||
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 | t.CPtr = 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 = self.RenumClassNames[i]
|
||||
existing: str = (str)(t.CVoid(self.RenumClassNames[i], t.CPtr))
|
||||
if existing is not None and string.strcmp(existing, class_name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
@@ -1011,13 +1087,13 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
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 = self.RenumClassNames[i]
|
||||
existing: str = (str)(t.CVoid(self.RenumClassNames[i], t.CPtr))
|
||||
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 = self.RenumVariantNames[name_offset]
|
||||
vname: str = (str)(t.CVoid(self.RenumVariantNames[name_offset], t.CPtr))
|
||||
if vname is not None and string.strcmp(vname, variant_name) == 0:
|
||||
return self.RenumVariantTags[name_offset]
|
||||
return -1
|
||||
@@ -1058,6 +1134,13 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
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:
|
||||
return
|
||||
@@ -1117,6 +1200,8 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
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
|
||||
|
||||
|
||||
@@ -136,8 +136,10 @@ class MatchGenMixin:
|
||||
trans.SymTab, nm.id)
|
||||
entry_annot: str = self.Gen.VarGen.var_annot_class_name(entry)
|
||||
if entry_annot is not None \
|
||||
and self.Gen.ClassGenEnum._is_renum_class_name(
|
||||
entry_annot) != 0:
|
||||
and (self.Gen.ClassGenEnum._is_renum_class_name(
|
||||
entry_annot) != 0
|
||||
or self.Gen.ClassGenEnum._is_renum_by_entry(
|
||||
entry_annot) != 0):
|
||||
is_renum = 1
|
||||
renum_name = entry_annot
|
||||
subject_ptr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
@@ -159,7 +161,8 @@ class MatchGenMixin:
|
||||
and pat.kind() == ast.ASTKind.MatchClass:
|
||||
rnm: str = self._extract_renum_name_from_cls(pat)
|
||||
if rnm is not None \
|
||||
and self.Gen.ClassGenEnum._is_renum_class_name(rnm) != 0:
|
||||
and (self.Gen.ClassGenEnum._is_renum_class_name(rnm) != 0
|
||||
or self.Gen.ClassGenEnum._is_renum_by_entry(rnm) != 0):
|
||||
is_renum = 1
|
||||
renum_name = rnm
|
||||
if subject_ptr is None:
|
||||
|
||||
@@ -1825,6 +1825,18 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
self.Gen.TypeGenBase.pop_trace()
|
||||
if spec_name_chk is not None:
|
||||
gen_spec_ty = self.Gen.StructGen.get_struct_type(gen_mangled)
|
||||
# [D31] gen_mangled 由本函数自行拼接(_get_type_name_from_annotation
|
||||
# + _norm_type_arg_name),而 _specialize_generic_class 内部还会
|
||||
# 对每个实参再走一次规范化,两处命名可能不一致:如元素注解
|
||||
# `ast.AST | t.CPtr` 本函数拼出 "list[<sha1>.AST|t.CPtr]",
|
||||
# 特化侧规范化为 "list[<sha1>.ASTptr]"(联合折叠为指针名)。
|
||||
# 此时按 gen_mangled 重查恒 miss → 静默退化为裸 list* →
|
||||
# 之后 list.get() 误分派(返回 i32)→ inttoptr 截断指针 →
|
||||
# 读垃圾 AST 节点崩溃(D21/D25 崩溃族根因之一)。
|
||||
# spec_name_chk 是特化侧返回的**权威特化名**,必须按它重查。
|
||||
# 注:非联合实参(如 list[int])两侧命名一致,本步恒 miss 不改变行为。
|
||||
if gen_spec_ty is None:
|
||||
gen_spec_ty = self.Gen.StructGen.get_struct_type(spec_name_chk)
|
||||
if gen_spec_ty is not None:
|
||||
return gen_spec_ty
|
||||
else:
|
||||
@@ -1835,6 +1847,21 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
VLogger.info(f"[GENERIC-DBG] 模板未注册: {gen_cls_name}", "Phase1")
|
||||
else:
|
||||
VLogger.info(f"[GENERIC-DBG] trans 为 None: {gen_cls_name}", "Phase1")
|
||||
# [D32 治本 fail-fast] Phase B(declare_only==0)全量翻译时,**泛型模板类**的
|
||||
# 下标仍解析不出特化结构体 ⇒ 上游注解必然退化:
|
||||
# * BinOp(`list[X] | t.CPtr`) 分支会落到 `Ptr(i8)`(丢类型);
|
||||
# * 其它路径可能退化到裸基类 `list*`。
|
||||
# 二者后续的 `.get()` 都会按错误元素类型分派(实测 list[int].get 返回 i32)
|
||||
# → inttoptr 截断指针 → 读垃圾 AST 节点崩溃(D21/D25/D31/D32 崩溃族)。
|
||||
# 禁止静默退化:报出查表键与实际模板名,直接暴露退化点。
|
||||
# 仅当基名确为泛型模板时才触发——避免误伤 rowptr/CArray 等 builtin 下标。
|
||||
if trans is not None and trans._declare_only == 0 \
|
||||
and self.Gen.ClassGenGeneric._find_generic_template(gen_cls_name) is not None:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
sub,
|
||||
f"泛型下标 '{gen_mangled}' 未解析出特化结构体(泛型模板='{gen_cls_name}');"
|
||||
f"该注解将退化为裸基类/i8* → 后续 .get() 按错误元素类型分派并截断指针",
|
||||
"TypeError")
|
||||
# 未特化:返回 None(不报错,让后续流程处理)
|
||||
return None
|
||||
def resolve_annotation_type(self, pool: rowptr[memhub.MemBuddy],
|
||||
|
||||
Reference in new issue
Block a user