chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更

Phase 25.1 完了成果:
-  LoopForm v2 テスト・ドキュメント・コメント完備
  - 4ケース(A/B/C/D)完全テストカバレッジ
  - 最小再現ケース作成(SSAバグ調査用)
  - SSOT文書作成(loopform_ssot.md)
  - 全ソースに [LoopForm] コメントタグ追加

-  Stage-1 CLI デバッグ環境構築
  - stage1_cli.hako 実装
  - stage1_bridge.rs ブリッジ実装
  - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh)
  - アーキテクチャ改善提案文書

-  環境変数削減計画策定
  - 25変数の完全調査・分類
  - 6段階削減ロードマップ(25→5、80%削減)
  - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG)

Phase 26-D からの累積変更:
- PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等)
- MIRビルダーリファクタリング
- 型伝播・最適化パス改善
- その他約300ファイルの累積変更

🎯 技術的成果:
- SSAバグ根本原因特定(条件分岐内loop変数変更)
- Region+next_iパターン適用完了(UsingCollectorBox等)
- LoopFormパターン文書化・テスト化完了
- セルフホスティング基盤強化

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ChatGPT <noreply@openai.com>
Co-Authored-By: Task Assistant <task@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-21 06:25:17 +09:00
parent baf028a94f
commit f9d100ce01
366 changed files with 14322 additions and 5236 deletions

View File

