//! Match/expr-block lowering for JSON v0 bridge. use super::merge::new_block; use super::BridgeEnv; use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId}; use super::super::ast::{ExprV0, MatchArmV0}; use super::expr::{lower_expr_with_scope, VarScope}; pub(super) fn lower_match_expr_with_scope( env: &BridgeEnv, f: &mut MirFunction, cur_bb: BasicBlockId, scrutinee: &ExprV0, arms: &[MatchArmV0], else_expr: &ExprV0, vars: &mut S, ) -> Result<(ValueId, BasicBlockId), String> { // Evaluate scrutinee let (scr_val, start_bb) = lower_expr_with_scope(env, f, cur_bb, scrutinee, vars)?; // Set up blocks let dispatch_bb = new_block(f); if let Some(bb) = f.get_block_mut(start_bb) { if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, start_bb, dispatch_bb); } } let else_bb = new_block(f); let merge_bb = new_block(f); // Chain dispatch over arms let mut cur_dispatch = dispatch_bb; let mut phi_inputs: Vec<(BasicBlockId, ValueId)> = Vec::new(); for (i, arm) in arms.iter().enumerate() { let then_bb = new_block(f); let next_dispatch = if i + 1 < arms.len() { Some(new_block(f)) } else { None }; let fall_bb = next_dispatch.unwrap_or(else_bb); // Pre-allocate ids to avoid double borrow let ldst = f.next_value_id(); let cond = f.next_value_id(); if let Some(bb) = f.get_block_mut(cur_dispatch) { // compare scr_val == label bb.add_instruction(MirInstruction::Const { dst: ldst, value: ConstValue::String(arm.label.clone()) }); } crate::mir::ssot::cf_common::emit_compare_func(f, cur_dispatch, cond, CompareOp::Eq, scr_val, ldst); crate::mir::ssot::cf_common::set_branch(f, cur_dispatch, cond, then_bb, fall_bb); // Then arm body let (tval, tend) = lower_expr_with_scope(env, f, then_bb, &arm.expr, vars)?; if let Some(bb) = f.get_block_mut(tend) { if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb); } } phi_inputs.push((tend, tval)); cur_dispatch = fall_bb; } // Else body let (eval, eend) = lower_expr_with_scope(env, f, else_bb, else_expr, vars)?; if let Some(bb) = f.get_block_mut(eend) { if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb); } } phi_inputs.push((eend, eval)); // Merge result let out = f.next_value_id(); // フェーズM.2: PHI統一処理(no_phi分岐削除) let inputs = phi_inputs; crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs); Ok((out, merge_bb)) }