fix(mir/exit_phi): Pass branch_source_block to build_exit_phis()
## Problem Exit PHI generation was using header_id as predecessor, but when build_expression(condition) creates new blocks, the actual branch instruction is emitted from a different block, causing: "phi pred mismatch: no input for predecessor BasicBlockId(X)" ## Solution - Modified build_exit_phis() to accept branch_source_block parameter - Capture actual block after condition evaluation in loop_builder.rs - Use branch_source_block instead of header_id for PHI inputs ## Progress - Error changed from ValueId(5941)/BasicBlockId(4674) to ValueId(5927)/BasicBlockId(4672), showing partial fix - Added comprehensive test suite in mir_loopform_exit_phi.rs - Added debug logging to trace condition block creation ## Status Partial fix - unit tests pass, but Test 2 (Stage-B compilation) still has errors. Needs further investigation of complex nested compilation scenarios. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
174
src/tests/mir_loopform_exit_phi.rs
Normal file
174
src/tests/mir_loopform_exit_phi.rs
Normal file
@ -0,0 +1,174 @@
|
||||
/*!
|
||||
* Unit tests for LoopForm v2 exit PHI generation
|
||||
*
|
||||
* Tests the build_exit_phis() implementation in loopform_builder.rs
|
||||
* Focus: predecessor tracking and PHI input generation for break statements
|
||||
*/
|
||||
|
||||
use crate::parser::NyashParser;
|
||||
use crate::mir::{MirCompiler, MirVerifier};
|
||||
|
||||
#[test]
|
||||
fn test_loopform_exit_phi_single_break() {
|
||||
// Enable LoopForm PHI v2 and MIR verification
|
||||
std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1");
|
||||
std::env::set_var("NYASH_VM_VERIFY_MIR", "1");
|
||||
std::env::set_var("NYASH_LOOPFORM_DEBUG", "1");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
||||
|
||||
let src = r#"
|
||||
static box TestExitPhi {
|
||||
test() {
|
||||
local i = 0
|
||||
loop(i < 10) {
|
||||
if i == 5 { break }
|
||||
i = i + 1
|
||||
}
|
||||
return i
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
println!("=== Test: Single break statement ===");
|
||||
|
||||
// Parse
|
||||
let ast = NyashParser::parse_from_string(src)
|
||||
.expect("parse failed");
|
||||
|
||||
// Compile
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let cr = mc.compile(ast).expect("compile failed");
|
||||
|
||||
// MIR verification
|
||||
let mut verifier = MirVerifier::new();
|
||||
if let Err(errors) = verifier.verify_module(&cr.module) {
|
||||
for err in &errors {
|
||||
eprintln!("❌ MIR verification error: {}", err);
|
||||
}
|
||||
panic!("❌ MIR verification failed with {} errors", errors.len());
|
||||
}
|
||||
println!("✅ MIR verification passed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_loopform_exit_phi_multiple_breaks() {
|
||||
std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1");
|
||||
std::env::set_var("NYASH_VM_VERIFY_MIR", "1");
|
||||
std::env::set_var("NYASH_LOOPFORM_DEBUG", "1");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
||||
|
||||
let src = r#"
|
||||
static box TestMultiBreak {
|
||||
test() {
|
||||
local i = 0
|
||||
loop(i < 10) {
|
||||
if i == 3 { break }
|
||||
if i == 5 { break }
|
||||
i = i + 1
|
||||
}
|
||||
return i
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
println!("=== Test: Multiple break statements ===");
|
||||
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let cr = mc.compile(ast).expect("compile failed");
|
||||
|
||||
let mut verifier = MirVerifier::new();
|
||||
if let Err(errors) = verifier.verify_module(&cr.module) {
|
||||
for err in &errors {
|
||||
eprintln!("❌ MIR verification error: {}", err);
|
||||
}
|
||||
panic!("❌ MIR verification failed with {} errors", errors.len());
|
||||
}
|
||||
println!("✅ MIR verification passed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_loopform_exit_phi_nested_if_break() {
|
||||
std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1");
|
||||
std::env::set_var("NYASH_VM_VERIFY_MIR", "1");
|
||||
std::env::set_var("NYASH_LOOPFORM_DEBUG", "1");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
||||
|
||||
let src = r#"
|
||||
static box TestNestedBreak {
|
||||
test() {
|
||||
local i = 0
|
||||
local found = 0
|
||||
loop(i < 10) {
|
||||
if i > 5 {
|
||||
if i == 7 {
|
||||
found = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return found
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
println!("=== Test: Nested if with break ===");
|
||||
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let cr = mc.compile(ast).expect("compile failed");
|
||||
|
||||
let mut verifier = MirVerifier::new();
|
||||
if let Err(errors) = verifier.verify_module(&cr.module) {
|
||||
for err in &errors {
|
||||
eprintln!("❌ MIR verification error: {}", err);
|
||||
}
|
||||
panic!("❌ MIR verification failed with {} errors", errors.len());
|
||||
}
|
||||
println!("✅ MIR verification passed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_loopform_exit_phi_multiple_vars() {
|
||||
std::env::set_var("NYASH_LOOPFORM_PHI_V2", "1");
|
||||
std::env::set_var("NYASH_VM_VERIFY_MIR", "1");
|
||||
std::env::set_var("NYASH_LOOPFORM_DEBUG", "1");
|
||||
std::env::set_var("NYASH_PARSER_STAGE3", "1");
|
||||
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
||||
|
||||
let src = r#"
|
||||
static box TestMultiVars {
|
||||
test() {
|
||||
local i = 0
|
||||
local sum = 0
|
||||
local product = 1
|
||||
loop(i < 10) {
|
||||
if sum > 20 { break }
|
||||
sum = sum + i
|
||||
product = product * 2
|
||||
i = i + 1
|
||||
}
|
||||
return sum
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
println!("=== Test: Multiple variables with break ===");
|
||||
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse failed");
|
||||
let mut mc = MirCompiler::with_options(false);
|
||||
let cr = mc.compile(ast).expect("compile failed");
|
||||
|
||||
let mut verifier = MirVerifier::new();
|
||||
if let Err(errors) = verifier.verify_module(&cr.module) {
|
||||
for err in &errors {
|
||||
eprintln!("❌ MIR verification error: {}", err);
|
||||
}
|
||||
panic!("❌ MIR verification failed with {} errors", errors.len());
|
||||
}
|
||||
println!("✅ MIR verification passed");
|
||||
}
|
||||
Reference in New Issue
Block a user