import t, c from stdint import * import ast import llvmlite import memhub import string import viperlib import lib.core.Gen.Translator as HT import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator # ============================================================ # MatchGenMixin - match 语句翻译 Mixin(P6 方法化) # ============================================================ # match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) define MAX_MATCH_CASES = 32 # 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) define SCOPE_MATCH = 6 # match 翻译最大递归深度(match → case body → translate_value → 嵌套 match)。 # 入口计数出口递减,超限即 fail-fast:AST 自引用环可致无限递归 → 栈溢出。 define MATCH_TRANSLATE_MAX_DEPTH = 64 novirtual class MatchGenMixin: """match 语句翻译 Mixin(P6 方法化)""" # _case_tail_unreachable - case 体末尾结构性不可达判定 # case 体翻译后当前块未终止、且末句是控制流语句(If/While/For/Match)且其 # merge 结构性不可达(全分支 return)时,当前块即该 merge(无 terminator), # 与 HandlesIf L309-315 / ClassGenVTable L1084 同语义补 unreachable。 # 返回 1=已补 unreachable(调用方不应 br end_bb);0=正常收尾(应 br end_bb)。 # 不含 Try/With:其处理器不维护 _ctrl_merge_reachable,避免残留值误判。 Gen: Generator.Generator* def _case_tail_unreachable(self, trans: HT.Translator*, builder: llvmlite.IRBuilder*, body_list: list[ast.AST*]*) -> int: if trans is None or builder is None: return 0 if llvmlite.builder_cur_block_is_terminated(builder) != 0: return 0 if body_list is None or len(body_list) == 0: return 0 lst: ast.AST* = body_list.get(len(body_list) - 1) if lst is None: return 0 lk: int = lst.kind() if lk != ast.ASTKind.If and lk != ast.ASTKind.While \ and lk != ast.ASTKind.For and lk != ast.ASTKind.Match: return 0 if trans._ctrl_merge_reachable != 0: return 0 llvmlite.build_unreachable(builder) return 1 # ============================================================ # translate_match - match 语句主入口,返回 0 # (迁移自 HandlesMatch.MatchHandle.Handle) # ============================================================ def translate_match(self, trans: HT.Translator*, node: ast.AST*) -> int: """match 语句翻译主入口(深度守卫包装器,原逻辑见 _translate_match_impl)""" if trans is not None: if trans.MatchTranslateDepth >= MATCH_TRANSLATE_MAX_DEPTH: self.Gen.TypeGenErr.fatal_error(node, "match 翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError") trans.MatchTranslateDepth += 1 mret: int = self._translate_match_impl(trans, node) if trans is not None: trans.MatchTranslateDepth -= 1 return mret def _translate_match_impl(self, trans: HT.Translator*, node: ast.AST*) -> int: if node is None: return 0 pool: memhub.MemBuddy* = trans.Pool builder: llvmlite.IRBuilder* = trans._cur_builder func: llvmlite.Function* = trans._cur_func if builder is None or func is None: return 0 # match merge 可达性重置(分派前初始化为 0)。标志必须由各处理函数 # (_handle_renum_match/_handle_sequence_match/_handle_simple_match) # 内部声明并收尾覆盖:声明在 Handle 这里会退化为隐式全局,跨 match 污染。 trans._ctrl_merge_reachable = 0 m_node: ast.Match* = ast.Match*(node) # 1. 求值 subject subject_node: ast.AST* = m_node.subject if subject_node is None: return 0 # 序列匹配(match (a, b): case (x, y): ...)走独立路径: # Tuple/List subject 无法用 translate_value 求值(会返回 None), # 提前分派到 _handle_sequence_match,避免 fail-fast 误报。 sk_seq: int = subject_node.kind() if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List: return self._handle_sequence_match(trans, m_node, subject_node) subject_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, subject_node, trans._funcs, trans._func_count, trans) if subject_val is None: # fail-fast: match subject 翻译失败 self.Gen.TypeGenErr.fatal_error(subject_node, "match subject 翻译失败", "TypeError") # 2. 检测是否 REnum match is_renum: int = 0 renum_name: str = None subject_ptr: llvmlite.Value* = None # 2a. 若 subject 是 Name,查变量注解类名 if subject_node.kind() == ast.ASTKind.Name: nm: ast.Name* = ast.Name*(subject_node) if nm.id is not None: entry: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(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 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) # 2b. 若未确定,遍历 cases 查 MatchClass 变体 if is_renum == 0: cases_list: list[ast.AST*]* = m_node.cases if cases_list is not None: cn: sizet = len(cases_list) ci: int = 0 while ci < cn and is_renum == 0: case_node: ast.AST* = cases_list.get(ci) if case_node is not None \ and case_node.kind() == ast.ASTKind.MatchCase: mc: rawptr[ast.MatchCase] = (rawptr[ast.MatchCase])(case_node) pat: ast.AST* = mc.pattern if pat is not None \ 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 or self.Gen.ClassGenEnum._is_renum_by_entry(rnm) != 0): is_renum = 1 renum_name = rnm if subject_ptr is None: subject_ptr = subject_val ci = ci + 1 # 3. 分派 if is_renum != 0 and subject_ptr is not None: return self._handle_renum_match(trans, m_node, renum_name, subject_ptr) return self._handle_simple_match(trans, m_node, subject_val) # ============================================================ # _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名 # # LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType' # llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType' # Ptr -> Name('Ptr') -> 遍历查找 # ============================================================ def _extract_renum_name_from_cls(self, pattern: ast.AST*) -> str: if pattern is None: return None mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pattern) cls_node: ast.AST* = mc.cls if cls_node is None: return None # Attribute 形式 if cls_node.kind() == ast.ASTKind.Attribute: at: ast.Attribute* = ast.Attribute*(cls_node) if at.value is not None: if at.value.kind() == ast.ASTKind.Name: inner_nm: ast.Name* = ast.Name*(at.value) return inner_nm.id if at.value.kind() == ast.ASTKind.Attribute: inner_at: ast.Attribute* = (ast.Attribute*)(at.value) return inner_at.attr # Name 形式:遍历所有 REnum 类反查 if cls_node.kind() == ast.ASTKind.Name: nm: ast.Name* = ast.Name*(cls_node) return self._find_renum_class_for_variant(nm.id) return None # ============================================================ # _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名 # ============================================================ def _extract_variant_name_from_cls(self, pattern: ast.AST*) -> str: if pattern is None: return None mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pattern) cls_node: ast.AST* = mc.cls if cls_node is None: return None if cls_node.kind() == ast.ASTKind.Attribute: at: ast.Attribute* = ast.Attribute*(cls_node) return at.attr if cls_node.kind() == ast.ASTKind.Name: nm: ast.Name* = ast.Name*(cls_node) return nm.id return None # ============================================================ # _find_renum_class_for_variant - 从变体名反查 REnum 类名 # # P5-2 后 REnum 变体表迁入 gen 字段(RenumClassNames/RenumClassCount), # 模块级 _renum_class_* 已失效,统一委托到 gen._lookup_renum_variant。 # ============================================================ def _find_renum_class_for_variant(self, variant_name: str) -> str: if variant_name is None: return None return self.Gen.ClassGenEnum._lookup_renum_variant(variant_name) # ============================================================ # _has_no_break - 检测 case body 是否含 c.NoBreak() 调用 # # 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak'))) # ============================================================ def _has_no_break(self, body_list: list[ast.AST*]*) -> int: if body_list is None: return 0 n: sizet = len(body_list) i: int = 0 while i < n: stmt: ast.AST* = body_list.get(i) if stmt is not None and stmt.kind() == ast.ASTKind.Expr: expr_node: rawptr[ast.Expr] = rawptr[ast.Expr](stmt) val: ast.AST* = expr_node.value if val is not None and val.kind() == ast.ASTKind.Call: call_node: ast.Call* = ast.Call*(val) fn: ast.AST* = call_node.func if fn is not None and fn.kind() == ast.ASTKind.Attribute: at: ast.Attribute* = (ast.Attribute*)(fn) if at.value is not None \ and at.value.kind() == ast.ASTKind.Name: base_nm: ast.Name* = (ast.Name*)(at.value) if base_nm.id is not None \ and string.strcmp(base_nm.id, "c") == 0 \ and at.attr is not None \ and string.strcmp(at.attr, "NoBreak") == 0: return 1 i = i + 1 return 0 # ============================================================ # _handle_renum_match - REnum 路径 # # 1. bitcast subject 到 i32* 读 __tag # 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表 # 3. 发射 build_switch # 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定) # ============================================================ def _handle_renum_match(self, trans: HT.Translator*, node: ast.Match*, renum_name: str, subject_ptr: llvmlite.Value*) -> int: pool: memhub.MemBuddy* = trans.Pool builder: llvmlite.IRBuilder* = trans._cur_builder func: llvmlite.Function* = trans._cur_func # 局部记录本 renum match 是否有 br 进入 end_bb,收尾时覆盖 # _ctrl_merge_reachable(case 体内嵌套 If 无 else + return 会把全局 # 标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾 # fail-fast "流程掉出末尾"。声明必须在本函数内——放 Handle 分派 # 函数里会使本函数引用退化为隐式全局,跨 match 污染)。 rm_merge_reach: int = 0 # 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针 # (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm) # 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T* # 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64) # → alloca REnum 结构体 + store 值 + 用 alloca 指针 # 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针 subj_ty: llvmlite.LLVMType* = subject_ptr.Ty if subj_ty is not None and self.Gen.ExprGenBase.is_ptr_type(subj_ty) != 0 \ and subj_ty.Pointee != 0 \ and self.Gen.ExprGenBase.is_ptr_type(subj_ty.Pointee) != 0: # 情况1: T** → load 一次得 T* loaded_sub: llvmlite.Value* = llvmlite.build_load(builder, subj_ty.Pointee, subject_ptr) if loaded_sub is not None: subject_ptr = loaded_sub # 情况2: 值型 subject(非指针)→ inttoptr 转回指针 # 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针), # 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store if subject_ptr.Ty is None or self.Gen.ExprGenBase.is_ptr_type(subject_ptr.Ty) == 0: renum_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(renum_name) renum_sty: llvmlite.LLVMType* = None if renum_se is not None: renum_sty = renum_se.Ty if renum_sty is None: # fail-fast: REnum 结构体未注册,无法构造 self.Gen.TypeGenErr.fatal_error(node, f"REnum 结构体 '{renum_name}' 未注册", "NameError") i64_ty0: llvmlite.LLVMType* = llvmlite.Int64(pool) int_val: llvmlite.Value* = subject_ptr # 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽) # 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值 if subj_ty is not None and self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) != 64 \ and self.Gen.ExprGenBase.is_ptr_type(subj_ty) == 0: if self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) > 64: int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0) else: int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0) renum_ptr_ty0: llvmlite.LLVMType* = llvmlite.Ptr(pool, renum_sty) subj_ptr0: llvmlite.Value* = llvmlite.build_inttoptr(builder, int_val, renum_ptr_ty0) if subj_ptr0 is not None: subject_ptr = subj_ptr0 # 1. bitcast subject 到 __tag* 读 __tag # tag 的**类型**取 __tag 的字段声明类型(FieldEntry.Ty),与 kind() # (CallGenDispatch)和变体构造共用同一真源,不再各自硬编码 i32; # 下方 case 常量(ConstInt)同用 tag_ty ⇒ 将来 __tag 换宽度时 # 读 / 写 / 比较三侧自动跟随。(默认 i32 仅当字段条目取不到时的等效值: # __tag 全仓唯一写入点是 ClassGenEnum:1009 add_field(entry,"__tag",Int32)。) tag_ty: llvmlite.LLVMType* = llvmlite.Int32(pool) tag_se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(renum_name) if tag_se is not None and tag_se.Ty is not None: tag_fe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(tag_se.Ty, "__tag") if tag_fe is not None and tag_fe.Ty is not None: tag_ty = tag_fe.Ty tag_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, tag_ty) tag_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, subject_ptr, tag_ptr_ty) if tag_ptr is None: # fail-fast: REnum tag 指针转换失败 self.Gen.TypeGenErr.fatal_error(node, "REnum tag 指针转换失败", "TypeError") tag_val: llvmlite.Value* = llvmlite.build_load(builder, tag_ty, tag_ptr) if tag_val is None: # fail-fast: REnum tag 读取失败 self.Gen.TypeGenErr.fatal_error(node, "REnum tag 读取失败", "TypeError") # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 name_buf: str = pool.alloc(32) if name_buf is None: # fail-fast: 标签缓冲区分配失败 self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) # 3. 准备收集数组(用 CSizeT 数组存指针) cases_list: list[ast.AST*]* = node.cases if cases_list is None: # fail-fast: match cases 缺失 self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") case_count: sizet = len(cases_list) # BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组 bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) # pass1 缓存的 mc 指针数组(pass2 复用,避免重索引) mc_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None \ or mc_arr is None: # fail-fast: match 分派数组分配失败 self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") collected: int = 0 has_default: int = 0 # 穷尽臂(`case _`)节点:pass1 显式记录,default 块直接翻译 default_case_node: ast.AST* = None # SwitchCase 链表 sw_head: rawptr[llvmlite.SwitchCase] = None sw_tail: rawptr[llvmlite.SwitchCase] = None sw_count: int = 0 # 应提交 case 的臂计数(非 default 且模式必须产出 case 值:MatchClass # 必有变体 tag / MatchValue 必有常量值);与 sw_count 不等即静默丢 case, # build_switch 前 fail-fast(见 step 5 前的硬校验)。 need_case: int = 0 # 修复: 未取到 case 值的臂诊断串(供硬校验报错打印 臂序号/变体名/tag) # 容量 = 8 条 × 单条上限(diag_tmp 128,strcat 无边界检查 → 必须够大) miss_buf: str = pool.alloc(1088) diag_tmp: str = pool.alloc(128) if miss_buf is None or diag_tmp is None: # fail-fast: 诊断缓冲区分配失败(与上方 name_buf 同款处理) self.Gen.TypeGenErr.fatal_error(node, "match 诊断缓冲区分配失败", "TypeError") miss_buf[0] = '\0' miss_cnt: int = 0 # 变体表 RenumClassNames 按裸类名注册(ClassDef.name),而 renum_name 来自 # 注解书写形态(Spec.SourceName,Attribute 会带模块限定名 "mod.LLVMType")→ # 精确 strcmp 失配恒 -1 → 该臂被静默丢弃。故先去模块前缀(复用 find_struct # 同款「括号外取点」判定,泛型下标内的点不算)。 tag_cls_bare: str = renum_name rn_dot: str = self.Gen.StructGen._last_dot_outside_brackets(renum_name) if rn_dot is not None and rn_dot[1] != '\0': tag_cls_bare = rn_dot + 1 # 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表 i: int = 0 while i < case_count: case_node: ast.AST* = cases_list.get(i) if case_node is None: i = i + 1 continue if case_node.kind() != ast.ASTKind.MatchCase: i = i + 1 continue mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node) pat: ast.AST* = mc.pattern is_def: int = 0 cv: llvmlite.Value* = None # 修复: 提升到臂作用域(原先声明在 MatchClass 分支内),供下方 # "未取到 case 值"诊断打印变体名/tag vnm: str = None tag: int = -1 if pat is not None: pk: int = pat.kind() if pk == ast.ASTKind.MatchClass: vnm = self._extract_variant_name_from_cls(pat) if vnm is not None: # 先用裸类名查表(变体表按裸类名注册,与模式侧 2b 路径同口径); # 失败再用注解书写形态重试(泛型特化 mangled 名确需带点)。 # 两者都失败 → tag=-1 → step 5 前的硬校验 fail-fast。 tag = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(tag_cls_bare, vnm) if tag < 0 and string.strcmp(tag_cls_bare, renum_name) != 0: tag = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(renum_name, vnm) if tag >= 0: tag_buf: str = pool.alloc(32) if tag_buf is not None: viperlib.snprintf(tag_buf, 32, "%d", tag) cv = llvmlite.ConstInt(pool, tag_ty, tag, tag_buf if tag_buf is not None else "0") elif pk == ast.ASTKind.MatchAs: ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat) if ma.pattern is None: is_def = 1 has_default = 1 default_case_node = case_node elif pk == ast.ASTKind.MatchValue: mv: rawptr[ast.MatchValue] = rawptr[ast.MatchValue](pat) cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans) elif pk == ast.ASTKind.MatchOr: # MatchOr: 多个值共享一个 BB(取第一个值做 case) mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat) pats: list[ast.AST*]* = mo.patterns if pats is not None and len(pats) > 0: first_pat: ast.AST* = pats.get(0) if first_pat is not None \ and first_pat.kind() == ast.ASTKind.MatchValue: mv2: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(first_pat) cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv2.value, trans._funcs, trans._func_count, trans) # 创建 case BB if is_def == 0: if collected >= MAX_MATCH_CASES: break viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) else: bb = default_bb # 检测 NoBreak body_list: list[ast.AST*]* = mc.children nb: int = self._has_no_break(body_list) # 存入数组 if collected < MAX_MATCH_CASES: bb_arr[collected] = sizet(bb) cv_arr[collected] = sizet(cv) def_arr[collected] = is_def nb_arr[collected] = nb # 缓存 mc 指针(pass2 复用,避免重索引) mc_arr[collected] = sizet(mc) collected = collected + 1 # 计入"必须提交 case"的臂(MatchClass 必有变体 tag、MatchValue 必有 # 常量值);必须在 MAX_MATCH_CASES 上限判定之后计数(超上限的臂已 # break,不参与校验)。 if is_def == 0 and pat is not None: pkm: int = pat.kind() if pkm == ast.ASTKind.MatchClass or pkm == ast.ASTKind.MatchValue: need_case = need_case + 1 # 构建 SwitchCase 链表(非 default case 且有值) if is_def == 0 and cv is not None: sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, cv, bb) if sc is not None: if sw_head is None: sw_head = sc sw_tail = sc else: sw_tail.Next = sc sw_tail = sc sw_count = sw_count + 1 # 记录"应产出 case 值但未产出"的臂(MatchClass 变体 tag 查表失败 / # MatchValue 常量翻译失败)。此处只收集诊断,是否致命由 step 5 前的 # 硬校验统一判定(口径唯一)。 if is_def == 0 and cv is None and miss_cnt < 8 and pat is not None: pkm_d: int = pat.kind() if pkm_d == ast.ASTKind.MatchClass or pkm_d == ast.ASTKind.MatchValue: viperlib.snprintf(diag_tmp, 128, " #%d(%s,tag=%d)", i, vnm if vnm is not None else "?", tag) string.strcat(miss_buf, diag_tmp) miss_cnt = miss_cnt + 1 i = i + 1 # 5. 发射 switch 指令 # 禁止静默丢 case:必须提交 case 的臂数(MatchClass/MatchValue,非 default) # 必须等于实际提交给 build_switch 的 sw_count。不等即该臂 case 值未算出 # (REnum 变体 tag 查表失败最常见)→ build_switch 发射空 case 列表、臂体 # 结构性不可达。故不等即 fail-fast,打印类名/查表名/应提交数/实际数/ # 各未取到值臂的 序号(变体名,tag),便于定位变体表失配。 if need_case != sw_count: self.Gen.TypeGenErr.fatal_error(node, f"REnum match 分派丢失 case:class='{renum_name}'(查表名='{tag_cls_bare}')应提交 {need_case} 个 case,实际提交 {sw_count} 个;未取到值的臂:{miss_buf}", "InternalCompilerError") 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 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 while i < collected: # pass2 用 pass1 缓存的 mc(避免重索引错位) mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_arr[i]) if mc is None: i = i + 1 continue pat: ast.AST* = mc.pattern # 取 BB bb_addr: sizet = bb_arr[i] case_bb: rawptr[llvmlite.BasicBlock] = (rawptr[llvmlite.BasicBlock])(bb_addr) is_def: int = def_arr[i] nb: int = nb_arr[i] # default case 的 body 在 step 8 单独翻译,这里跳过避免重复 if is_def == 1: i = i + 1 continue # 定位到 case BB llvmlite.position_at_end(builder, case_bb) # 进入 case 作用域(变体字段绑定隔离) self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) # 变体字段绑定(MatchClass) 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 if body_list is not None: bc: sizet = len(body_list) bi: int = 0 while bi < bc: # 用 list.get() 读取元素值(已验证编译为 8 字节加载,与 # pass1 的 cases_list.get(i) 同型同码)。切勿改为 # `bl_data + bi*8` 裸地址:那会把数组槽地址当节点传入 # translate_stmt,虚调用跳进 vtable 表 → DEP 崩溃。 stmt: ast.AST* = body_list.get(bi) if stmt is not None: self.Gen.StmtGen.translate_stmt(trans, stmt) bi = bi + 1 # 退出 case 作用域 self.Gen.VarGen.exit_scope(trans.SymTab) # 若未终止且无 NoBreak,跳到 end # 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ and nb == 0 \ and self._case_tail_unreachable(trans, builder, body_list) == 0: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 rm_merge_reach = 1 i = i + 1 # 8. 处理 default 块 llvmlite.position_at_end(builder, default_bb) if has_default == 0 or default_case_node is None: # 无显式 default:default 直接跳 end(match 不穷尽 ⇒ merge 可达) if llvmlite.builder_cur_block_is_terminated(builder) == 0: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 rm_merge_reach = 1 else: # 有显式 default:直接翻译 pass1 记录的 `case _` 臂 # (不再经 def_arr 槽位反查 cases_list:collected 下标与原始下标 # 在"有臂被跳过"时会错位,default_bb 随之空转) dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node) self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) # dbody 预声明+重赋值会使 .get 误分派成 list[int].get # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。 # 用 dbody3 内联声明接收者遍历(对齐 Converter arg_defaults 规避模式)。 dbody3: list[ast.AST*]* = dmc_d.children if dbody3 is not None: dn3: sizet = len(dbody3) dj3: int = 0 while dj3 < dn3: stmt3: ast.AST* = dbody3.get(dj3) if stmt3 is not None: self.Gen.StmtGen.translate_stmt(trans, stmt3) dj3 = dj3 + 1 self.Gen.VarGen.exit_scope(trans.SymTab) # 末句控制流全 return → 补 unreachable(不 br end_bb) if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ and self._case_tail_unreachable(trans, builder, dbody3) == 0: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 rm_merge_reach = 1 # 9. 定位到 end 块 llvmlite.position_at_end(builder, end_bb) # 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对 # _ctrl_merge_reachable 的污染(全 case return 时应为不可达) trans._ctrl_merge_reachable = rm_merge_reach return 0 # ============================================================ # _bind_variant_fields - 绑定 MatchClass 的变体字段 # # case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段 # ============================================================ def _bind_variant_fields(self, pat: ast.AST*, renum_name: str, renum_entry: GenTypes.StructEntry*, renum_ty: llvmlite.LLVMType*, subject_ptr: llvmlite.Value*, trans: HT.Translator*, pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*): if pat is None or renum_entry is None or renum_ty is None: return mc: rawptr[ast.MatchClass] = rawptr[ast.MatchClass](pat) pats: list[ast.AST*]* = mc.patterns if pats is None: return # bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配) renum_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, renum_ty) casted_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, subject_ptr, renum_ptr_ty) if casted_ptr is None: casted_ptr = subject_ptr pn: sizet = len(pats) for j in range(pn): sub_pat: ast.AST* = pats.get(j) if sub_pat is not None and sub_pat.kind() == ast.ASTKind.MatchAs: ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](sub_pat) bind_name: str = ma.name if bind_name is not None: # 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1 # 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配) payload_idx: int = j + 1 # 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中) if payload_idx >= renum_entry.FieldCount: # class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name # (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool 指针); # renum_name(AnnotClassName 等)是不同指针,恒不匹配 → 误报 fail-fast。 alt_idx: int = self.Gen.ClassGenEnum._lookup_renum_field_alias(renum_entry.Name, bind_name) if alt_idx >= 1: payload_idx = alt_idx else: # fail-fast: payload 越界且别名查找失败 # (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat # 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在 # 运行时求值才报错,TPV 惰性编译方法体时即 NameError) self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", "TypeError") # 获取字段类型 fe: GenTypes.FieldEntry* = (self.Gen.StructGen._get_field_entry(renum_entry, payload_idx)) field_ty: llvmlite.LLVMType* = None if fe is not None: field_ty = fe.Ty if field_ty is None: # fail-fast: 变体字段类型缺失,禁止兜底 i8 self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段类型缺失: {bind_name}", "TypeError") # GEP 取字段地址 elem_ptr: llvmlite.Value* = llvmlite.build_gep_struct(builder, renum_ty, field_ty,casted_ptr, payload_idx) if elem_ptr is None: # fail-fast: 变体字段地址计算失败 self.Gen.TypeGenErr.fatal_error(sub_pat, f"REnum 变体字段 '{bind_name}' 地址计算失败", "TypeError") # 变体成员实际类型(对齐 TPC class_members):注册时别名表存了成员 # 注解解析出的类型(perm_pool 深拷贝),用它把槽位地址 bitcast 成 # Ptr(成员类型),使绑定变量按成员类型读 payload(否则按槽位 i64 读 → # is 比较/下标/strlen 等字符串操作翻译失败)。 # 必须按 (class, 变体名, 位置) 定位:MatchAs 名是局部变量名而非字段名, # 按字段名查恒不匹配;同一 payload 位置跨变体类型也不同。 # 自引用类型注册期解析失败 → 查不到类型时回退槽位类型。 mem_ty_m: llvmlite.LLVMType* = None vnt_m: str = self._extract_variant_name_from_cls(pat) if vnt_m is not None and renum_entry is not None \ and renum_entry.Name is not None: mem_ty_m = self.Gen.ClassGenEnum._lookup_renum_member_ty(renum_entry.Name, vnt_m, payload_idx) if mem_ty_m is not None: mem_ptr_m: llvmlite.LLVMType* = llvmlite.Ptr(pool, mem_ty_m) if mem_ptr_m is not None: cast_m: llvmlite.Value* = llvmlite.build_bitcast(builder, elem_ptr, mem_ptr_m) if cast_m is not None: elem_ptr = cast_m self.Gen.VarGen.define_var(trans.SymTab, bind_name, elem_ptr) # ============================================================ # _seq_cmp_eq - 序列匹配元素相等比较 # # 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后 # 生成 icmp eq,返回 i1 条件。 # ============================================================ def _seq_cmp_eq(self, trans: HT.Translator*, builder: llvmlite.IRBuilder*, lhs: llvmlite.Value*, rhs: llvmlite.Value*) -> llvmlite.Value*: """对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)""" if lhs is None or rhs is None or builder is None: return None pool: memhub.MemBuddy* = trans.Pool if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0 \ or self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool) if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0: lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) if self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) lb: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty) rb: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty) if lb != rb and lb != 0 and rb != 0: if lb < rb: if lb == 1: lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) else: lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) else: if rb == 1: rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) else: rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs) # ============================================================ # _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...) # # subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python # 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行): # 元素 pattern: # MatchValue v → subject[i] == v # MatchAs(pattern=None) → _ 通配(恒真) # MatchStar → 剩余元素通配(恒真) # IR 结构(check/body 链): # entry → check0 # check_i: 匹配条件 → body_i(不满足 → check_{i+1}) # body_i: → end(c.NoBreak 时 fallthrough 到下一 case body) # 全不匹配 → default → end # ============================================================ def _handle_sequence_match(self, trans: HT.Translator*, node: ast.Match*, subject_node: ast.AST*) -> int: pool: memhub.MemBuddy* = trans.Pool builder: llvmlite.IRBuilder* = trans._cur_builder func: llvmlite.Function* = trans._cur_func if builder is None or func is None: return 0 # 同主路径:局部记录本 sequence match 的 br end_bb,收尾覆盖 # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 sq_merge_reach: int = 0 # 1. 求值 subject 各元素 elts: list[ast.AST*]* = None if subject_node.kind() == ast.ASTKind.Tuple: st: ast.Tuple* = ast.Tuple*(subject_node) if st is not None: elts = st.elts elif subject_node.kind() == ast.ASTKind.List: sl2: ast.List* = ast.List*(subject_node) if sl2 is not None: elts = sl2.elts if elts is None: return 0 ecount: sizet = len(elts) if ecount == 0: return 0 subj_vals: sizet* = pool.alloc(8 * ecount) if subj_vals is None: return 0 for ei in range(ecount): # elts 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断); # 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式) elts_inl: list[ast.AST*]* = elts elt: ast.AST* = elts_inl.get(ei) sv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, elt, trans._funcs, trans._func_count, trans) if sv is None: self.Gen.TypeGenErr.fatal_error(elt, f"match 序列元素 {ei} 翻译失败", "TypeError") subj_vals[ei] = sizet(sv) # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 name_buf: str = pool.alloc(32) if name_buf is None: return 0 viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt) default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt) end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) # 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard) cases_list: list[ast.AST*]* = node.cases if cases_list is None: return 0 case_count: sizet = len(cases_list) check_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) body_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) guard_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) if check_arr is None or body_arr is None or def_arr is None \ or nb_arr is None or guard_arr is None: return 0 collected: int = 0 has_default: int = 0 # 穷尽臂(`case _`)节点:pass1 显式记录,default 块直接翻译 default_case_node: ast.AST* = None first_check: int = -1 i: int = 0 while i < case_count: # 容量防线(与 _translate_match_simple / match-list 路径的 # `collected < MAX_MATCH_CASES` 守卫对齐):默认 case(case _)分支也须校验 # collected 再写 check_arr/body_arr/def_arr/nb_arr/guard_arr[collected], # 否则 case 数超 MAX_MATCH_CASES 会越界写穿 pool 相邻块。超限直接 # fail-fast,不静默丢弃 case。 if collected >= MAX_MATCH_CASES: self.Gen.TypeGenErr.fatal_error(node, f"match case 数量超过上限 MAX_MATCH_CASES={MAX_MATCH_CASES}", "OverflowError") break case_node: ast.AST* = cases_list.get(i) if case_node is None or case_node.kind() != ast.ASTKind.MatchCase: i = i + 1 continue mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node) pat: ast.AST* = mc.pattern is_def: int = 0 if pat is not None: pk: int = pat.kind() if pk == ast.ASTKind.MatchAs: ma0: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat) if ma0.pattern is None: is_def = 1 elif pk != ast.ASTKind.MatchSequence: # fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配 self.Gen.TypeGenErr.fatal_error(pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError") if is_def == 1: has_default = 1 default_case_node = case_node check_arr[collected] = 0 body_arr[collected] = sizet(default_bb) else: if collected >= MAX_MATCH_CASES: break viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i) cbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i) bbb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) check_arr[collected] = sizet(cbb) body_arr[collected] = sizet(bbb) if first_check < 0: first_check = collected body_list: list[ast.AST*]* = mc.children nb: int = self._has_no_break(body_list) def_arr[collected] = is_def nb_arr[collected] = nb guard_arr[collected] = sizet(mc.guard) collected = collected + 1 i = i + 1 # 4. 入口 → 第一个 check(或 default/end) if first_check >= 0: head_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[first_check]) llvmlite.build_br(builder, head_bb) elif has_default == 1: llvmlite.build_br(builder, default_bb) else: llvmlite.build_br(builder, end_bb) # 5. 发射 check 链 ci: int = 0 while ci < collected: if def_arr[ci] == 1: ci = ci + 1 continue cbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](check_arr[ci]) bbb2: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci]) llvmlite.position_at_end(builder, cbb2) # 计算匹配条件(元素比较 && guard) cond: llvmlite.Value* = None cnode: ast.AST* = cases_list.get(ci) mc2: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](cnode) ms: rawptr[ast.MatchSequence] = (rawptr[ast.MatchSequence])(mc2.pattern) pats: list[ast.AST*]* = None if ms is not None: pats = ms.patterns pcount: sizet = 0 if pats is not None: pcount = len(pats) if pcount != ecount: # 元素数量不匹配 → 恒假(对齐 Python 语义) cond = llvmlite.const_int(pool, 1, 0) else: for pi in range(ecount): # pats 预声明+重赋值会把 .get 误分派成 list[int].get(i32 截断); # 用内联别名接收者规避(对齐 Converter arg_defaults 内联模式) pats_inl: list[ast.AST*]* = pats pat1: ast.AST* = pats_inl.get(pi) if pat1 is None: continue pk1: int = pat1.kind() if pk1 == ast.ASTKind.MatchValue: mv: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(pat1) pv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans) if pv is None: self.Gen.TypeGenErr.fatal_error(pat1, f"序列模式元素 {pi} 翻译失败", "TypeError") sv1: llvmlite.Value* = llvmlite.Value*(subj_vals[pi]) c1: llvmlite.Value* = self._seq_cmp_eq(trans, builder, sv1, pv) if c1 is None: self.Gen.TypeGenErr.fatal_error(pat1, "序列模式元素比较失败", "TypeError") if cond is None: cond = c1 else: cond = llvmlite.build_and(builder, cond, c1) elif pk1 == ast.ASTKind.MatchAs: ma2: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat1) if ma2.pattern is None: continue # _ 通配:恒真 if ma2.name is not None: # fail-fast:序列模式变量绑定暂不支持 self.Gen.TypeGenErr.fatal_error(pat1, "序列模式变量绑定暂不支持", "NotImplementedError") elif pk1 == ast.ASTKind.MatchStar: continue # 剩余元素通配:恒真 else: self.Gen.TypeGenErr.fatal_error(pat1, "序列模式不支持的 pattern 类型", "TypeError") # guard(若有):匹配成立且 guard 非零 g_addr: sizet = guard_arr[ci] if g_addr != 0: gnode: ast.AST* = (ast.AST*)(g_addr) gv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, gnode, trans._funcs, trans._func_count, trans) if gv is None: self.Gen.TypeGenErr.fatal_error(gnode, "match guard 翻译失败", "TypeError") gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty) if gbits == 1: g1: llvmlite.Value* = gv else: gzero: llvmlite.Value* = llvmlite.const_int(pool, gbits if gbits > 0 else 32, 0) g1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, gv, gzero) if cond is None: cond = g1 else: cond = llvmlite.build_and(builder, cond, g1) if cond is None: cond = llvmlite.const_int(pool, 1, 1) # 下一个 check(或 default/end) nxt: rawptr[llvmlite.BasicBlock] = None nj: int = ci + 1 while nj < collected and def_arr[nj] == 1: nj = nj + 1 if nj < collected: nxt = rawptr[llvmlite.BasicBlock](check_arr[nj]) elif has_default == 1: nxt = default_bb else: nxt = end_bb llvmlite.build_cond_br(builder, cond, bbb2, nxt) ci = ci + 1 # 6. 翻译 case body ci = 0 while ci < collected: if def_arr[ci] == 1: ci = ci + 1 continue bbb3: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[ci]) llvmlite.position_at_end(builder, bbb3) cnode2: ast.AST* = cases_list.get(ci) mc3: rawptr[ast.MatchCase] = (rawptr[ast.MatchCase])(cnode2) self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) body_list2: list[ast.AST*]* = mc3.children if body_list2 is not None: bc: sizet = len(body_list2) bi: int = 0 while bi < bc: stmt: ast.AST* = body_list2.get(bi) if stmt is not None: self.Gen.StmtGen.translate_stmt(trans, stmt) bi = bi + 1 self.Gen.VarGen.exit_scope(trans.SymTab) # 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough) if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ and self._case_tail_unreachable(trans, builder, body_list2) == 0: if nb_arr[ci] == 0: llvmlite.build_br(builder, end_bb) else: # c.NoBreak:fallthrough 到下一个 case body(跳过模式检查) nj2: int = ci + 1 while nj2 < collected and def_arr[nj2] == 1: nj2 = nj2 + 1 if nj2 < collected: nbb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](body_arr[nj2]) llvmlite.build_br(builder, nbb) elif has_default == 1: llvmlite.build_br(builder, default_bb) else: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 sq_merge_reach = 1 ci = ci + 1 # 7. default 块 llvmlite.position_at_end(builder, default_bb) dbody: list[ast.AST*]* = None if has_default == 1 and default_case_node is not None: # 直接翻译 pass1 记录的 `case _` 臂(不再经 def_arr 槽位反查 cases_list: # collected 下标与原始下标在"有臂被跳过"时会错位,default_bb 随之空转) dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node) self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) # dbody 预声明+重赋值会使 .get 误分派成 list[int].get # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。 # 用 dbody3 内联声明接收者遍历(对齐 Converter arg_defaults 规避模式)。 dbody3: list[ast.AST*]* = dmc_d.children dbody = dbody3 if dbody3 is not None: dn3: sizet = len(dbody3) dj3: int = 0 while dj3 < dn3: stmt3: ast.AST* = dbody3.get(dj3) if stmt3 is not None: self.Gen.StmtGen.translate_stmt(trans, stmt3) dj3 = dj3 + 1 self.Gen.VarGen.exit_scope(trans.SymTab) # 末句控制流全 return → 补 unreachable(不 br end_bb) if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ and self._case_tail_unreachable(trans, builder, dbody) == 0: llvmlite.build_br(builder, end_bb) sq_merge_reach = 1 # 8. 定位到 end llvmlite.position_at_end(builder, end_bb) # 覆盖嵌套控制流污染(同主路径) trans._ctrl_merge_reachable = sq_merge_reach return 0 # ============================================================ # _handle_simple_match - 非 REnum 路径 # # subject ptrtoint 到 i32 + switch 分派 # ============================================================ def _handle_simple_match(self, trans: HT.Translator*, node: ast.Match*, subject_val: llvmlite.Value*) -> int: pool: memhub.MemBuddy* = trans.Pool builder: llvmlite.IRBuilder* = trans._cur_builder func: llvmlite.Function* = trans._cur_func # 同主路径:局部记录本 simple match 的 br end_bb,收尾覆盖 # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 sm_merge_reach: int = 0 # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool) subj_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(subject_val.Ty) subj_val: llvmlite.Value* = subject_val if subj_bits != 32: if self.Gen.ExprGenBase.is_ptr_type(subject_val.Ty) != 0: subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) elif subj_bits > 32: # trunc 到 i32 subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty) elif subj_bits == 0: # 未知类型,尝试 ptrtoint subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) if subj_val is None: # fail-fast: subject 转 i32 失败 self.Gen.TypeGenErr.fatal_error(node, "match subject 转换为 i32 失败", "TypeError") # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 name_buf: str = pool.alloc(32) if name_buf is None: # fail-fast: 标签缓冲区分配失败 self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) default_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) # 3. 收集 case 信息 cases_list: list[ast.AST*]* = node.cases if cases_list is None: # fail-fast: match cases 缺失 self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") case_count: sizet = len(cases_list) bb_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) cv_arr: sizet* = pool.alloc(8 * MAX_MATCH_CASES) def_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: int | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: # fail-fast: match 分派数组分配失败 self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") collected: int = 0 has_default: int = 0 # 穷尽臂(`case _`)的 MatchCase 节点:pass1 显式记录,step 7 直接使用。 # 不再依赖 def_arr 槽位反查(collected → cases_list 下标在"有臂被跳过" # 时会错位,default_bb 随之空转 → merge 误判可达 → 函数末句穷尽 match # 被误报"流程掉出函数末尾",同时 case _ 臂不生成 IR)。 default_case_node: ast.AST* = None sw_head: rawptr[llvmlite.SwitchCase] = None sw_tail: rawptr[llvmlite.SwitchCase] = None sw_count: int = 0 # 4. 第一遍:收集 + 创建 BB + 构建链表 i: int = 0 while i < case_count: case_node: ast.AST* = cases_list.get(i) if case_node is None: i = i + 1 continue if case_node.kind() != ast.ASTKind.MatchCase: i = i + 1 continue mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node) pat: ast.AST* = mc.pattern is_def: int = 0 cv: llvmlite.Value* = None if pat is not None: pk: int = pat.kind() if pk == ast.ASTKind.MatchValue: mv: rawptr[ast.MatchValue] = rawptr[ast.MatchValue](pat) cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans) elif pk == ast.ASTKind.MatchSingleton: ms: rawptr[ast.MatchSingleton] = (rawptr[ast.MatchSingleton])(pat) # None -> 0 cv = llvmlite.const_int32(pool, 0) elif pk == ast.ASTKind.MatchAs: ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat) if ma.pattern is None: is_def = 1 has_default = 1 default_case_node = case_node elif pk == ast.ASTKind.MatchOr: mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat) pats: list[ast.AST*]* = mo.patterns if pats is not None and len(pats) > 0: first_pat: ast.AST* = pats.get(0) if first_pat is not None \ and first_pat.kind() == ast.ASTKind.MatchValue: mv2: rawptr[ast.MatchValue] = (rawptr[ast.MatchValue])(first_pat) cv = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, mv2.value, trans._funcs, trans._func_count, trans) elif pk == ast.ASTKind.MatchClass: # 本路径(非 REnum 分派)不为 class-pattern 臂产出 case 值 → 该臂被 # 静默丢弃、臂体不可达。若该 class-pattern 确实指向已注册 REnum # (_is_renum_class_name / _is_renum_by_entry 命中),说明是 REnum # 分派失配,必须 fail-fast 暴露,不得静默丢 case(禁止兜底掩盖)。 rnm_nr: str = self._extract_renum_name_from_cls(pat) if rnm_nr is not None and (self.Gen.ClassGenEnum._is_renum_class_name(rnm_nr) != 0 or self.Gen.ClassGenEnum._is_renum_by_entry(rnm_nr) != 0): self.Gen.TypeGenErr.fatal_error(pat, f"非 REnum 路径收到 REnum 变体模式 'case {rnm_nr}.*':case 值无法产出,该臂会被静默丢弃(REnum 分派失配)", "InternalCompilerError") if is_def == 0: if collected >= MAX_MATCH_CASES: break viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf) else: bb = default_bb body_list: list[ast.AST*]* = mc.children nb: int = self._has_no_break(body_list) if collected < MAX_MATCH_CASES: bb_arr[collected] = sizet(bb) cv_arr[collected] = sizet(cv) def_arr[collected] = is_def nb_arr[collected] = nb collected = collected + 1 if is_def == 0 and cv is not None: sc: rawptr[llvmlite.SwitchCase] = llvmlite.new_switch_case(pool, cv, bb) if sc is not None: if sw_head is None: sw_head = sc sw_tail = sc else: sw_tail.Next = sc sw_tail = sc sw_count = sw_count + 1 i = i + 1 # 5. 发射 switch llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count) # 6. 第二遍:翻译 case body i = 0 while i < collected: case_node: ast.AST* = cases_list.get(i) if case_node is None: i = i + 1 continue mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node) bb_addr: sizet = bb_arr[i] case_bb: rawptr[llvmlite.BasicBlock] = rawptr[llvmlite.BasicBlock](bb_addr) is_def: int = def_arr[i] nb: int = nb_arr[i] # default case 的 body 在 step 7 单独翻译,这里跳过避免重复 if is_def == 1: i = i + 1 continue llvmlite.position_at_end(builder, case_bb) self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) body_list: list[ast.AST*]* = mc.children if body_list is not None: bc: sizet = len(body_list) bi: int = 0 while bi < bc: stmt: ast.AST* = body_list.get(bi) if stmt is not None: self.Gen.StmtGen.translate_stmt(trans, stmt) bi = bi + 1 self.Gen.VarGen.exit_scope(trans.SymTab) # 末句控制流全 return → 补 unreachable(不 br end_bb) if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ and nb == 0 \ and self._case_tail_unreachable(trans, builder, body_list) == 0: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 sm_merge_reach = 1 i = i + 1 # 7. default 块(含 `case _` 穷尽臂) llvmlite.position_at_end(builder, default_bb) if has_default == 0 or default_case_node is None: # 无显式 default:default 直接跳 end(match 不穷尽 ⇒ merge 可达) if llvmlite.builder_cur_block_is_terminated(builder) == 0: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 sm_merge_reach = 1 else: # 直接翻译 pass1 记录的 `case _` 臂(不再经 def_arr 槽位反查 cases_list: # collected 下标与原始下标在"有臂被跳过"时会错位,default_bb 随之空转) dmc_d: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](default_case_node) self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) # dbody 预声明+重赋值会使 .get 误分派成 list[int].get # (i32→inttoptr 截断指针 → translate_stmt 读垃圾节点崩溃,gen1 IR 证据)。 # 用 dbody3 内联声明接收者遍历(对齐 Converter arg_defaults 规避模式)。 dbody3: list[ast.AST*]* = dmc_d.children if dbody3 is not None: dn3: sizet = len(dbody3) dj3: int = 0 while dj3 < dn3: stmt3: ast.AST* = dbody3.get(dj3) if stmt3 is not None: self.Gen.StmtGen.translate_stmt(trans, stmt3) dj3 = dj3 + 1 self.Gen.VarGen.exit_scope(trans.SymTab) # 末句控制流全 return → 补 unreachable(不 br end_bb) if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ and self._case_tail_unreachable(trans, builder, dbody3) == 0: llvmlite.build_br(builder, end_bb) trans._ctrl_merge_reachable = 1 sm_merge_reach = 1 # 8. 定位到 end llvmlite.position_at_end(builder, end_bb) # 覆盖嵌套控制流污染(同主路径) trans._ctrl_merge_reachable = sm_merge_reach return 0