fix(tpc): REnum 变体嵌套结构体按需补发 + 模式捕获绑不上即 fail-fast
a 编译器缺陷:导入模块侧 stub 只声明主 REnum(`%"…LLVMType" = type {…}`),**不含**
变体嵌套结构体(`LLVMType_Ptr` 等)——它们由 `_EmitExternalClassDeclLlvm` 的 REnum
分支按主结构体布局就地生成。若本模块从未触发该 REnum 的外部声明发射:
1) match 模式捕获(`case llvmlite.LLVMType.Ptr(pointee_cs):`)绑定静默为空 ⇒ case
body 里引用的绑定名随后报"未定义名称"(现场 VpiReader.vp:1521 `pointee_cs`);
2) REnum 变体构造的载荷实参静默丢弃(只写 tag)—— 静默错码。
修法:
- 新增 BaseHandle._EnsureRenumVariantStruct:成员缺失时按需补发(先试 stub,再按
类 sha1 找到定义模块 .vpi 触发 `_TryLoadClassMembersFromPyi` → 内部即调
`_EmitExternalClassDeclLlvm`)。
- HandlesMatch._HandleRenumMatchLlvm:改用该助手;**模式捕获登记不全即 fail-fast**
(报出变体名、class_members 项数、structs 命中与同前缀键),绝不让绑定名留到
取名时才炸。
- HandlesMatch 非 REnum 兜底分支:MatchClass 含捕获时改为 fail-fast,并列出判据
(IsEnumMember/EnumName/IsRenum/IsStruct/IsEnum),直接暴露"外层 REnum 判定为何
未成立"。
- HandlesExprCall._HandleREnumConstructLlvm:载荷实参存在而嵌套结构体缺失时补齐,
补不上则 fail-fast(拒绝产出"只有 tag 没有载荷"的值)。
This commit is contained in:
1 parent
02d89b0900
commit
53bde9157e
3 files changed
+130
-7
No files matched your search
@@ -997,6 +997,45 @@ class BaseHandle:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _EnsureRenumVariantStruct(self, Gen: Any, RenumName: str, VariantName: str) -> str:
|
||||
"""确保 REnum 变体嵌套结构体 `<REnumName>_<VariantName>` 及其 class_members 就绪。
|
||||
|
||||
为什么需要:导入模块侧的 stub **只声明主 REnum**(如
|
||||
`%"…LLVMType" = type { i32, i64, i64, i64 }`),**不含**变体嵌套结构体声明
|
||||
(`LLVMType_Ptr` 等)——它们由 `_EmitExternalClassDeclLlvm` 的 REnum 分支按主
|
||||
结构体布局就地生成。若本模块从未触发该 REnum 的外部声明发射,`Gen.structs` /
|
||||
`Gen.class_members` 里就没有变体——于是:
|
||||
|
||||
- match 模式捕获(`case LLVMType.Ptr(pointee):`)绑定静默为空 ⇒ case body
|
||||
里引用的绑定名随后变成"未定义名称"(现场 VpiReader.vp:1521 `pointee_cs`);
|
||||
- REnum 变体构造的载荷实参静默丢弃(只写了 tag)。
|
||||
|
||||
故按需补发:先试 stub,再按类 sha1 找到定义模块的 `.vpi` 触发完整外部声明发射
|
||||
(`_TryLoadClassMembersFromPyi` 内部即调 `_EmitExternalClassDeclLlvm`)。
|
||||
返回嵌套结构体名(调用方据此查 `Gen.class_members` 判可用性)。
|
||||
"""
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if Gen.class_members.get(NestedStructName):
|
||||
return NestedStructName
|
||||
_sha1: str | None = None
|
||||
for _map in (getattr(Gen, 'class_sha1_map', {}), getattr(Gen, '_struct_sha1_map', {})):
|
||||
_sha1 = _map.get(RenumName)
|
||||
if _sha1:
|
||||
break
|
||||
_IH: Any = getattr(self.Trans, 'ImportHandler', None)
|
||||
if _IH is None:
|
||||
return NestedStructName
|
||||
try:
|
||||
_IH._TryLoadStructFromStub(NestedStructName, Gen)
|
||||
except Exception: # 与既有导入路径同口径:失败由下方判据统一暴露
|
||||
pass
|
||||
if not Gen.class_members.get(NestedStructName) and _sha1:
|
||||
try:
|
||||
_IH._TryLoadClassMembersFromPyi(RenumName, f"{_sha1}.stub.ll", Gen)
|
||||
except Exception:
|
||||
pass
|
||||
return NestedStructName
|
||||
|
||||
def CollectAnnAssignMember(
|
||||
self, item: ast.AST, Gen: Any
|
||||
) -> tuple[str, _ir.Type, CTypeInfo | None] | None:
|
||||
|
||||
@@ -2231,6 +2231,22 @@ class ExprCallHandle(BaseHandle):
|
||||
tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr")
|
||||
Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr)
|
||||
NestedStructName = f"{RenumName}_{VariantName}"
|
||||
if Node.args:
|
||||
# 变体嵌套结构体按需补发:导入模块侧 stub 只声明主 REnum,不含
|
||||
# `<REnum>_<Variant>` 声明(见 BaseHandle._EnsureRenumVariantStruct)。
|
||||
# 缺它时历史行为是**静默丢弃全部载荷实参**(只写 tag)—— 属静默错码,
|
||||
# 故此处补齐;补不上则响亮失败,绝不产出"只有 tag 没有载荷"的值。
|
||||
self._EnsureRenumVariantStruct(Gen, RenumName, VariantName)
|
||||
if NestedStructName not in Gen.structs or not Gen.class_members.get(NestedStructName):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"REnum 变体 '{RenumName}.{VariantName}' 的嵌套结构体/载荷成员缺失,"
|
||||
f"无法写入 {len(Node.args)} 个载荷实参(拒绝静默丢弃):"
|
||||
f"structs 命中={'有' if NestedStructName in Gen.structs else '无'} "
|
||||
f"class_members={len(Gen.class_members.get(NestedStructName, []))} 项;"
|
||||
f"同前缀 structs 键="
|
||||
f"{[k for k in Gen.structs if k.startswith(RenumName + '_')][:8]}"
|
||||
)
|
||||
if NestedStructName in Gen.structs and Node.args:
|
||||
NestedStructType = Gen.structs[NestedStructName]
|
||||
NestedStructPtrType = ir.PointerType(NestedStructType)
|
||||
|
||||
@@ -8,6 +8,32 @@ import llvmlite.ir as ir
|
||||
|
||||
|
||||
class MatchHandle(BaseHandle):
|
||||
@staticmethod
|
||||
def _PatternCaptureNames(Pattern: ast.AST) -> list[str]:
|
||||
"""模式中所有**捕获名**(递归 MatchOr/MatchClass/MatchSequence/MatchMapping)。
|
||||
|
||||
用于判定"该 case 是否必须登记绑定":有捕获却登记不上,case body 里的名字
|
||||
就会变成"未定义名称",必须在**生成 body 之前**响亮失败,而不是留到取名时。
|
||||
"""
|
||||
Names: list[str] = []
|
||||
if isinstance(Pattern, ast.MatchAs):
|
||||
if Pattern.name:
|
||||
Names.append(Pattern.name)
|
||||
if Pattern.pattern is not None:
|
||||
Names.extend(MatchHandle._PatternCaptureNames(Pattern.pattern))
|
||||
elif isinstance(Pattern, ast.MatchStar):
|
||||
if Pattern.name:
|
||||
Names.append(Pattern.name)
|
||||
elif isinstance(Pattern, (ast.MatchOr, ast.MatchSequence, ast.MatchClass, ast.MatchMapping)):
|
||||
for p in (getattr(Pattern, 'patterns', None) or []):
|
||||
Names.extend(MatchHandle._PatternCaptureNames(p))
|
||||
for p in (getattr(Pattern, 'kwd_patterns', None) or []):
|
||||
Names.extend(MatchHandle._PatternCaptureNames(p))
|
||||
_rest: str | None = getattr(Pattern, 'rest', None)
|
||||
if _rest:
|
||||
Names.append(_rest)
|
||||
return Names
|
||||
|
||||
def _HandleMatchLlvm(self, Node: ast.Match) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject)
|
||||
@@ -152,6 +178,32 @@ class MatchHandle(BaseHandle):
|
||||
if SymInfo_mc and SymInfo_mc.IsEnumMember:
|
||||
TagValue_mc = SymInfo_mc.value
|
||||
if TagValue_mc is not None:
|
||||
# 兜底分支**不登记捕获绑定**(它按整数 tag 处理,无变体载荷可 GEP)。
|
||||
# 因此只要该 case 有捕获,就必须在此 fail-fast —— 否则 case body 里的
|
||||
# 绑定名随后变成"未定义名称"(现场 VpiReader.vp:1521 pointee_cs),
|
||||
# 真因(外层 REnum 判定未成立)被掩盖。报文直接列出判据供定位。
|
||||
_caps_mc: list[str] = self._PatternCaptureNames(pattern)
|
||||
if _caps_mc:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
_en_mc: str | None = getattr(SymInfo_mc, 'EnumName', None)
|
||||
_sym_en: "SymbolTable.SymbolInfo" = (
|
||||
self.Trans.SymbolTable.lookup(_en_mc) if _en_mc else None)
|
||||
_sym_v: "SymbolTable.SymbolInfo" = (
|
||||
self.Trans.SymbolTable.lookup(VariantName_mc) if VariantName_mc else None)
|
||||
raise FailFastError(
|
||||
f"REnum 变体模式 '{QualifiedName_mc or VariantName_mc}' 含捕获 {_caps_mc},"
|
||||
f"但外层 REnum 匹配判定未成立(IsRenumMatch=False)⇒ 兜底分支不登记捕获绑定,"
|
||||
f"case body 里这些名字必然成为'未定义名称'。判据:"
|
||||
f"符号表['{QualifiedName_mc}'] => "
|
||||
f"IsEnumMember={getattr(SymInfo_mc, 'IsEnumMember', None)} "
|
||||
f"value={getattr(SymInfo_mc, 'value', None)} EnumName={_en_mc!r};"
|
||||
f"符号表['{_en_mc}'] => IsRenum={getattr(_sym_en, 'IsRenum', None)} "
|
||||
f"IsStruct={getattr(_sym_en, 'IsStruct', None)} "
|
||||
f"IsEnum={getattr(_sym_en, 'IsEnum', None)};"
|
||||
f"符号表['{VariantName_mc}'] => "
|
||||
f"IsEnumMember={getattr(_sym_v, 'IsEnumMember', None)} "
|
||||
f"EnumName={getattr(_sym_v, 'EnumName', None)!r}"
|
||||
)
|
||||
CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc))
|
||||
CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}"))
|
||||
else:
|
||||
@@ -297,13 +349,29 @@ class MatchHandle(BaseHandle):
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))
|
||||
CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}")
|
||||
CaseBBs.append(CaseBB)
|
||||
NestedStructName: str = f"{RenumName}_{VariantName}"
|
||||
if NestedStructName in Gen.structs:
|
||||
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
|
||||
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
|
||||
for j, sub_pat in enumerate(pattern.patterns):
|
||||
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
|
||||
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
|
||||
# 变体嵌套结构体按需补发:导入模块侧 stub 只声明主 REnum,
|
||||
# 不含 `<REnum>_<Variant>` 声明(见 _EnsureRenumVariantStruct)。
|
||||
NestedStructName: str = self._EnsureRenumVariantStruct(Gen, RenumName, VariantName)
|
||||
members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, [])
|
||||
payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag']
|
||||
# 模式捕获必须能全部绑定:绑不上就在此 fail-fast,绝不让 case body
|
||||
# 里的绑定名留到后面变成"未定义名称"(现场 VpiReader.vp:1521 pointee_cs)。
|
||||
_captures: list[str] = [p.name for p in pattern.patterns
|
||||
if isinstance(p, ast.MatchAs) and p.name]
|
||||
if _captures and len(payLoad_members) < len(_captures):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"REnum 变体模式 '{RenumName}.{VariantName}' 的载荷成员不足,"
|
||||
f"无法绑定模式捕获 {_captures}:"
|
||||
f"class_members['{NestedStructName}']={len(members)} 项"
|
||||
f"(去 __tag 后载荷 {len(payLoad_members)} 项);"
|
||||
f"structs 命中={'有' if NestedStructName in Gen.structs else '无'};"
|
||||
f"同前缀 structs 键="
|
||||
f"{[k for k in Gen.structs if k.startswith(RenumName + '_')][:8]}"
|
||||
)
|
||||
for j, sub_pat in enumerate(pattern.patterns):
|
||||
if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members):
|
||||
bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j))
|
||||
CaseBindings.append(bindings)
|
||||
else:
|
||||
CaseValues.append(ir.Constant(ir.IntType(32), 0))
|
||||
|
||||
Reference in new issue
Block a user