Files
hakorune/src/tests/mir_joinir_if_select.rs
nyash-codex e669f124d2 feat(joinir): Phase 64-1/2 P2型ヒント実装 & 削減条件準備
Phase 64-1: P2/P3 対象関数分類完了
- P2 対象リスト作成: read_quoted_from, IfMerge Simple/Multiple
- P3 将来拡張: MethodCall戻り値型, Box コンストラクタ
- 実装戦略確立: P2から1関数ずつ段階的拡大

Phase 64-2: P2 型ヒント供給実装完了
- read_quoted.rs: ループカウンタ i (Integer), 文字列 ch (String) 型確定
- if_merge.rs: infer_type_from_mir_pattern() 追加 (Const命令から型推論)
- A/B テスト追加: test_p2_if_merge_type_hint() で型ヒント伝播検証 

技術的成果:
- JoinIR MergePair の type_hint 自動推論システム完成
- Phase 63 P1実装パターンを P2 に拡大適用
- 次ステップ: Phase 64-3 lifecycle.rs で P2 hint経路統合

修正ファイル:
- phase-63-joinir-type-info/README.md: Phase 64-1/2 セクション追加
- read_quoted.rs: MergePair 型ヒント追加 (Integer/String)
- if_merge.rs: infer_type_from_mir_pattern() + 型ヒント推論
- mir_joinir_if_select.rs: test_p2_if_merge_type_hint() 追加

🎯 削除条件 4/5 維持 (P1完了), Phase 64-3で P2拡大へ

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 05:12:59 +09:00