@ -1,23 +1,23 @@
use super::ast::{ProgramV0, StmtV0, ExprV0};
use super::ast::{ExprV0, ProgramV0, StmtV0};
use crate::mir::Callee;
use crate::mir::{
BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction, MirInstruction, MirModule,
MirPrinter, MirType, ValueId,
BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction, MirInstruction,
MirModule, MirPrinter, MirType, ValueId,
};
use std::collections::HashMap;
use std::cell::RefCell;
use std::collections::HashMap;
// Split out merge/new_block helpers for readability (no behavior change)
mod merge;
use merge::{merge_var_maps, new_block};
// Feature splits (gradual extraction)
pub(super) mod expr;
pub(super) mod if_else;
pub(super) mod loop_;
pub(super) mod try_catch;
pub(super) mod expr;
pub(super) mod ternary; // placeholder (not wired)
pub(super) mod match_expr; // placeholder (not wired)
pub(super) mod throw_ctx; // thread-local ctx for Result-mode throw routing
pub(super) mod ternary; // placeholder (not wired)
pub(super) mod throw_ctx;
pub(super) mod try_catch; // thread-local ctx for Result-mode throw routing
#[derive(Clone, Copy)]
pub(super) struct LoopContext {
@ -77,8 +77,15 @@ pub(super) fn detect_and_push_increment_hint(body: &[StmtV0]) {
if vname == name {
if let ExprV0::Int { value } = *rhs {
if let Some(v) = value.as_i64() {
let s = match op.as_str() { "+" => v, "-" => -v, _ => 0 };
if s != 0 { hint = Some((name.clone(), s)); break; }
let s = match op.as_str() {
"+" => v,
"-" => -v,
_ => 0,
};
if s != 0 {
hint = Some((name.clone(), s));
break;
}
}
}
}
@ -149,16 +156,15 @@ impl FunctionDefBuilder {
// Phase 25.1m で確立した規則:
// - static box 内のメソッドで、box_name が Main 以外 → インスタンスメソッド
// - Main.main は特別扱い(エントリポイント)
!self.def.box_name.is_empty()
&& self.def.box_name != "Main"
!self.def.box_name.is_empty() && self.def.box_name != "Main"
}
/// パラメータ ValueId の生成(インスタンスメソッドなら %0 を me 用に予約)
fn build_param_ids(&self) -> Vec<ValueId> {
let offset = if self.is_instance_method() {
0 // %0 = me, params start from %1
0 // %0 = me, params start from %1
} else {
1 // params start from %1 (no implicit receiver)
1 // params start from %1 (no implicit receiver)
};
(0..self.def.params.len())
@ -251,7 +257,6 @@ fn lower_continue_stmt(f: &mut MirFunction, cur_bb: BasicBlockId, target_bb: Bas
// );
}
pub(super) fn lower_stmt_with_vars(
f: &mut MirFunction,
cur_bb: BasicBlockId,
@ -322,16 +327,14 @@ pub(super) fn lower_stmt_with_vars(
catches,
finally,
} => {
try_catch::lower_try_stmt(
f, cur_bb, try_body, catches, finally, vars, loop_stack, env,
)
try_catch::lower_try_stmt(f, cur_bb, try_body, catches, finally, vars, loop_stack, env)
}
StmtV0::If { cond, then, r#else } => {
if_else::lower_if_stmt(f, cur_bb, cond, then, r#else, vars, loop_stack, env)
}
StmtV0::Loop { cond, body } => {
loop_::lower_loop_stmt(f, cur_bb, cond, body, vars, loop_stack, env)
}
StmtV0::If { cond, then, r#else } => if_else::lower_if_stmt(
f, cur_bb, cond, then, r#else, vars, loop_stack, env,
),
StmtV0::Loop { cond, body } => loop_::lower_loop_stmt(
f, cur_bb, cond, body, vars, loop_stack, env,
),
}
}
@ -355,7 +358,10 @@ pub(super) fn lower_stmt_list_with_vars(
Ok(cur)
}
pub(super) fn lower_program(prog: ProgramV0, imports: std::collections::HashMap<String, String>) -> Result<MirModule, String> {
pub(super) fn lower_program(
prog: ProgramV0,
imports: std::collections::HashMap<String, String>,
) -> Result<MirModule, String> {
if prog.body.is_empty() {
return Err("empty body".into());
}
@ -468,7 +474,11 @@ pub(super) fn lower_program(prog: ProgramV0, imports: std::collections::HashMap<
// Phase 21.6: Call resolution post-processing
// Toggle: HAKO_MIR_BUILDER_CALL_RESOLVE=1
// Resolve Call instructions to use qualified function names (e.g., "add" -> "Main.add")
if std::env::var("HAKO_MIR_BUILDER_CALL_RESOLVE").ok().as_deref() == Some("1") {
if std::env::var("HAKO_MIR_BUILDER_CALL_RESOLVE")
.ok()
.as_deref()
== Some("1")
{
if !func_map.is_empty() {
for (_func_idx, func) in module.functions.iter_mut() {
for (_block_id, block) in func.blocks.iter_mut() {
@ -476,7 +486,12 @@ pub(super) fn lower_program(prog: ProgramV0, imports: std::collections::HashMap<
// Find Call instructions and their associated Const values
for inst in &block.instructions {
if let MirInstruction::Call { func: func_reg, args, .. } = inst {
if let MirInstruction::Call {
func: func_reg,
args,
..
} = inst
{
// Look for the Const instruction that defines func_reg
for const_inst in &block.instructions {
if let MirInstruction::Const { dst, value } = const_inst {
@ -486,12 +501,30 @@ pub(super) fn lower_program(prog: ProgramV0, imports: std::collections::HashMap<
if let Some(resolved) = func_map.get(name) {
let mut new_name = resolved.clone();
// Avoid double suffix if already contains '/N'
if !resolved.rsplit('/').next().unwrap_or("").chars().all(|c| c.is_ascii_digit()) || !resolved.contains('/') {
new_name = format!("{}{}", resolved.clone(), format!("/{}", args.len()));
if !resolved
.rsplit('/')
.next()
.unwrap_or("")
.chars()
.all(|c| c.is_ascii_digit())
|| !resolved.contains('/')
{
new_name = format!(
"{}{}",
resolved.clone(),
format!("/{}", args.len())
);
}
const_replacements.push((*dst, new_name));
if std::env::var("HAKO_MIR_BUILDER_DEBUG").ok().as_deref() == Some("1") {
eprintln!("[mirbuilder/call:resolve] {} => {}", name, resolved);
if std::env::var("HAKO_MIR_BUILDER_DEBUG")
.ok()
.as_deref()
== Some("1")
{
eprintln!(
"[mirbuilder/call:resolve] {} => {}",
name, resolved
);
}
}
}
@ -512,15 +545,23 @@ pub(super) fn lower_program(prog: ProgramV0, imports: std::collections::HashMap<
}
}
// Build a map reg -> name after replacements
let mut reg_name: std::collections::HashMap<ValueId, String> = std::collections::HashMap::new();
let mut reg_name: std::collections::HashMap<ValueId, String> =
std::collections::HashMap::new();
for inst in &block.instructions {
if let MirInstruction::Const { dst, value } = inst {
if let ConstValue::String(s) = value { reg_name.insert(*dst, s.clone()); }
if let ConstValue::String(s) = value {
reg_name.insert(*dst, s.clone());
}
}
}
// Upgrade legacy calls to Global callee when name is known
for inst in &mut block.instructions {
if let MirInstruction::Call { func: func_reg, callee, .. } = inst {
if let MirInstruction::Call {
func: func_reg,
callee,
..
} = inst
{
if let Some(name) = reg_name.get(func_reg).cloned() {
*callee = Some(Callee::Global(name));
}

View File

@ -1,10 +1,8 @@
use super::merge::new_block;
use super::BridgeEnv;
use super::ternary;
use super::match_expr;
use crate::mir::{
BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId,
};
use super::merge::new_block;
use super::ternary;
use super::BridgeEnv;
use crate::mir::{BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId};
use std::collections::HashMap;
use super::super::ast::ExprV0;
@ -140,7 +138,10 @@ fn lower_throw(
} else {
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::Const { dst, value: ConstValue::Integer(0) });
bb.add_instruction(MirInstruction::Const {
dst,
value: ConstValue::Integer(0),
});
}
(dst, cur_bb)
}
@ -264,8 +265,15 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
// );
let cdst = f.next_value_id();
if let Some(bb) = f.get_block_mut(fall_bb) {
let cval = if is_and { ConstValue::Bool(false) } else { ConstValue::Bool(true) };
bb.add_instruction(MirInstruction::Const { dst: cdst, value: cval });
let cval = if is_and {
ConstValue::Bool(false)
} else {
ConstValue::Bool(true)
};
bb.add_instruction(MirInstruction::Const {
dst: cdst,
value: cval,
});
}
crate::mir::ssot::cf_common::set_jump(f, fall_bb, merge_bb);
let (rval, rhs_end) = lower_expr_with_scope(env, f, rhs_bb, rhs, vars)?;
@ -277,7 +285,11 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
let out = f.next_value_id();
// フェーズM.2: PHI統一処理no_phi分岐削除
let mut inputs: Vec<(BasicBlockId, ValueId)> = vec![(fall_bb, cdst)];
if rhs_end != fall_bb { inputs.push((rhs_end, rval)); } else { inputs.push((fall_bb, rval)); }
if rhs_end != fall_bb {
inputs.push((rhs_end, rval));
} else {
inputs.push((fall_bb, rval));
}
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
Ok((out, merge_bb))
}
@ -346,7 +358,10 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
let (arg_ids, cur) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
let fun_val = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::Const { dst: fun_val, value: ConstValue::String(name.clone()) });
bb.add_instruction(MirInstruction::Const {
dst: fun_val,
value: ConstValue::String(name.clone()),
});
}
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
@ -361,8 +376,10 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
Ok((dst, cur))
}
ExprV0::Method { recv, method, args } => {
let recv_is_console_new = matches!(&**recv, ExprV0::New { class, .. } if class == "ConsoleBox");
if recv_is_console_new && (method == "println" || method == "print" || method == "log") {
let recv_is_console_new =
matches!(&**recv, ExprV0::New { class, .. } if class == "ConsoleBox");
if recv_is_console_new && (method == "println" || method == "print" || method == "log")
{
let (arg_ids, cur2) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur2) {
@ -378,11 +395,16 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
}
// Phase 25.1b: Handle env.box_introspect.kind(value) pattern
// Pattern: Method { recv: Method { recv: Var("env"), method: "box_introspect" }, method: "kind", args }
if let ExprV0::Method { recv: inner_recv, method: inner_method, args: inner_args } = &**recv {
if let ExprV0::Method {
recv: inner_recv,
method: inner_method,
args: inner_args,
} = &**recv
{
if matches!(&**inner_recv, ExprV0::Var { name } if name == "env")
&& inner_method == "box_introspect"
&& inner_args.is_empty() {
&& inner_args.is_empty()
{
// Lower args for the final method call
let (arg_ids, cur2) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
let dst = f.next_value_id();
@ -418,7 +440,11 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
let (arg_ids, cur) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::NewBox { dst, box_type: class.clone(), args: arg_ids });
bb.add_instruction(MirInstruction::NewBox {
dst,
box_type: class.clone(),
args: arg_ids,
});
}
Ok((dst, cur))
}
@ -430,10 +456,14 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
let (exc, cur) = lower_expr_with_scope(env, f, cur_bb, expr, vars)?;
Ok(lower_throw(env, f, cur, exc))
}
ExprV0::Ternary { cond, then, r#else } =>
ternary::lower_ternary_expr_with_scope(env, f, cur_bb, cond, then, r#else, vars),
ExprV0::Match { scrutinee, arms, r#else } =>
match_expr::lower_match_expr_with_scope(env, f, cur_bb, scrutinee, arms, r#else, vars),
ExprV0::Ternary { cond, then, r#else } => {
ternary::lower_ternary_expr_with_scope(env, f, cur_bb, cond, then, r#else, vars)
}
ExprV0::Match {
scrutinee,
arms,
r#else,
} => match_expr::lower_match_expr_with_scope(env, f, cur_bb, scrutinee, arms, r#else, vars),
}
}

View File

@ -1,8 +1,8 @@
use super::super::ast::ExprV0;
use super::super::ast::StmtV0;
use super::{lower_stmt_list_with_vars, merge_var_maps, new_block, BridgeEnv, LoopContext};
use crate::mir::{BasicBlockId, MirFunction, ValueId};
use std::collections::HashMap;
use super::super::ast::StmtV0;
use super::super::ast::ExprV0;
pub(super) fn lower_if_stmt(
f: &mut MirFunction,
@ -24,16 +24,22 @@ pub(super) fn lower_if_stmt(
let tend = lower_stmt_list_with_vars(f, then_bb, then_body, &mut then_vars, loop_stack, env)?;
let mut then_terminated = false;
if let Some(bb) = f.get_block_mut(tend) {
if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb); }
else { then_terminated = true; }
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb);
} else {
then_terminated = true;
}
}
let (else_end_pred, else_vars, else_terminated) = if let Some(elses) = else_body {
let mut ev = base_vars.clone();
let eend = lower_stmt_list_with_vars(f, else_bb, elses, &mut ev, loop_stack, env)?;
let mut term = false;
if let Some(bb) = f.get_block_mut(eend) {
if !bb.is_terminated() { crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb); }
else { term = true; }
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb);
} else {
term = true;
}
}
(eend, ev, term)
} else {

View File

@ -20,14 +20,14 @@
* だけを行う。
*/
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps};
use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox;
use crate::mir::phi_core::phi_input_collector::PhiInputCollector;
use std::collections::HashMap;
use super::super::ast::StmtV0;
use super::super::ast::ExprV0;
use super::super::ast::StmtV0;
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox;
use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps};
use crate::mir::phi_core::phi_input_collector::PhiInputCollector;
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
use std::collections::HashMap;
/// LoopForm v2 用の JSON bridge 実装。
///
@ -97,7 +97,9 @@ impl LoopFormOps for LoopFormJsonOps<'_> {
fn is_parameter(&self, value_id: ValueId) -> bool {
// Phase 26-A-4: ValueId から変数名を逆引き
// vars マップを逆引きして変数名を取得
let name = self.vars.iter()
let name = self
.vars
.iter()
.find(|(_, &v)| v == value_id)
.map(|(n, _)| n.as_str());
@ -153,7 +155,11 @@ impl LoopFormOps for LoopFormJsonOps<'_> {
) -> Result<(), String> {
if let Some(bb) = self.f.get_block_mut(block) {
for inst in &mut bb.instructions {
if let MirInstruction::Phi { dst, inputs: phi_inputs } = inst {
if let MirInstruction::Phi {
dst,
inputs: phi_inputs,
} = inst
{
if *dst == phi_id {
*phi_inputs = inputs;
return Ok(());
@ -231,7 +237,10 @@ pub(super) fn lower_loop_stmt(
// DEBUG: Log preheader snapshot
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
eprintln!("[loop_/lower] === PREHEADER SNAPSHOT (bb={:?}) ===", preheader_bb);
eprintln!(
"[loop_/lower] === PREHEADER SNAPSHOT (bb={:?}) ===",
preheader_bb
);
eprintln!("[loop_/lower] Function: {}", f.signature.name);
eprintln!("[loop_/lower] base_vars.len() = {}", base_vars.len());
let mut sorted: Vec<_> = base_vars.iter().collect();
@ -253,8 +262,7 @@ pub(super) fn lower_loop_stmt(
loopform.emit_header_phis(&mut ops)?;
// 3) ループ条件を header ブロックで評価し、body/exit へ分岐
let (cval, cend) =
super::expr::lower_expr_with_vars(env, ops.f, header_bb, cond, ops.vars)?;
let (cval, cend) = super::expr::lower_expr_with_vars(env, ops.f, header_bb, cond, ops.vars)?;
crate::mir::ssot::cf_common::set_branch(ops.f, cend, cval, body_bb, exit_bb);
// 4) ループ本体を loweringbreak/continue スナップショットは lowering.rs 側が管理)
@ -266,8 +274,7 @@ pub(super) fn lower_loop_stmt(
continue_merge_bb: Some(continue_merge_bb),
});
super::detect_and_push_increment_hint(body);
let bend_res =
lower_stmt_list_with_vars(ops.f, body_bb, body, &mut body_vars, loop_stack, env);
let bend_res = lower_stmt_list_with_vars(ops.f, body_bb, body, &mut body_vars, loop_stack, env);
loop_stack.pop();
let _ = super::pop_increment_hint();
let bend = bend_res?;
@ -293,10 +300,13 @@ pub(super) fn lower_loop_stmt(
// DEBUG: Log writes collection
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
let func_name = ops.f.signature.name.clone(); // Clone before borrowing
let func_name = ops.f.signature.name.clone(); // Clone before borrowing
eprintln!("[loop_/lower] === WRITES COLLECTION (Step 5-1) ===");
eprintln!("[loop_/lower] Function: {}", func_name);
eprintln!("[loop_/lower] {} variables modified in loop body", writes.len());
eprintln!(
"[loop_/lower] {} variables modified in loop body",
writes.len()
);
let mut sorted_writes: Vec<_> = writes.iter().collect();
sorted_writes.sort();
for name in &sorted_writes {
@ -330,10 +340,7 @@ pub(super) fn lower_loop_stmt(
let mut all_inputs: HashMap<String, Vec<(BasicBlockId, ValueId)>> = HashMap::new();
for (bb, snap) in &continue_snaps {
for (name, &val) in snap {
all_inputs
.entry(name.clone())
.or_default()
.push((*bb, val));
all_inputs.entry(name.clone()).or_default().push((*bb, val));
}
}

View File

@ -1,10 +1,10 @@
//! Match/expr-block lowering for JSON v0 bridge.
use super::super::ast::{ExprV0, MatchArmV0};
use super::expr::{lower_expr_with_scope, VarScope};
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<S: VarScope>(
env: &BridgeEnv,
@ -21,7 +21,9 @@ pub(super) fn lower_match_expr_with_scope<S: VarScope>(
// 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); }
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);
@ -31,7 +33,11 @@ pub(super) fn lower_match_expr_with_scope<S: VarScope>(
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 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
@ -39,15 +45,27 @@ pub(super) fn lower_match_expr_with_scope<S: VarScope>(
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()) });
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::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); }
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb);
}
}
phi_inputs.push((tend, tval));
@ -57,7 +75,9 @@ pub(super) fn lower_match_expr_with_scope<S: VarScope>(
// 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); }
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb);
}
}
phi_inputs.push((eend, eval));

View File

@ -1,6 +1,4 @@
use crate::mir::{
BasicBlock, BasicBlockId, MirFunction, MirInstruction, ValueId,
};
use crate::mir::{BasicBlock, BasicBlockId, MirFunction, MirInstruction, ValueId};
fn next_block_id(f: &MirFunction) -> BasicBlockId {
let mut mx = 0u32;

View File

@ -3,10 +3,10 @@
//! NOTE: This module is introduced as part of the helper split.
//! It is not wired yet and should not alter behavior.
use super::super::ast::ExprV0;
use super::merge::new_block;
use super::BridgeEnv;
use crate::mir::{BasicBlockId, MirFunction, ValueId};
use super::super::ast::ExprV0;
use super::expr::{lower_expr_with_scope, VarScope};
@ -27,11 +27,15 @@ pub(super) fn lower_ternary_expr_with_scope<S: VarScope>(
crate::mir::ssot::cf_common::set_branch(f, cur, cval, then_bb, else_bb);
let (tval, tend) = lower_expr_with_scope(env, f, then_bb, then_e, 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); }
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, tend, merge_bb);
}
}
let (eval, eend) = lower_expr_with_scope(env, f, else_bb, else_e, 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); }
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, eend, merge_bb);
}
}
let out = f.next_value_id();
// フェーズM.2: PHI統一処理no_phi分岐削除

View File

@ -13,7 +13,10 @@ pub(super) struct ThrowCtx {
impl ThrowCtx {
fn new(catch_bb: BasicBlockId) -> Self {
Self { catch_bb, incoming: Vec::new() }
Self {
catch_bb,
incoming: Vec::new(),
}
}
}
@ -33,7 +36,11 @@ pub(super) fn is_active() -> bool {
/// Record a throw from `from_bb` with value `exc_val`. Sets terminator Jump to catch and
/// appends predecessor+value to the incoming list. Returns the catch block id if active.
pub(super) fn record_throw(f: &mut MirFunction, from_bb: BasicBlockId, exc_val: ValueId) -> Option<BasicBlockId> {
pub(super) fn record_throw(
f: &mut MirFunction,
from_bb: BasicBlockId,
exc_val: ValueId,
) -> Option<BasicBlockId> {
THROW_CTX.with(|slot| {
if let Some(ctx) = slot.borrow_mut().as_mut() {
let target = ctx.catch_bb;

View File

@ -1,9 +1,7 @@
use super::{
lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext,
};
use super::super::ast::{CatchV0, StmtV0};
use super::{lower_stmt_list_with_vars, new_block, BridgeEnv, LoopContext};
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
use std::collections::HashMap;
use super::super::ast::{StmtV0, CatchV0};
pub(super) fn lower_try_stmt(
f: &mut MirFunction,
@ -23,9 +21,23 @@ pub(super) fn lower_try_stmt(
if catches.len() > 1 {
// Fallback to safe lowering (ignore catches) for multi-catch
let mut tmp_vars = vars.clone();
let mut next_bb = super::lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
let mut next_bb = super::lower_stmt_list_with_vars(
f,
cur_bb,
try_body,
&mut tmp_vars,
loop_stack,
env,
)?;
if !finally.is_empty() {
next_bb = super::lower_stmt_list_with_vars(f, next_bb, finally, &mut tmp_vars, loop_stack, env)?;
next_bb = super::lower_stmt_list_with_vars(
f,
next_bb,
finally,
&mut tmp_vars,
loop_stack,
env,
)?;
}
*vars = tmp_vars;
return Ok(next_bb);
@ -34,29 +46,47 @@ pub(super) fn lower_try_stmt(
let base_vars = vars.clone();
let try_bb = new_block(f);
let catch_bb_opt = if has_catch { Some(new_block(f)) } else { None };
let finally_bb = if !finally.is_empty() { Some(new_block(f)) } else { None };
let finally_bb = if !finally.is_empty() {
Some(new_block(f))
} else {
None
};
let exit_bb = new_block(f);
f.set_jump_terminator(cur_bb, try_bb)?;
if let Some(succ) = f.get_block_mut(try_bb) { succ.add_predecessor(cur_bb); }
if let Some(succ) = f.get_block_mut(try_bb) {
succ.add_predecessor(cur_bb);
}
// Install thread-local throw context so nested throw expressions jump to catch_bb
if has_catch {
let catch_bb = catch_bb_opt.expect("catch_bb must exist when has_catch");
if crate::config::env::cli_verbose() {
eprintln!("[Bridge] try_result_mode: set ThrowCtx (catch_bb={:?})", catch_bb);
eprintln!(
"[Bridge] try_result_mode: set ThrowCtx (catch_bb={:?})",
catch_bb
);
}
super::throw_ctx::set(catch_bb);
} else if crate::config::env::cli_verbose() {
eprintln!("[Bridge] try_result_mode: no catch present; ThrowCtx not set");
}
let mut try_vars = base_vars.clone();
let try_end = super::lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?;
let try_end =
super::lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?;
// Take recorded incoming exceptions
let incoming_exc = if has_catch { super::throw_ctx::take().map(|c| c.incoming).unwrap_or_default() } else { Vec::new() };
let incoming_exc = if has_catch {
super::throw_ctx::take()
.map(|c| c.incoming)
.unwrap_or_default()
} else {
Vec::new()
};
let target = finally_bb.unwrap_or(exit_bb);
f.set_jump_terminator(try_end, target)?;
if let Some(succ) = f.get_block_mut(target) { succ.add_predecessor(try_end); }
if let Some(succ) = f.get_block_mut(target) {
succ.add_predecessor(try_end);
}
let try_branch_vars = try_vars.clone();
// Lower catch block if present and reachable
@ -72,7 +102,9 @@ pub(super) fn lower_try_stmt(
if let Some(_bb) = f.get_block_mut(catch_bb) {
let mut inputs = incoming_exc.clone();
inputs.sort_by_key(|(bbid, _)| bbid.0);
crate::mir::ssot::cf_common::insert_phi_at_head(f, catch_bb, phi_dst, inputs);
crate::mir::ssot::cf_common::insert_phi_at_head(
f, catch_bb, phi_dst, inputs,
);
}
catch_vars.insert(param.clone(), phi_dst);
}
@ -87,7 +119,9 @@ pub(super) fn lower_try_stmt(
)?;
let target = finally_bb.unwrap_or(exit_bb);
f.set_jump_terminator(end, target)?;
if let Some(succ) = f.get_block_mut(target) { succ.add_predecessor(end); }
if let Some(succ) = f.get_block_mut(target) {
succ.add_predecessor(end);
}
(end, catch_vars)
} else {
(try_end, base_vars.clone())
@ -98,21 +132,30 @@ pub(super) fn lower_try_stmt(
if let Some(finally_block) = finally_bb {
// Compute merged var map from try_end + catch_end (if has_catch)
let branch_vars: Vec<(BasicBlockId, HashMap<String, ValueId>)> = if has_catch {
vec![(try_end, try_branch_vars.clone()), (catch_end, catch_branch_vars.clone())]
vec![
(try_end, try_branch_vars.clone()),
(catch_end, catch_branch_vars.clone()),
]
} else {
vec![(try_end, try_branch_vars.clone())]
};
let mut names: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars { names.extend(map.keys().cloned()); }
for (_, map) in &branch_vars {
names.extend(map.keys().cloned());
}
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars {
if let Some(&v) = map.get(&name) { inputs.push((*bbid, v)); }
if let Some(&v) = map.get(&name) {
inputs.push((*bbid, v));
}
}
if inputs.is_empty() {
if let Some(&b) = base_vars.get(&name) { merged_vars.insert(name.clone(), b); }
if let Some(&b) = base_vars.get(&name) {
merged_vars.insert(name.clone(), b);
}
continue;
}
let uniq: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
@ -126,12 +169,23 @@ pub(super) fn lower_try_stmt(
merged_vars.insert(name.clone(), dst);
}
if let Some(_bb) = f.get_block_mut(finally_block) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs);
}
}
let mut finally_vars = merged_vars.clone();
let final_end = super::lower_stmt_list_with_vars(f, finally_block, finally, &mut finally_vars, loop_stack, env)?;
let final_end = super::lower_stmt_list_with_vars(
f,
finally_block,
finally,
&mut finally_vars,
loop_stack,
env,
)?;
f.set_jump_terminator(final_end, exit_bb)?;
if let Some(succ) = f.get_block_mut(exit_bb) { succ.add_predecessor(final_end); }
if let Some(succ) = f.get_block_mut(exit_bb) {
succ.add_predecessor(final_end);
}
*vars = finally_vars;
return Ok(exit_bb);
} else {
@ -142,38 +196,49 @@ pub(super) fn lower_try_stmt(
vec![(try_end, try_branch_vars)]
};
let mut names: HashSet<String> = base_vars.keys().cloned().collect();
for (_, map) in &branch_vars { names.extend(map.keys().cloned()); }
for (_, map) in &branch_vars {
names.extend(map.keys().cloned());
}
let mut merged_vars = base_vars.clone();
let mut phi_entries: Vec<(ValueId, Vec<(BasicBlockId, ValueId)>)> = Vec::new();
for name in names {
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
for (bbid, map) in &branch_vars { if let Some(&v) = map.get(&name) { inputs.push((*bbid, v)); } }
if inputs.is_empty() { if let Some(&b) = base_vars.get(&name) { merged_vars.insert(name.clone(), b); } continue; }
for (bbid, map) in &branch_vars {
if let Some(&v) = map.get(&name) {
inputs.push((*bbid, v));
}
}
if inputs.is_empty() {
if let Some(&b) = base_vars.get(&name) {
merged_vars.insert(name.clone(), b);
}
continue;
}
let uniq: HashSet<ValueId> = inputs.iter().map(|(_, v)| *v).collect();
if uniq.len() == 1 { merged_vars.insert(name.clone(), inputs[0].1); continue; }
if uniq.len() == 1 {
merged_vars.insert(name.clone(), inputs[0].1);
continue;
}
let dst = f.next_value_id();
inputs.sort_by_key(|(bbid, _)| bbid.0);
phi_entries.push((dst, inputs));
merged_vars.insert(name.clone(), dst);
}
if let Some(_bb) = f.get_block_mut(exit_bb) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs);
}
}
*vars = merged_vars;
return Ok(exit_bb);
}
} else if !try_enabled || catches.is_empty() || catches.len() > 1 {
let mut tmp_vars = vars.clone();
let mut next_bb = lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
let mut next_bb =
lower_stmt_list_with_vars(f, cur_bb, try_body, &mut tmp_vars, loop_stack, env)?;
if !finally.is_empty() {
next_bb = lower_stmt_list_with_vars(
f,
next_bb,
finally,
&mut tmp_vars,
loop_stack,
env,
)?;
next_bb =
lower_stmt_list_with_vars(f, next_bb, finally, &mut tmp_vars, loop_stack, env)?;
}
*vars = tmp_vars;
return Ok(next_bb);
@ -260,7 +325,9 @@ pub(super) fn lower_try_stmt(
}
// フェーズM.2: PHI統一処理no_phi分岐削除
if let Some(_bb) = f.get_block_mut(finally_block) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, finally_block, dst, inputs);
}
}
let mut finally_vars = merged_vars.clone();
let final_end = lower_stmt_list_with_vars(
@ -309,7 +376,9 @@ pub(super) fn lower_try_stmt(
}
// フェーズM.2: PHI統一処理no_phi分岐削除
if let Some(_bb) = f.get_block_mut(exit_bb) {
for (dst, inputs) in phi_entries { crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs); }
for (dst, inputs) in phi_entries {
crate::mir::ssot::cf_common::insert_phi_at_head(f, exit_bb, dst, inputs);
}
}
*vars = merged_vars;
Ok(exit_bb)

View File

@ -10,16 +10,26 @@ pub fn parse_json_v0_to_module(json: &str) -> Result<crate::mir::MirModule, Stri
parse_json_v0_to_module_with_imports(json, HashMap::new())
}
pub fn parse_json_v0_to_module_with_imports(json: &str, imports: HashMap<String, String>) -> Result<crate::mir::MirModule, String> {
pub fn parse_json_v0_to_module_with_imports(
json: &str,
imports: HashMap<String, String>,
) -> Result<crate::mir::MirModule, String> {
let prog: ProgramV0 =
serde_json::from_str(json).map_err(|e| format!("invalid JSON v0: {}", e))?;
if crate::config::env::cli_verbose() {
let first = prog
.body
.get(1)
.map(|s| match s { StmtV0::Try { .. } => "Try", _ => "Other" })
.map(|s| match s {
StmtV0::Try { .. } => "Try",
_ => "Other",
})
.unwrap_or("<none>");
eprintln!("[Bridge] JSON v0: body_len={} first_type={}", prog.body.len(), first);
eprintln!(
"[Bridge] JSON v0: body_len={} first_type={}",
prog.body.len(),
first
);
}
if prog.version != 0 || prog.kind != "Program" {
return Err("unsupported IR: expected {version:0, kind:\"Program\"}".into());