diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index 090d953..50abbb5 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -997,6 +997,45 @@ class BaseHandle: return True return False + def _EnsureRenumVariantStruct(self, Gen: Any, RenumName: str, VariantName: str) -> str: + """确保 REnum 变体嵌套结构体 `_` 及其 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: diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index b6cc9bb..c3c5ef0 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -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,不含 + # `_` 声明(见 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) diff --git a/lib/core/Handles/HandlesMatch.py b/lib/core/Handles/HandlesMatch.py index a14e343..97b578d 100644 --- a/lib/core/Handles/HandlesMatch.py +++ b/lib/core/Handles/HandlesMatch.py @@ -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, + # 不含 `_` 声明(见 _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))