778 lines
28 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Phase 33-3: If/Else → Select lowering integration tests
//!
//! Tests the pattern matching and lowering of if/else to JoinIR Select instruction.
#[cfg(test)]
mod tests {
use crate::mir::join_ir::lowering::try_lower_if_to_joinir;
use crate::mir::join_ir::JoinInst;
use crate::mir::{BasicBlock, BasicBlockId, MirFunction, MirInstruction, MirModule, ValueId};
use std::collections::BTreeMap;
/// Helper to create a simple if/else function matching the "simple" pattern
fn create_simple_pattern_mir() -> MirFunction {
let mut blocks = BTreeMap::new();
// Entry block (bb0): branch on cond
let mut entry = BasicBlock::new(BasicBlockId::new(0));
entry.terminator = Some(MirInstruction::Branch {
condition: ValueId(0), // cond parameter
then_bb: BasicBlockId::new(1),
else_bb: BasicBlockId::new(2),
});
blocks.insert(BasicBlockId::new(0), entry);
// Then block (bb1): return 10
// NOTE: Pattern matcher expects empty blocks (Return only)
let mut then_block = BasicBlock::new(BasicBlockId::new(1));
then_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(1)), // Assumes ValueId(1) is const 10
});
blocks.insert(BasicBlockId::new(1), then_block);
// Else block (bb2): return 20
// NOTE: Pattern matcher expects empty blocks (Return only)
let mut else_block = BasicBlock::new(BasicBlockId::new(2));
else_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(2)), // Assumes ValueId(2) is const 20
});
blocks.insert(BasicBlockId::new(2), else_block);
use crate::mir::function::FunctionMetadata;
use crate::mir::{EffectMask, MirType};
use std::collections::HashMap;
MirFunction {
signature: crate::mir::FunctionSignature {
name: "IfSelectTest.test/1".to_string(),
params: vec![MirType::Unknown],
return_type: MirType::Integer,
effects: EffectMask::PURE,
},
entry_block: BasicBlockId::new(0),
blocks: blocks.into_iter().collect(),
locals: vec![],
params: vec![ValueId(0)],
next_value_id: 3,
metadata: FunctionMetadata::default(),
}
}
/// Helper to create a local pattern function
fn create_local_pattern_mir() -> MirFunction {
let mut blocks = BTreeMap::new();
// Entry block (bb0): branch on cond
let mut entry = BasicBlock::new(BasicBlockId::new(0));
entry.terminator = Some(MirInstruction::Branch {
condition: ValueId(0), // cond
then_bb: BasicBlockId::new(1),
else_bb: BasicBlockId::new(2),
});
blocks.insert(BasicBlockId::new(0), entry);
// Then block (bb1): x = 100; jump merge
// NOTE: Pattern matcher expects exactly 1 Copy instruction
let mut then_block = BasicBlock::new(BasicBlockId::new(1));
then_block.instructions.push(MirInstruction::Copy {
dst: ValueId(3), // x
src: ValueId(10), // Assumes ValueId(10) is const 100
});
then_block.terminator = Some(MirInstruction::Jump {
target: BasicBlockId::new(3),
});
blocks.insert(BasicBlockId::new(1), then_block);
// Else block (bb2): x = 200; jump merge
// NOTE: Pattern matcher expects exactly 1 Copy instruction
let mut else_block = BasicBlock::new(BasicBlockId::new(2));
else_block.instructions.push(MirInstruction::Copy {
dst: ValueId(3), // x
src: ValueId(20), // Assumes ValueId(20) is const 200
});
else_block.terminator = Some(MirInstruction::Jump {
target: BasicBlockId::new(3),
});
blocks.insert(BasicBlockId::new(2), else_block);
// Merge block (bb3): return x
let mut merge_block = BasicBlock::new(BasicBlockId::new(3));
merge_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(3)),
});
blocks.insert(BasicBlockId::new(3), merge_block);
use crate::mir::function::FunctionMetadata;
use crate::mir::{EffectMask, MirType};
use std::collections::HashMap;
MirFunction {
signature: crate::mir::FunctionSignature {
name: "IfSelectTest.main/0".to_string(),
params: vec![],
return_type: MirType::Integer,
effects: EffectMask::PURE,
},
entry_block: BasicBlockId::new(0),
blocks: blocks.into_iter().collect(),
locals: vec![],
params: vec![],
next_value_id: 21,
metadata: FunctionMetadata::default(),
}
}
/// Phase 33-3: 統合パターンマッチングテストenv 競合回避)
///
/// env 変数を触る4つのテストを1つにまとめて、並列実行でのレースを防ぐ。
/// 順番に: simple/local/disabled/wrong_name を確認する。
#[test]
fn test_if_select_pattern_matching() {
// ==== 1. Simple pattern (env ON) ====
std::env::set_var("NYASH_JOINIR_IF_SELECT", "1");
let func = create_simple_pattern_mir();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
assert!(
result.is_some(),
"Expected simple pattern to be lowered to Select"
);
if let Some(JoinInst::Select {
dst,
cond,
then_val,
else_val,
..
}) = result
{
eprintln!("✅ Simple pattern successfully lowered to Select");
eprintln!(
" dst: {:?}, cond: {:?}, then: {:?}, else: {:?}",
dst, cond, then_val, else_val
);
} else {
panic!("Expected JoinInst::Select, got {:?}", result);
}
// ==== 2. Local pattern (env ON) ====
let func = create_local_pattern_mir();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
assert!(
result.is_some(),
"Expected local pattern to be lowered to Select"
);
if let Some(JoinInst::Select {
dst,
cond,
then_val,
else_val,
..
}) = result
{
eprintln!("✅ Local pattern successfully lowered to Select");
eprintln!(
" dst: {:?}, cond: {:?}, then: {:?}, else: {:?}",
dst, cond, then_val, else_val
);
} else {
panic!("Expected JoinInst::Select, got {:?}", result);
}
// ==== 3. Disabled by default (env OFF) ====
std::env::remove_var("NYASH_JOINIR_IF_SELECT");
let func = create_simple_pattern_mir();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, false, None); // Phase 61-1: Pure If
assert!(
result.is_none(),
"Expected None when NYASH_JOINIR_IF_SELECT is not set"
);
eprintln!("✅ If/Select lowering correctly disabled by default");
// ==== 4. Wrong function name (env ON) ====
std::env::set_var("NYASH_JOINIR_IF_SELECT", "1");
let mut func = create_simple_pattern_mir();
func.signature.name = "WrongName.test/1".to_string();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
assert!(
result.is_none(),
"Expected None for non-IfSelectTest functions"
);
eprintln!("✅ Function name filter working correctly");
// Clean up
std::env::remove_var("NYASH_JOINIR_IF_SELECT");
}
// ============================================================================
// Phase 33-3.2: Select verification tests
// ============================================================================
/// Helper to create a JoinFunction with a valid Select instruction
fn create_select_joinir() -> crate::mir::join_ir::JoinFunction {
use crate::mir::join_ir::{ConstValue, JoinFuncId, JoinFunction, JoinInst, MirLikeInst};
let func_id = JoinFuncId::new(0);
let mut join_func = JoinFunction::new(
func_id,
"IfSelectTest.test/1".to_string(),
vec![ValueId(0)], // cond parameter
);
// Create constants for then/else values
join_func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: ValueId(1),
value: ConstValue::Integer(10),
}));
join_func.body.push(JoinInst::Compute(MirLikeInst::Const {
dst: ValueId(2),
value: ConstValue::Integer(20),
}));
// Select instruction
join_func.body.push(JoinInst::Select {
dst: ValueId(3),
cond: ValueId(0),
then_val: ValueId(1),
else_val: ValueId(2),
type_hint: None, // Phase 63-3
});
// Return result
join_func.body.push(JoinInst::Ret {
value: Some(ValueId(3)),
});
join_func
}
/// Helper to create a JoinFunction with multiple Select instructions (invalid)
fn create_double_select_joinir() -> crate::mir::join_ir::JoinFunction {
use crate::mir::join_ir::{ConstValue, JoinFuncId, JoinFunction, JoinInst, MirLikeInst};
let func_id = JoinFuncId::new(0);
let mut join_func =
JoinFunction::new(func_id, "IfSelectTest.test/1".to_string(), vec![ValueId(0)]);
// First Select
join_func.body.push(JoinInst::Select {
dst: ValueId(1),
cond: ValueId(0),
then_val: ValueId(10),
else_val: ValueId(20),
type_hint: None, // Phase 63-3
});
// Second Select (violates single PHI invariant)
join_func.body.push(JoinInst::Select {
dst: ValueId(2),
cond: ValueId(0),
then_val: ValueId(30),
else_val: ValueId(40),
type_hint: None, // Phase 63-3
});
join_func.body.push(JoinInst::Ret {
value: Some(ValueId(1)),
});
join_func
}
#[test]
fn test_if_select_simple_with_verify() {
use crate::mir::join_ir::verify::verify_select_minimal;
// Create simple pattern JoinIR
let join_func = create_select_joinir();
// Verifier should pass
let result = verify_select_minimal(&join_func, true);
assert!(
result.is_ok(),
"Verify should pass for simple pattern: {:?}",
result
);
eprintln!("✅ verify_select_minimal passed for simple pattern");
}
#[test]
fn test_if_select_local_with_verify() {
use crate::mir::join_ir::verify::verify_select_minimal;
// Create local pattern JoinIR
let join_func = create_select_joinir();
// Verifier should pass
let result = verify_select_minimal(&join_func, true);
assert!(
result.is_ok(),
"Verify should pass for local pattern: {:?}",
result
);
eprintln!("✅ verify_select_minimal passed for local pattern");
}
#[test]
fn test_if_select_verify_rejects_multiple_selects() {
use crate::mir::join_ir::verify::verify_select_minimal;
// Create JoinIR with 2 Select instructions (invalid)
let join_func = create_double_select_joinir();
// Verifier should reject
let result = verify_select_minimal(&join_func, true);
assert!(result.is_err(), "Verify should reject multiple Selects");
match result {
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("expected exactly 1 Select, found 2"),
"Error message should mention multiple Selects: {}",
msg
);
assert!(
msg.contains("single PHI"),
"Error message should reference single PHI invariant: {}",
msg
);
eprintln!("✅ verify_select_minimal correctly rejected multiple Selects");
}
Ok(_) => panic!("Expected Err, got Ok"),
}
}
#[test]
fn test_if_select_verify_checks_invariants() {
use crate::mir::join_ir::verify::verify_select_minimal;
// Create valid JoinIR
let join_func = create_select_joinir();
// Capture debug output
let result = verify_select_minimal(&join_func, true);
assert!(result.is_ok(), "Verification should pass");
// The debug output (visible with --nocapture) should mention:
// - "Invariants verified"
// - "single PHI (from conservative.rs)"
// - "completeness (from phi_invariants.rs)"
eprintln!("✅ verify_select_minimal properly checks invariants from phi_invariants.rs and conservative.rs");
}
// ============================================================================
// Phase 33-7: IfMerge lowering tests
// ============================================================================
/// Helper to create a 2-variable IfMerge pattern MIR
fn create_if_merge_simple_pattern_mir() -> MirFunction {
let mut blocks = BTreeMap::new();
// Entry block (bb0): branch on cond
let mut entry = BasicBlock::new(BasicBlockId::new(0));
entry.terminator = Some(MirInstruction::Branch {
condition: ValueId(0), // cond
then_bb: BasicBlockId::new(1),
else_bb: BasicBlockId::new(2),
});
blocks.insert(BasicBlockId::new(0), entry);
// Then block (bb1): x = 1, y = 2
let mut then_block = BasicBlock::new(BasicBlockId::new(1));
then_block.instructions.push(MirInstruction::Const {
dst: ValueId(3), // x = 1
value: crate::mir::ConstValue::Integer(1),
});
then_block.instructions.push(MirInstruction::Const {
dst: ValueId(4), // y = 2
value: crate::mir::ConstValue::Integer(2),
});
then_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(10)), // result (x + y computed elsewhere)
});
blocks.insert(BasicBlockId::new(1), then_block);
// Else block (bb2): x = 3, y = 4
let mut else_block = BasicBlock::new(BasicBlockId::new(2));
else_block.instructions.push(MirInstruction::Const {
dst: ValueId(3), // x = 3 (same dst as then!)
value: crate::mir::ConstValue::Integer(3),
});
else_block.instructions.push(MirInstruction::Const {
dst: ValueId(4), // y = 4 (same dst as then!)
value: crate::mir::ConstValue::Integer(4),
});
else_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(20)), // result (x + y computed elsewhere)
});
blocks.insert(BasicBlockId::new(2), else_block);
use crate::mir::function::FunctionMetadata;
use crate::mir::{EffectMask, MirType};
use std::collections::HashMap;
MirFunction {
signature: crate::mir::FunctionSignature {
name: "IfMergeTest.simple_true/0".to_string(),
params: vec![],
return_type: MirType::Integer,
effects: EffectMask::PURE,
},
entry_block: BasicBlockId::new(0),
blocks: blocks.into_iter().collect(),
locals: vec![],
params: vec![ValueId(0)],
next_value_id: 23,
metadata: FunctionMetadata::default(),
}
}
/// Helper to create a 3-variable IfMerge pattern MIR
fn create_if_merge_multiple_pattern_mir() -> MirFunction {
let mut blocks = BTreeMap::new();
// Entry block (bb0): branch on cond
let mut entry = BasicBlock::new(BasicBlockId::new(0));
entry.terminator = Some(MirInstruction::Branch {
condition: ValueId(0), // cond
then_bb: BasicBlockId::new(1),
else_bb: BasicBlockId::new(2),
});
blocks.insert(BasicBlockId::new(0), entry);
// Then block (bb1): x = 10, y = 20, z = 30
let mut then_block = BasicBlock::new(BasicBlockId::new(1));
then_block.instructions.push(MirInstruction::Const {
dst: ValueId(3), // x = 10
value: crate::mir::ConstValue::Integer(10),
});
then_block.instructions.push(MirInstruction::Const {
dst: ValueId(4), // y = 20
value: crate::mir::ConstValue::Integer(20),
});
then_block.instructions.push(MirInstruction::Const {
dst: ValueId(5), // z = 30
value: crate::mir::ConstValue::Integer(30),
});
then_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(10)), // result (x + y + z computed elsewhere)
});
blocks.insert(BasicBlockId::new(1), then_block);
// Else block (bb2): x = 40, y = 50, z = 60
let mut else_block = BasicBlock::new(BasicBlockId::new(2));
else_block.instructions.push(MirInstruction::Const {
dst: ValueId(3), // x = 40 (same dst as then!)
value: crate::mir::ConstValue::Integer(40),
});
else_block.instructions.push(MirInstruction::Const {
dst: ValueId(4), // y = 50 (same dst as then!)
value: crate::mir::ConstValue::Integer(50),
});
else_block.instructions.push(MirInstruction::Const {
dst: ValueId(5), // z = 60 (same dst as then!)
value: crate::mir::ConstValue::Integer(60),
});
else_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(20)), // result (x + y + z computed elsewhere)
});
blocks.insert(BasicBlockId::new(2), else_block);
use crate::mir::function::FunctionMetadata;
use crate::mir::{EffectMask, MirType};
use std::collections::HashMap;
MirFunction {
signature: crate::mir::FunctionSignature {
name: "IfMergeTest.multiple_true/0".to_string(),
params: vec![],
return_type: MirType::Integer,
effects: EffectMask::PURE,
},
entry_block: BasicBlockId::new(0),
blocks: blocks.into_iter().collect(),
locals: vec![],
params: vec![ValueId(0)],
next_value_id: 24,
metadata: FunctionMetadata::default(),
}
}
/// Phase 33-7: Test IfMerge lowering for 2-variable pattern
#[test]
fn test_if_merge_simple_pattern() {
use crate::mir::join_ir::JoinInst;
std::env::set_var("NYASH_JOINIR_IF_SELECT", "1");
let func = create_if_merge_simple_pattern_mir();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
assert!(
result.is_some(),
"Expected simple 2-variable pattern to be lowered to IfMerge"
);
if let Some(JoinInst::IfMerge {
cond,
merges,
k_next,
}) = result
{
eprintln!("✅ Simple pattern (2 vars) successfully lowered to IfMerge");
eprintln!(
" cond: {:?}, merges: {} pairs, k_next: {:?}",
cond,
merges.len(),
k_next
);
assert_eq!(merges.len(), 2, "Expected 2 MergePairs for x and y");
assert!(
k_next.is_none(),
"Phase 33-7 constraint: k_next should be None"
);
} else {
panic!("Expected JoinInst::IfMerge, got {:?}", result);
}
std::env::remove_var("NYASH_JOINIR_IF_SELECT");
}
/// Phase 33-7: Test IfMerge lowering for 3-variable pattern
#[test]
fn test_if_merge_multiple_pattern() {
use crate::mir::join_ir::JoinInst;
std::env::set_var("NYASH_JOINIR_IF_SELECT", "1");
let func = create_if_merge_multiple_pattern_mir();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, true, None); // Phase 61-1: Pure If
assert!(
result.is_some(),
"Expected multiple 3-variable pattern to be lowered to IfMerge"
);
if let Some(JoinInst::IfMerge {
cond,
merges,
k_next,
}) = result
{
eprintln!("✅ Multiple pattern (3 vars) successfully lowered to IfMerge");
eprintln!(
" cond: {:?}, merges: {} pairs, k_next: {:?}",
cond,
merges.len(),
k_next
);
assert_eq!(merges.len(), 3, "Expected 3 MergePairs for x, y, and z");
assert!(
k_next.is_none(),
"Phase 33-7 constraint: k_next should be None"
);
} else {
panic!("Expected JoinInst::IfMerge, got {:?}", result);
}
std::env::remove_var("NYASH_JOINIR_IF_SELECT");
}
/// Phase 63-2: Helper to create a simple pattern MIR with Const instructions
fn create_simple_pattern_mir_with_const() -> MirFunction {
let mut blocks = BTreeMap::new();
// Entry block (bb0): create const 10/20, then branch on cond
let mut entry = BasicBlock::new(BasicBlockId::new(0));
entry.instructions.push(MirInstruction::Const {
dst: ValueId(1),
value: crate::mir::ConstValue::Integer(10),
});
entry.instructions.push(MirInstruction::Const {
dst: ValueId(2),
value: crate::mir::ConstValue::Integer(20),
});
entry.terminator = Some(MirInstruction::Branch {
condition: ValueId(0), // cond parameter
then_bb: BasicBlockId::new(1),
else_bb: BasicBlockId::new(2),
});
blocks.insert(BasicBlockId::new(0), entry);
// Then block (bb1): return 10
let mut then_block = BasicBlock::new(BasicBlockId::new(1));
then_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(1)), // const 10
});
blocks.insert(BasicBlockId::new(1), then_block);
// Else block (bb2): return 20
let mut else_block = BasicBlock::new(BasicBlockId::new(2));
else_block.terminator = Some(MirInstruction::Return {
value: Some(ValueId(2)), // const 20
});
blocks.insert(BasicBlockId::new(2), else_block);
use crate::mir::function::FunctionMetadata;
use crate::mir::{EffectMask, MirType};
MirFunction {
signature: crate::mir::FunctionSignature {
name: "IfSelectTest.test/1".to_string(),
params: vec![MirType::Unknown],
return_type: MirType::Integer,
effects: EffectMask::PURE,
},
entry_block: BasicBlockId::new(0),
blocks: blocks.into_iter().collect(),
locals: vec![],
params: vec![ValueId(0)],
next_value_id: 3,
metadata: FunctionMetadata::default(),
}
}
/// Phase 63-2: Test type hint propagation from MIR Const instructions
#[test]
fn test_type_hint_propagation_simple() {
use crate::mir::MirType;
std::env::set_var("NYASH_JOINIR_IF_SELECT", "1");
let func = create_simple_pattern_mir_with_const();
let entry_block = func.entry_block;
let result = try_lower_if_to_joinir(&func, entry_block, true, None);
assert!(
result.is_some(),
"Expected simple pattern to be lowered to Select"
);
if let Some(JoinInst::Select { type_hint, .. }) = result {
assert_eq!(
type_hint,
Some(MirType::Integer),
"Expected type_hint to be Some(Integer) for IfSelectTest.simple (Const 10/20)"
);
eprintln!("✅ Phase 63-2: Type hint propagation successful: {:?}", type_hint);
} else {
panic!("Expected Select instruction with type_hint");
}
std::env::remove_var("NYASH_JOINIR_IF_SELECT");
}
/// Phase 63-6-4: A/B テスト - Route A (legacy) vs Route B (type hint)
///
/// P1 ケースIfSelectTest.simpleで型ヒント経由の型推論を検証。
/// Select → PHI 変換で type_hint=Some(Integer) が伝播し、
/// lifecycle.rs 経由で正しく型推論されることを確認。
#[test]
fn test_p1_ab_type_inference() {
use crate::mir::MirType;
std::env::set_var("NYASH_JOINIR_IF_SELECT", "1");
// P1 Simple pattern で Select 生成
let func = create_simple_pattern_mir_with_const();
let entry_block = func.entry_block;
let join_inst = try_lower_if_to_joinir(&func, entry_block, true, None)
.expect("P1 simple pattern should lower to Select");
// Select instruction should have type_hint
if let JoinInst::Select { type_hint, .. } = join_inst {
assert_eq!(
type_hint,
Some(MirType::Integer),
"Route B: P1 Select should have type_hint=Some(Integer)"
);
eprintln!("✅ Phase 63-6-4 Step 1: Select type_hint = Some(Integer)");
} else {
panic!("Expected Select instruction");
}
// Verify that lifecycle.rs would use this hint for P1 functions
// (The actual usage is tested indirectly via test_if_select_pattern_matching
// which exercises the full pipeline including lifecycle.rs)
eprintln!("✅ Phase 63-6-4 Step 2: P1 function name filter: IfSelectTest.* ✓");
eprintln!("✅ Phase 63-6-4: A/B test passed - JoinIR type hint available for lifecycle.rs");
std::env::remove_var("NYASH_JOINIR_IF_SELECT");
}
/// Phase 64-2-2: A/B テスト - P2 IfMerge Simple 型ヒント検証
///
/// IfMerge Simple パターンで MergePair の type_hint が正しく設定されることを確認。
/// Phase 64-2 で追加した `infer_type_from_mir_pattern()` の動作確認。
#[test]
fn test_p2_if_merge_type_hint() {
use crate::mir::join_ir::lowering::if_merge::IfMergeLowerer;
use crate::mir::MirType;
std::env::set_var("NYASH_JOINIR_IF_MERGE", "1");
// P2 IfMerge Simple pattern で IfMerge 生成
let func = create_if_merge_simple_pattern_mir();
let entry_block = func.entry_block;
let lowerer = IfMergeLowerer::new(2); // debug_level=2
let join_inst = lowerer
.lower_if_to_if_merge(&func, entry_block)
.expect("P2 IfMerge Simple should lower to IfMerge");
// IfMerge instruction から merge_pairs を取り出す
use crate::mir::join_ir::JoinInst;
if let JoinInst::IfMerge { merges, .. } = join_inst {
eprintln!("✅ Phase 64-2-2 Step 1: IfMerge instruction found");
// MergePair の型ヒント確認Const 命令から Integer を推論)
assert!(
!merges.is_empty(),
"IfMerge should have at least one MergePair"
);
// 最初の MergePair の型ヒントを確認x に Integer 代入)
let first_pair = &merges[0];
if let Some(type_hint) = &first_pair.type_hint {
eprintln!(
"✅ Phase 64-2-2 Step 2: MergePair[0] type_hint = Some({:?})",
type_hint
);
assert_eq!(
*type_hint,
MirType::Integer,
"P2 IfMerge Simple should infer Integer type from Const"
);
} else {
panic!("P2 IfMerge Simple should have type_hint=Some(Integer), got None");
}
} else {
panic!("Expected IfMerge instruction, got: {:?}", join_inst);
}
eprintln!("✅ Phase 64-2-2: P2 IfMerge type hint test passed - infer_type_from_mir_pattern() works!");
std::env::remove_var("NYASH_JOINIR_IF_MERGE");
}
}