from __future__ import annotations from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Handles.HandlesBase import BaseHandle import vast as ast 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 @staticmethod def _ValueLabelKey(Value: ast.expr) -> str: """MatchValue.value 的标签键:Constant / Name / Attribute 链""" if isinstance(Value, ast.Constant): Kind: str = Value.kind if Value.kind is not None else type(Value.value).__name__ return f"{Kind}:{Value.value!r}" if isinstance(Value, ast.Name): return f"Name:{Value.id}" if isinstance(Value, ast.Attribute): return f"Attr:{MatchHandle._ValueLabelKey(Value.value)}.{Value.attr}" return f"{type(Value).__name__}" @staticmethod def _CaseLabelKey(Pattern: ast.pattern) -> str | None: """case 的 switch 标签键(None = 不参与重名判定) - MatchValue → 'V:<值键>'(Constant 值 / Name / Attribute 链) - MatchSingleton → 'S:<值>'(None/True/False) - MatchClass → 'K:<变体名>'(cls 为 Name 用 id,Attribute 用链) - MatchOr → 'O:<子模式键>'(子键任一不可比则整条不可比) - MatchAs / MatchSequence 等 → None(通配/序列,不产出 switch 常量标签) """ if isinstance(Pattern, ast.MatchValue): return f"V:{MatchHandle._ValueLabelKey(Pattern.value)}" if isinstance(Pattern, ast.MatchSingleton): return f"S:{Pattern.value!r}" if isinstance(Pattern, ast.MatchClass): Cls: ast.expr = Pattern.cls if isinstance(Cls, ast.Name): return f"K:{Cls.id}" if isinstance(Cls, ast.Attribute): return f"K:{MatchHandle._ValueLabelKey(Cls)}" return None if isinstance(Pattern, ast.MatchOr): Parts: list[str | None] = [MatchHandle._CaseLabelKey(p) for p in Pattern.patterns] if any(p is None for p in Parts): return None return "O:" + "|".join(Parts) return None def _HandleMatchLlvm(self, Node: ast.Match) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen # 重名 case 检测(fail-fast):**match 不允许重复 case 标签**——重复标签会让 # 某个臂永远不可达,且通常意味着漏改的分支。**switch 允许重复标签**(按书写 # 顺序,先出现者生效),故仅对 match 做值标签去重。 # 通配臂(match 的 `case _` / switch 的 `default`)两者都只允许一个。 # 在产出任何 IR 之前检查,保证报错即终止。报文前缀按 is_switch 区分。 KindLabel: str = 'switch' if Node.is_switch else 'match' DefaultLabel: str = '`default`' if Node.is_switch else '`case _`' SeenLabels: dict[str, int] = {} DefaultCount: int = 0 for ci, case in enumerate(Node.cases): Key: str | None = MatchHandle._CaseLabelKey(case.pattern) if Key is None: if isinstance(case.pattern, ast.MatchAs) and case.pattern.pattern is None: DefaultCount += 1 continue if not Node.is_switch and Key in SeenLabels: from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"match 出现重名 case:标签 '{Key}' 已在第 {SeenLabels[Key]} 个 case 使用," f"第 {ci} 个 case 重复(match 不允许重复 case 标签)") SeenLabels[Key] = ci if DefaultCount > 1: from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( f"{KindLabel} 出现 {DefaultCount} 个 {DefaultLabel}(通配/default 只允许一个)") SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject) if not SubjectVal: return IsRenumMatch: bool = False RenumName: str | None = None SubjectPtr: ir.Value | None = None if isinstance(Node.subject, ast.Name): VarName: str = Node.subject.id TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) if TypeInfo and TypeInfo.IsRenum: IsRenumMatch = True RenumName = TypeInfo.Name SubjectPtr = Gen._Load_var(VarName) if not IsRenumMatch: for case in Node.cases: if isinstance(case.pattern, ast.MatchClass): cls_node: ast.expr = case.pattern.cls VariantName: str | None = None QualifiedName: str | None = None if isinstance(cls_node, ast.Name): VariantName = cls_node.id elif isinstance(cls_node, ast.Attribute): VariantName = cls_node.attr # Extract enum name for qualified lookup to avoid collision # with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr) if isinstance(cls_node.value, ast.Attribute): QualifiedName = f"{cls_node.value.attr}.{VariantName}" elif isinstance(cls_node.value, ast.Name): QualifiedName = f"{cls_node.value.id}.{VariantName}" if VariantName: # Try qualified name first (e.g., "LLVMType.Ptr") to avoid # collision with same-name functions (e.g., def Ptr(...)) SymInfo: "SymbolTable.SymbolInfo" = None if QualifiedName: SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) if not (SymInfo and SymInfo.IsEnumMember): SymInfo = self.Trans.SymbolTable.lookup(VariantName) if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName: EnumName: str = SymInfo.EnumName EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName) if EnumInfo and EnumInfo.IsRenum: IsRenumMatch = True RenumName = EnumName if SubjectPtr is None: SubjectPtr = self.HandleExprLlvm(Node.subject) break if IsRenumMatch and SubjectPtr: self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) return if not isinstance(SubjectVal.type, ir.IntType): try: SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") except Exception: # 回退:ptrtoint 失败时直接返回 return SwitchIntType: ir.IntType = SubjectVal.type DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") CaseBBs: list[ir.Block] = [] CaseValues: list[ir.Value] = [] HasDefault: bool = False HasNoBreak: list[bool] = [] for i, case in enumerate(Node.cases): pattern: ast.pattern = case.pattern if isinstance(pattern, ast.MatchValue): Val: ir.Value | None = self.HandleExprLlvm(pattern.value) if Val: if not isinstance(Val, ir.Constant): from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( "switch/match 的 case 标签必须是编译期常量" "(当前标签求值成运行期值,无法作为 switch 的 case 常量)") CaseVal: ir.Value if isinstance(Val.type, ir.IntType): if Val.type != SwitchIntType: if Val.type.width > SwitchIntType.width: CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) else: CaseVal = ir.Constant(SwitchIntType, Val.constant) else: CaseVal = Val else: try: CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") except Exception: # 回退:ptrtoint 失败时设默认值 0 CaseVal = ir.Constant(SwitchIntType, 0) CaseValues.append(CaseVal) CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) elif isinstance(pattern, ast.MatchOr): for j, SubPattern in enumerate(pattern.patterns): if isinstance(SubPattern, ast.MatchValue): Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value) if Val: if not isinstance(Val, ir.Constant): from lib.core.LLVMCG.FuncGen import FailFastError raise FailFastError( "switch/match 的 case 标签必须是编译期常量" "(当前标签求值成运行期值,无法作为 switch 的 case 常量)") CaseVal: ir.Value if isinstance(Val.type, ir.IntType): if Val.type != SwitchIntType: if Val.type.width > SwitchIntType.width: CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) else: CaseVal = ir.Constant(SwitchIntType, Val.constant) else: CaseVal = Val else: try: CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") except Exception: # 回退:ptrtoint 失败时设默认值 0 CaseVal = ir.Constant(SwitchIntType, 0) CaseValues.append(CaseVal) CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) elif isinstance(pattern, ast.MatchSingleton): if pattern.value is None: CaseValues.append(ir.Constant(SwitchIntType, 0)) CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) elif isinstance(pattern, ast.MatchAs): if pattern.pattern is None: HasDefault = True CaseBBs.append(DefaultBB) elif isinstance(pattern, ast.MatchSequence): HasDefault = True CaseBBs.append(DefaultBB) elif isinstance(pattern, ast.MatchClass): # 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式) # 尝试从变体名查找 tag 值,按整数值处理 cls_node_mc: ast.expr = pattern.cls VariantName_mc: str | None = None QualifiedName_mc: str | None = None if isinstance(cls_node_mc, ast.Name): VariantName_mc = cls_node_mc.id elif isinstance(cls_node_mc, ast.Attribute): VariantName_mc = cls_node_mc.attr if isinstance(cls_node_mc.value, ast.Attribute): QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}" elif isinstance(cls_node_mc.value, ast.Name): QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}" TagValue_mc: int | None = None SymInfo_mc: "SymbolTable.SymbolInfo" = None if QualifiedName_mc: SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc) if not (SymInfo_mc and SymInfo_mc.IsEnumMember): SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc) 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: # 变体名未找到,跳过此 case(fast-fail 已在外层处理) pass HasNoBreak.append(MatchHandle._HasNoBreakMarker(case.body) if case.body else False) if not HasDefault: CaseBBs.append(DefaultBB) SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB) for val, bb in SwitchCases: switch_instr.add_case(val, bb) CaseIdx: int = 0 for i, case in enumerate(Node.cases): pattern: ast.pattern = case.pattern if isinstance(pattern, ast.MatchOr): NumSubCases: int = len(pattern.patterns) for j in range(NumSubCases): if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: Gen.builder.position_at_start(CaseBBs[CaseIdx]) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: Gen.builder.position_at_start(CaseBBs[CaseIdx]) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, ast.MatchAs): if pattern.pattern is None: Gen.builder.position_at_start(DefaultBB) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, ast.MatchSequence): Gen.builder.position_at_start(DefaultBB) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, ast.MatchClass): # 兜底处理:MatchClass 在非 REnum 路径的 case body 生成 # case 收集阶段已创建 CaseBB,此处生成 body if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: Gen.builder.position_at_start(CaseBBs[CaseIdx]) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 if not HasDefault: Gen.builder.position_at_start(DefaultBB) Gen.builder.branch(AfterBB) elif not any(isinstance(pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(pattern, ast.MatchSequence) for c in Node.cases): Gen.builder.position_at_start(DefaultBB) Gen.builder.branch(AfterBB) Gen.builder.position_at_start(AfterBB) @staticmethod def _HasNoBreakMarker(Stmts: list[ast.stmt]) -> bool: """case 体(含其嵌套 body/orelse)是否含 `fallthrough` 标记(NoBreak())""" for stmt in Stmts: if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): if isinstance(stmt.value.func, ast.Name) and stmt.value.func.id == 'NoBreak': return True NestedBody: Any = getattr(stmt, 'body', None) if NestedBody and isinstance(NestedBody, list) and MatchHandle._HasNoBreakMarker(NestedBody): return True NestedElse: Any = getattr(stmt, 'orelse', None) if NestedElse and isinstance(NestedElse, list) and MatchHandle._HasNoBreakMarker(NestedElse): return True return False def _HandleMatchCaseBody(self, Gen: "Translator.LlvmGen", Body: list[ast.stmt], AfterBB: ir.Block, IsSwitch: bool) -> None: """翻译一个 case 体:case 体内的 break 目标是 AfterBB(C switch 语义) - case 内 break 跳出 **match/switch**(而非外层循环):翻译前把 AfterBB 压入 loop_break_targets,翻译完弹出(外层循环目标不受影响)。 - 同时把 Gen.in_switch_case 置为 IsSwitch(进出恢复):供 `fallthrough` 标记语句判定合法性 —— 只有 switch 的 case 体内才允许,写进 match (完全禁止 fallthrough)或 switch 之外由 HandlesBody fail-fast。 """ Targets: list = Gen.loop_break_targets Targets.append(AfterBB) PrevInSwitch: bool = Gen.in_switch_case Gen.in_switch_case = IsSwitch try: self.HandleBodyLlvm(Body) finally: Gen.in_switch_case = PrevInSwitch Targets.pop() @staticmethod def _FallThroughTarget(CaseBBs: list[ir.Block], CaseIdx: int, AfterBB: ir.Block) -> ir.Block: """fallthrough 的落点:下一个 case 的 body(无后继槽位时落到 AfterBB) `fallthrough`(vast 关键字,脱糖为 NoBreak())表示"本 case 不自动 跳出 switch",直接落到下一个 case 的 body(对齐 C 的 [[fallthrough]])。 """ NextIdx: int = CaseIdx + 1 if 0 <= NextIdx < len(CaseBBs): return CaseBBs[NextIdx] return AfterBB def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None: Gen: "Translator.LlvmGen" = self.Trans.LlvmGen if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj") # Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。 # 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store # 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType) NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))) if NeedAlloca or NeedBitcast: RenumStructType: Any = Gen.structs.get(RenumName) if RenumStructType is None: # 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册 # (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。 # 使用 _get_or_create_struct 按需创建(可能为 opaque)。 RenumStructType = Gen._get_or_create_struct(RenumName) if NeedAlloca: AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca") CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast") Gen._store(SubjectPtr, CastedPtr) SubjectPtr = AllocaPtr else: SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast") # REnum 布局为 { i32 __tag, },tag 在偏移 0。 # 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体 # (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。 tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr") TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val") DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") CaseBBs: list[ir.Block] = [] CaseValues: list[ir.Value] = [] CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = [] HasDefault: bool = False HasNoBreak: list[bool] = [] for i, case in enumerate(Node.cases): pattern: ast.pattern = case.pattern bindings: list[tuple[str, str, ir.Type, int]] = [] if isinstance(pattern, ast.MatchClass): cls_node: ast.expr = pattern.cls VariantName: str | None = None QualifiedName: str | None = None if isinstance(cls_node, ast.Name): VariantName = cls_node.id elif isinstance(cls_node, ast.Attribute): VariantName = cls_node.attr if isinstance(cls_node.value, ast.Attribute): QualifiedName = f"{cls_node.value.attr}.{VariantName}" elif isinstance(cls_node.value, ast.Name): QualifiedName = f"{cls_node.value.id}.{VariantName}" if VariantName: TagValue: int | None = None SymInfo: "SymbolTable.SymbolInfo" = None if QualifiedName: SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) if not (SymInfo and SymInfo.IsEnumMember): SymInfo = self.Trans.SymbolTable.lookup(VariantName) if SymInfo and SymInfo.IsEnumMember: TagValue = SymInfo.value if TagValue is not None: CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}") CaseBBs.append(CaseBB) # 变体嵌套结构体按需补发:导入模块侧 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)) CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) CaseBindings.append([]) elif isinstance(pattern, ast.MatchValue): Val: ir.Value | None = self.HandleExprLlvm(pattern.value) if Val: CaseVal: ir.Value if isinstance(Val.type, ir.IntType): CaseVal = Val else: try: CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") except Exception: # 回退:ptrtoint 失败时设默认值 0 CaseVal = ir.Constant(ir.IntType(32), 0) CaseValues.append(CaseVal) CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) CaseBindings.append([]) elif isinstance(pattern, ast.MatchAs): if pattern.pattern is None: HasDefault = True CaseBBs.append(DefaultBB) CaseBindings.append([]) elif isinstance(pattern, ast.MatchSequence): HasDefault = True CaseBBs.append(DefaultBB) CaseBindings.append([]) HasNoBreak.append(MatchHandle._HasNoBreakMarker(case.body) if case.body else False) if not HasDefault: CaseBBs.append(DefaultBB) SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB) for val, bb in SwitchCases: switch_instr.add_case(val, bb) CaseIdx: int = 0 for i, case in enumerate(Node.cases): pattern: ast.pattern = case.pattern if isinstance(pattern, ast.MatchClass): if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: Gen.builder.position_at_start(CaseBBs[CaseIdx]) bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] cls_node: ast.expr = pattern.cls VariantName: str | None = None if isinstance(cls_node, ast.Name): VariantName = cls_node.id elif isinstance(cls_node, ast.Attribute): VariantName = cls_node.attr if VariantName: NestedStructName: str = f"{RenumName}_{VariantName}" if NestedStructName in Gen.structs: NestedStructType: ir.Type = Gen.structs[NestedStructName] # 变体 struct 可能仍是 opaque(body 未 set_body / 同名两份实例) # ⇒ 先取已具化实例,否则 GEP 在编译期算不出元素类型(判据见 # ExprAttrHandle._ConcretePointeeFor)。 _TwV: Any = self.Trans.ExprAttrHandle._ConcretePointeeFor( Gen, NestedStructName, NestedStructType) if isinstance(_TwV, ir.IdentifiedStructType): NestedStructType = _TwV NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType) variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") for bind_name, member_name, member_type, member_idx in bindings: elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") # REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与 # 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。 if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type: elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast") Gen.variables[bind_name] = elem_ptr self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) for bind_name, _, _, _ in bindings: if bind_name in Gen.variables: del Gen.variables[bind_name] if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, ast.MatchValue): if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: Gen.builder.position_at_start(CaseBBs[CaseIdx]) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, ast.MatchAs): if pattern.pattern is None: Gen.builder.position_at_start(DefaultBB) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 elif isinstance(pattern, ast.MatchSequence): Gen.builder.position_at_start(DefaultBB) self._HandleMatchCaseBody(Gen, case.body, AfterBB, Node.is_switch) if not Gen.builder.block.is_terminated: if not HasNoBreak[i]: Gen.builder.branch(AfterBB) else: Gen.builder.branch(self._FallThroughTarget(CaseBBs, CaseIdx, AfterBB)) CaseIdx += 1 if not HasDefault: Gen.builder.position_at_start(DefaultBB) Gen.builder.branch(AfterBB) elif not any(isinstance(pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(pattern, ast.MatchSequence) for c in Node.cases): Gen.builder.position_at_start(DefaultBB) Gen.builder.branch(AfterBB) Gen.builder.position_at_start(AfterBB)