refactor(joinir): Phase 221-R ExprResultResolver Box extraction

Extracted 64 lines of expr_result handling from merge/mod.rs into
dedicated ExprResultResolver Box following Phase 33 modularization.

- New module: expr_result_resolver.rs (185 lines, 4 unit tests)
- merge/mod.rs: -37 lines (net reduction)
- Single responsibility: expr_result resolution only
- Improved testability and maintainability

Phase 221-R completes the box-first refactoring of Phase 221's
expr_result routing implementation, aligning with Phase 33
modularization patterns (ExitMetaCollector, ExitLineReconnector).

Test results:
 phase212_if_sum_min.hako: RC=2
 loop_if_phi.hako: sum=9 (legacy mode)
 loop_min_while.hako: correct output
This commit is contained in:
nyash-codex
2025-12-10 04:23:34 +09:00
parent 8ca30f375a
commit 33e80637dd
2 changed files with 207 additions and 59 deletions

View File

@ -21,6 +21,7 @@ mod loop_header_phi_info;
mod loop_header_phi_builder;
mod tail_call_classifier;
mod merge_result;
mod expr_result_resolver;
// Phase 33-17: Re-export for use by other modules
pub use loop_header_phi_info::LoopHeaderPhiInfo;
@ -610,69 +611,31 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
builder.reserved_value_ids.clear();
}
// Phase 221: Return expr_result if present (for expr-position loops)
// The expr_result from boundary contains the JoinIR-local ValueId that should
// be returned. We need to map it to the HOST ValueId space.
//
// IMPORTANT: If expr_result corresponds to a carrier variable, we should return
// the carrier PHI dst (from loop header), NOT the remapped JoinIR value.
// This is because carriers use header PHIs which dominate the exit block.
if let Some(boundary) = boundary {
eprintln!(
"[cf_loop/joinir] Phase 221: Boundary present, expr_result={:?}, exit_bindings={:?}",
boundary.expr_result,
boundary.exit_bindings.iter().map(|b| (b.carrier_name.as_str(), b.join_exit_value)).collect::<Vec<_>>()
);
if let Some(expr_result_id) = boundary.expr_result {
// Check if expr_result corresponds to a carrier exit binding
// If so, use the carrier PHI dst instead of remapped value
for binding in &boundary.exit_bindings {
if binding.join_exit_value == expr_result_id {
// expr_result is a carrier! Use the carrier PHI dst
if let Some(&carrier_phi_dst) = carrier_phis.get(&binding.carrier_name) {
eprintln!(
"[cf_loop/joinir] Phase 221: expr_result {:?} is carrier '{}', returning PHI dst {:?}",
expr_result_id, binding.carrier_name, carrier_phi_dst
);
return Ok(Some(carrier_phi_dst));
} else {
return Err(format!(
"[cf_loop/joinir] Phase 221: Carrier '{}' not found in carrier_phis",
binding.carrier_name
));
}
}
}
// Phase 221-R: Use ExprResultResolver Box
let expr_result_value = expr_result_resolver::ExprResultResolver::resolve(
boundary.and_then(|b| b.expr_result),
boundary.map(|b| b.exit_bindings.as_slice()).unwrap_or(&[]),
&carrier_phis,
&remapper,
debug,
)?;
// expr_result is NOT a carrier - use remapped value
if let Some(remapped_expr) = remapper.get_value(expr_result_id) {
eprintln!(
"[cf_loop/joinir] Phase 221: Returning non-carrier expr_result: JoinIR {:?} → Host {:?}",
expr_result_id, remapped_expr
);
return Ok(Some(remapped_expr));
} else {
// expr_result was not remapped - this is an error
return Err(format!(
"[cf_loop/joinir] Phase 221: expr_result {:?} was not found in remapper",
expr_result_id
));
}
} else {
eprintln!("[cf_loop/joinir] Phase 221: expr_result is None, using fallback");
// Return expr_result if present, otherwise fall back to exit_phi_result_id
if let Some(resolved) = expr_result_value {
if debug {
eprintln!("[cf_loop/joinir] Phase 221-R: Returning expr_result_value {:?}", resolved);
}
Ok(Some(resolved))
} else {
eprintln!("[cf_loop/joinir] Phase 221: No boundary, using fallback");
// Fallback: return exit_phi_result_id (for legacy patterns or carrier-only loops)
if debug && exit_phi_result_id.is_some() {
eprintln!(
"[cf_loop/joinir] Phase 221-R: Returning exit_phi_result_id (fallback): {:?}",
exit_phi_result_id
);
}
Ok(exit_phi_result_id)
}
// Fallback: return exit_phi_result_id (for legacy patterns or carrier-only loops)
if debug && exit_phi_result_id.is_some() {
eprintln!(
"[cf_loop/joinir] Phase 221: Returning exit_phi_result_id (fallback): {:?}",
exit_phi_result_id
);
}
Ok(exit_phi_result_id)
}
/// Phase 3: Allocate new ValueIds for all collected values