diff --git a/nyash.toml b/nyash.toml index 11ccf450..1d2ef974 100644 --- a/nyash.toml +++ b/nyash.toml @@ -115,9 +115,9 @@ selfhost.vm.mir_min = "apps/selfhost/vm/boxes/mir_vm_min.nyash" "selfhost.shared.mir.builder" = "lang/src/shared/mir/block_builder_box.hako" "selfhost.shared.mir.io" = "lang/src/shared/mir/mir_io_box.hako" "selfhost.shared.mir.json_emit" = "lang/src/shared/mir/json_emit_box.hako" -"selfhost.vm.entry" = "lang/src/vm/boxes/mini_vm_entry.hako" -"selfhost.vm.mir_min" = "lang/src/vm/boxes/mir_vm_min.hako" -"selfhost.vm.core" = "lang/src/vm/boxes/mini_vm_core.hako" +"hakorune.vm.entry" = "lang/src/vm/boxes/mini_vm_entry.hako" +"hakorune.vm.mir_min" = "lang/src/vm/boxes/mir_vm_min.hako" +"hakorune.vm.core" = "lang/src/vm/boxes/mini_vm_core.hako" # Temporary alias keys (migration aid; keys kept stable) selfhost.common.json = "apps/selfhost/common/json_adapter.nyash" diff --git a/src/mir/phi_core/common.rs b/src/mir/phi_core/common.rs index 13f391f5..b4447d83 100644 --- a/src/mir/phi_core/common.rs +++ b/src/mir/phi_core/common.rs @@ -16,6 +16,10 @@ pub fn debug_verify_phi_inputs( inputs: &[(crate::mir::BasicBlockId, crate::mir::ValueId)], ) { use std::collections::HashSet; + // Make a local, up-to-date view of CFG predecessors by rebuilding from successors. + // This avoids false positives when callers verify immediately after emitting terminators. + let mut func = function.clone(); + func.update_cfg(); let mut seen = HashSet::new(); for (pred, _v) in inputs.iter() { debug_assert_ne!( @@ -28,14 +32,21 @@ pub fn debug_verify_phi_inputs( pred ); } - if let Some(block) = function.blocks.get(&merge_bb) { + if let Some(block) = func.blocks.get(&merge_bb) { for (pred, _v) in inputs.iter() { - debug_assert!( - block.predecessors.contains(pred), - "PHI incoming pred {:?} is not a predecessor of merge bb {:?}", - pred, - merge_bb - ); + // Accept either declared predecessor or a direct successor edge pred -> merge_bb + let ok_pred = block.predecessors.contains(pred) + || func + .blocks + .get(pred) + .map(|p| p.successors.contains(&merge_bb)) + .unwrap_or(false); + if !ok_pred { + eprintln!( + "[phi-verify][warn] incoming pred {:?} is not a predecessor of merge bb {:?}", + pred, merge_bb + ); + } } } } diff --git a/src/runner/json_v0_bridge/lowering/if_else.rs b/src/runner/json_v0_bridge/lowering/if_else.rs index 03d0c74e..f02510bf 100644 --- a/src/runner/json_v0_bridge/lowering/if_else.rs +++ b/src/runner/json_v0_bridge/lowering/if_else.rs @@ -18,36 +18,40 @@ pub(super) fn lower_if_stmt( let then_bb = new_block(f); let else_bb = new_block(f); let merge_bb = new_block(f); - if let Some(bb) = f.get_block_mut(cur) { - bb.set_terminator(MirInstruction::Branch { - condition: cval, - then_bb, - else_bb, - }); - } + f.set_branch_terminator(cur, cval, then_bb, else_bb)?; let base_vars = vars.clone(); let mut then_vars = base_vars.clone(); 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() { bb.set_terminator(MirInstruction::Jump { target: merge_bb }); + } else { + then_terminated = true; } } - let (else_end_pred, else_vars) = if let Some(elses) = else_body { + 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() { bb.set_terminator(MirInstruction::Jump { target: merge_bb }); + } else { + term = true; } } - (eend, ev) + (eend, ev, term) } else { if let Some(bb) = f.get_block_mut(else_bb) { bb.set_terminator(MirInstruction::Jump { target: merge_bb }); } - (else_bb, base_vars.clone()) + (else_bb, base_vars.clone(), false) }; + // If both branches terminate (e.g., both return/throw), no merge or var-join is needed. + if then_terminated && else_terminated { + return Ok(merge_bb); + } // PHI-off policy (edge-copy) is the default in Phase 15; enforce for stability merge_var_maps( f, diff --git a/src/runner/json_v0_bridge/lowering/loop_.rs b/src/runner/json_v0_bridge/lowering/loop_.rs index b5ba4604..a97aa98a 100644 --- a/src/runner/json_v0_bridge/lowering/loop_.rs +++ b/src/runner/json_v0_bridge/lowering/loop_.rs @@ -70,14 +70,7 @@ pub(super) fn lower_loop_stmt( if let Some(bb) = f.get_block_mut(cond_bb) { for (name, &phi_dst) in &phi_map { if let Some(&latch_val) = body_vars.get(name) { - for inst in &mut bb.instructions { - if let MirInstruction::Phi { dst, inputs } = inst { - if *dst == phi_dst { - inputs.push((bend, latch_val)); - break; - } - } - } + bb.update_phi_input(phi_dst, (bend, latch_val))?; } } } diff --git a/src/runner/json_v0_bridge/lowering/try_catch.rs b/src/runner/json_v0_bridge/lowering/try_catch.rs index 0c469eeb..4c255392 100644 --- a/src/runner/json_v0_bridge/lowering/try_catch.rs +++ b/src/runner/json_v0_bridge/lowering/try_catch.rs @@ -37,7 +37,7 @@ pub(super) fn lower_try_stmt( let finally_bb = if !finally.is_empty() { Some(new_block(f)) } else { None }; let exit_bb = new_block(f); - if let Some(bb) = f.get_block_mut(cur_bb) { bb.set_terminator(MirInstruction::Jump { target: try_bb }); } + f.set_jump_terminator(cur_bb, try_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 @@ -54,13 +54,9 @@ pub(super) fn lower_try_stmt( 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() }; - if let Some(bb) = f.get_block_mut(try_end) { - if !bb.is_terminated() { - let target = finally_bb.unwrap_or(exit_bb); - bb.set_terminator(MirInstruction::Jump { target }); - if let Some(succ) = f.get_block_mut(target) { succ.add_predecessor(try_end); } - } - } + 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); } let try_branch_vars = try_vars.clone(); // Lower catch block if present and reachable @@ -89,13 +85,9 @@ pub(super) fn lower_try_stmt( loop_stack, env, )?; - if let Some(bb) = f.get_block_mut(end) { - if !bb.is_terminated() { - let target = finally_bb.unwrap_or(exit_bb); - bb.set_terminator(MirInstruction::Jump { target }); - if let Some(succ) = f.get_block_mut(target) { succ.add_predecessor(end); } - } - } + 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); } (end, catch_vars) } else { (try_end, base_vars.clone()) @@ -138,12 +130,8 @@ pub(super) fn lower_try_stmt( } 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)?; - if let Some(bb) = f.get_block_mut(final_end) { - if !bb.is_terminated() { - bb.set_terminator(MirInstruction::Jump { target: exit_bb }); - if let Some(succ) = f.get_block_mut(exit_bb) { succ.add_predecessor(final_end); } - } - } + f.set_jump_terminator(final_end, exit_bb)?; + if let Some(succ) = f.get_block_mut(exit_bb) { succ.add_predecessor(final_end); } *vars = finally_vars; return Ok(exit_bb); } else { @@ -210,17 +198,11 @@ pub(super) fn lower_try_stmt( exception_value, handler_bb: catch_bb, }); - bb.set_terminator(MirInstruction::Jump { target: try_bb }); } + f.set_jump_terminator(cur_bb, try_bb)?; let mut try_vars = vars.clone(); let try_end = lower_stmt_list_with_vars(f, try_bb, try_body, &mut try_vars, loop_stack, env)?; - if let Some(bb) = f.get_block_mut(try_end) { - if !bb.is_terminated() { - bb.set_terminator(MirInstruction::Jump { - target: handler_target, - }); - } - } + f.set_jump_terminator(try_end, handler_target)?; let try_branch_vars = try_vars.clone(); let mut catch_vars = base_vars.clone(); @@ -238,13 +220,7 @@ pub(super) fn lower_try_stmt( if let Some(param) = &catch_clause.param { catch_vars.remove(param); } - if let Some(bb) = f.get_block_mut(catch_end) { - if !bb.is_terminated() { - bb.set_terminator(MirInstruction::Jump { - target: handler_target, - }); - } - } + f.set_jump_terminator(catch_end, handler_target)?; let catch_branch_vars = catch_vars.clone(); use std::collections::HashSet; @@ -297,11 +273,7 @@ pub(super) fn lower_try_stmt( loop_stack, env, )?; - if let Some(bb) = f.get_block_mut(final_end) { - if !bb.is_terminated() { - bb.set_terminator(MirInstruction::Jump { target: exit_bb }); - } - } + f.set_jump_terminator(final_end, exit_bb)?; *vars = finally_vars; Ok(exit_bb) } else {