fix(match): REnum 变体字段绑定不再静默跳过(__types.vp bits NameError)
根因:_handle_renum_match step6 用 renum_name 查 struct 且不校验 Ty;拿不到 entry/Ty 时 step7 的 _bind_variant_fields 被整段静默跳过 -> case 绑定名在 body 里未定义,最终只报 NameError(bits),真因藏到下游 1) 名字回退:变体表与 struct 注册都按裸类名,而 renum_name 来自注解 SourceName(Attribute 可带模块限定名)-> 精确查找失配;与 tag 查表同一裸名推导(tag_cls_bare) 2) 新增 StructGenMixin.find_struct_entry_with_ty:跳过 D30 重注册时就地中和的旧 entry(Name[0]=0/Ty=None/FieldCount=0),避免命中它拿到 Ty=None 3) 禁止静默:仍有 REnum 判据为真却无法绑定时 fail-fast,打印 class/查表名/entry/FieldCount/ty_present(对齐 D30/D32 的响亮失败口径)
This commit is contained in:
1 parent
a79e723e8d
commit
5e100e2195
2 files changed
+66
-4
No files matched your search
@@ -572,12 +572,25 @@ novirtual class MatchGenMixin:
|
||||
llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count)
|
||||
|
||||
# 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP)
|
||||
# 两条健壮性要求——否则 renum_entry/renum_ty 取不到,step 7 的变体字段绑定会被
|
||||
# **整段静默跳过** ⇒ case 绑定名在 body 里未定义(NameError:__types.vp
|
||||
# `_TypePrintDepth` 的 `bits` 根因,真因因此藏到下游):
|
||||
# (1) 名字:变体表与 struct 注册都按**裸类名**(ClassDef.name),而 renum_name
|
||||
# 来自注解书写形态(Spec.SourceName,Attribute 可带模块限定名,如
|
||||
# "c93534fe43c0ee56.LLVMType")⇒ 精确查找可能失配 → 回退 tag_cls_bare。
|
||||
# (2) 条目有效性:find_struct 是"首注册命中",可能命中 D30 重注册时被就地
|
||||
# 中和的旧 entry(Ty=None)⇒ 扫表取 Ty 有效者。
|
||||
renum_entry: GenTypes.StructEntry* = None
|
||||
renum_ty: llvmlite.LLVMType* = None
|
||||
se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(renum_name)
|
||||
if se is not None:
|
||||
if se is not None and se.Ty is not None:
|
||||
renum_entry = se
|
||||
renum_ty = se.Ty
|
||||
else:
|
||||
se_v: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_entry_with_ty(renum_name, tag_cls_bare)
|
||||
if se_v is not None:
|
||||
renum_entry = se_v
|
||||
renum_ty = se_v.Ty
|
||||
|
||||
# 7. 第二遍:翻译每个 case body
|
||||
i = 0
|
||||
@@ -607,9 +620,32 @@ novirtual class MatchGenMixin:
|
||||
self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH)
|
||||
|
||||
# 变体字段绑定(MatchClass)
|
||||
if pat is not None and pat.kind() == ast.ASTKind.MatchClass \
|
||||
and renum_entry is not None and renum_ty is not None:
|
||||
self._bind_variant_fields(pat, renum_name, renum_entry, renum_ty, subject_ptr, trans, pool, builder)
|
||||
if pat is not None and pat.kind() == ast.ASTKind.MatchClass:
|
||||
if renum_entry is not None and renum_ty is not None:
|
||||
self._bind_variant_fields(pat, renum_name, renum_entry, renum_ty, subject_ptr, trans, pool, builder)
|
||||
elif (self.Gen.ClassGenEnum._is_renum_class_name(tag_cls_bare) != 0
|
||||
or self.Gen.ClassGenEnum._is_renum_class_name(renum_name) != 0
|
||||
or self.Gen.ClassGenEnum._is_renum_by_entry(tag_cls_bare) != 0
|
||||
or self.Gen.ClassGenEnum._is_renum_by_entry(renum_name) != 0):
|
||||
# 走到这里 ⇒ 分派判定为 REnum match(同一组判据至少一条为真),而
|
||||
# MatchClass 却拿不到可用的 struct entry/类型:此前**静默跳过**绑定
|
||||
# ⇒ 绑定名在 body 里未定义,最终报 NameError(__types.vp `bits`),
|
||||
# 真因被藏到下游。此处 fail-fast 并打印现场,便于定位是"变体表缺该类"
|
||||
# 还是"条目被中和/Ty 缺失"。
|
||||
ent_nm: str = "None"
|
||||
ent_fc: int = -1
|
||||
if renum_entry is not None:
|
||||
ent_nm = renum_entry.Name
|
||||
ent_fc = renum_entry.FieldCount
|
||||
ty_present: int = 0
|
||||
if renum_ty is not None:
|
||||
ty_present = 1
|
||||
self.Gen.TypeGenErr.fatal_error(pat,
|
||||
f"REnum match 变体字段绑定失败:class='{tag_cls_bare}'(查表名='{renum_name}')"
|
||||
f" entry='{ent_nm}' FieldCount={ent_fc} ty_present={ty_present};"
|
||||
f"变体表已登记该类,说明结构体条目或 Ty 缺失(已不再静默跳过绑定,"
|
||||
f"否则绑定名未定义只会在下游报 NameError)",
|
||||
"InternalCompilerError")
|
||||
|
||||
# 翻译 case body
|
||||
body_list: list[ast.AST*]* = mc.children
|
||||
|
||||
@@ -733,6 +733,32 @@ novirtual class StructGenMixin:
|
||||
s_rm = StubMergerStore.LookupSha1ByModNameSuffix(mod_name)
|
||||
return s_rm
|
||||
|
||||
def find_struct_entry_with_ty(self, name: str, alt_name: str) -> GenTypes.StructEntry*:
|
||||
"""按名字(含备选名)查**带有效 Ty** 的结构体条目;找不到返回 None。
|
||||
|
||||
为什么需要它:`find_struct` 的语义是"首注册命中"。D30 的 REnum 重注册把旧
|
||||
entry **就地中和**(`Name[0]='\\0'` / `Ty=None` / `FieldCount=0`)后再追加新
|
||||
entry;若名索引/线性扫描先命中那条已中和的旧条目,调用方拿到的 `Ty` 是 None ——
|
||||
依赖 `Ty` 的代码(如 match 的 REnum 变体字段绑定)会**静默跳过**,症状表现为
|
||||
case 绑定名未定义(NameError,真因被藏到下游)。本函数跳过 `Ty` 无效的同名条目,
|
||||
返回首个 `Ty` 有效的同名(或备选名)条目;都没有则返回 None,由调用方决定报错。
|
||||
|
||||
name / alt_name:主名与备选名(如模块限定名与裸类名),任一命中即可。
|
||||
"""
|
||||
if self.StructTable is None:
|
||||
return None
|
||||
for i in range(self.StructCount):
|
||||
entry: GenTypes.StructEntry* = self._get_struct_entry(i)
|
||||
if entry is None or entry.Name is None or entry.Ty is None:
|
||||
continue
|
||||
if entry.Name[0] == '\0':
|
||||
continue
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
if alt_name is not None and string.strcmp(entry.Name, alt_name) == 0:
|
||||
return entry
|
||||
return None
|
||||
|
||||
def find_struct(self, name: str) -> GenTypes.StructEntry*:
|
||||
"""按类名查找结构体,返回 StructEntry 或 None
|
||||
|
||||
|
||||
Reference in new issue
Block a user