feat(joinir): Phase 215-2 ExprResult exit contract for Pattern 3
Implements Phase 215 Task 215-2: Wire expr_result exit line through ExitMeta → JoinInlineBoundary → ExitLine → MIR return for Pattern 3. ## Changes ### Fix 1: JoinIR Lowerer (loop_with_if_phi_if_sum.rs:312) - Changed `carrier_only()` → `with_expr_result(sum_final, exit_meta)` - Marks sum final value as expr_result for propagation ### Fix 2: Boundary Builder (pattern3_with_if_phi.rs:176-191) - Added `.with_expr_result(Some(expr_id))` to JoinInlineBoundaryBuilder - Passes expr_result to boundary for ExitLineReconnector ### Fix 3: Final Return (pattern3_with_if_phi.rs:195-219) - Changed from always returning Void to conditional return: - Expr-position loops: Return merge_result ValueId - Statement-position loops: Return Void - Matches Pattern 2 behavior ## Test Results Primary target: - phase212_if_sum_min.hako: RC=2 achieved ✅ Regression tests: - loop_if_phi.hako: RC=2 (existing behavior maintained) ✅ - Pattern 1/2/3 tests: All PASS ✅ ## Architecture Pattern 3 now follows the same ExprResult Exit Contract as Pattern 2: 1. JoinIR lowerer creates expr_result with `with_expr_result()` 2. Boundary builder passes expr_result with `.with_expr_result()` 3. Conversion pipeline returns merge result containing exit PHI ValueId 4. Pattern dispatcher conditionally returns expr_result or Void This enables: - Expr-position loops: Loop result propagates to caller - Statement-position loops: Loop updates variable_map only (returns Void) - Unified contract: Patterns 2 and 3 follow same expr_result flow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -173,15 +173,26 @@ impl MirBuilder {
|
||||
)
|
||||
);
|
||||
|
||||
let boundary = JoinInlineBoundaryBuilder::new()
|
||||
// Phase 215-2: Pass expr_result to boundary
|
||||
let mut boundary_builder = JoinInlineBoundaryBuilder::new()
|
||||
.with_inputs(join_inputs, host_inputs)
|
||||
.with_exit_bindings(exit_bindings)
|
||||
.with_loop_var_name(Some(ctx.loop_var_name.clone()))
|
||||
.build();
|
||||
.with_loop_var_name(Some(ctx.loop_var_name.clone()));
|
||||
|
||||
// Add expr_result if present
|
||||
if let Some(expr_id) = fragment_meta.expr_result {
|
||||
trace::trace().debug(
|
||||
"pattern3/if-sum",
|
||||
&format!("Passing expr_result={:?} to boundary", expr_id)
|
||||
);
|
||||
boundary_builder = boundary_builder.with_expr_result(Some(expr_id));
|
||||
}
|
||||
|
||||
let boundary = boundary_builder.build();
|
||||
|
||||
// Execute JoinIR conversion pipeline
|
||||
use super::conversion_pipeline::JoinIRConversionPipeline;
|
||||
let _ = JoinIRConversionPipeline::execute(
|
||||
let merge_result = JoinIRConversionPipeline::execute(
|
||||
self,
|
||||
join_module,
|
||||
Some(&boundary),
|
||||
@ -189,11 +200,23 @@ impl MirBuilder {
|
||||
debug,
|
||||
)?;
|
||||
|
||||
// Return Void (loop doesn't produce values)
|
||||
use crate::mir::builder::emission::constant;
|
||||
let void_val = constant::emit_void(self);
|
||||
trace::trace().debug("pattern3/if-sum", &format!("Loop complete, returning Void {:?}", void_val));
|
||||
Ok(Some(void_val))
|
||||
// Phase 215-2: Return expr_result if present (expr-position loop)
|
||||
if let Some(expr_val) = merge_result {
|
||||
trace::trace().debug(
|
||||
"pattern3/if-sum",
|
||||
&format!("Loop complete, returning expr_result {:?}", expr_val)
|
||||
);
|
||||
Ok(Some(expr_val))
|
||||
} else {
|
||||
// Statement-position loop (carrier-only)
|
||||
use crate::mir::builder::emission::constant;
|
||||
let void_val = constant::emit_void(self);
|
||||
trace::trace().debug(
|
||||
"pattern3/if-sum",
|
||||
&format!("Loop complete, returning Void {:?}", void_val)
|
||||
);
|
||||
Ok(Some(void_val))
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 188-195: Legacy PoC lowerer (hardcoded conditions)
|
||||
|
||||
Reference in New Issue
Block a user