From 9ec2e28b6a35026f3e77cb8e41a488f3851a53d0 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Wed, 17 Dec 2025 22:32:55 +0900 Subject: [PATCH] feat(joinir): add Pattern2 post-loop early return step --- .../pattern2_lowering_orchestrator.rs | 5 +- .../joinir/patterns/pattern2_steps/mod.rs | 2 +- .../post_loop_early_return_step_box.rs | 52 +++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/mir/builder/control_flow/joinir/patterns/pattern2_steps/post_loop_early_return_step_box.rs diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs index e41d0a19..fc097f9f 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_lowering_orchestrator.rs @@ -11,6 +11,7 @@ use super::pattern2_steps::apply_policy_step_box::ApplyPolicyStepBox; use super::pattern2_steps::emit_joinir_step_box::EmitJoinIRStepBox; use super::pattern2_steps::gather_facts_step_box::GatherFactsStepBox; use super::pattern2_steps::merge_step_box::MergeStepBox; +use super::pattern2_steps::post_loop_early_return_step_box::PostLoopEarlyReturnStepBox; use super::pattern2_steps::promote_step_box::PromoteStepBox; pub(crate) struct Pattern2LoweringOrchestrator; @@ -54,6 +55,8 @@ impl Pattern2LoweringOrchestrator { skeleton, )?; - MergeStepBox::merge(builder, emitted.join_module, emitted.boundary, debug) + let out = MergeStepBox::merge(builder, emitted.join_module, emitted.boundary, debug)?; + PostLoopEarlyReturnStepBox::maybe_emit(builder, promoted.inputs.post_loop_early_return.as_ref())?; + Ok(out) } } diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/mod.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/mod.rs index f91d95eb..4b6cce6d 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/mod.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/mod.rs @@ -10,5 +10,5 @@ pub(crate) mod apply_policy_step_box; pub(crate) mod emit_joinir_step_box; pub(crate) mod gather_facts_step_box; pub(crate) mod merge_step_box; +pub(crate) mod post_loop_early_return_step_box; pub(crate) mod promote_step_box; - diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/post_loop_early_return_step_box.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/post_loop_early_return_step_box.rs new file mode 100644 index 00000000..30ff174d --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_steps/post_loop_early_return_step_box.rs @@ -0,0 +1,52 @@ +//! PostLoopEarlyReturnStepBox (Phase 107) +//! +//! Responsibility: emulate `return i` inside the loop by emitting a post-loop +//! early-return guard. This keeps JoinIR lowering "break-only" while preserving +//! source semantics for the recognized family. + +use crate::ast::{ASTNode, BinaryOperator, Span}; +use crate::mir::builder::MirBuilder; + +pub(crate) struct PostLoopEarlyReturnStepBox; + +impl PostLoopEarlyReturnStepBox { + pub(crate) fn maybe_emit( + builder: &mut MirBuilder, + plan: Option< + &crate::mir::builder::control_flow::joinir::patterns::policies::balanced_depth_scan_policy::PostLoopEarlyReturnPlan, + >, + ) -> Result<(), String> { + let Some(plan) = plan else { return Ok(()); }; + + // if i < n { return i } + let cond = ASTNode::BinaryOp { + operator: BinaryOperator::Less, + left: Box::new(ASTNode::Variable { + name: plan.loop_counter_name.clone(), + span: Span::unknown(), + }), + right: Box::new(ASTNode::Variable { + name: plan.bound_name.clone(), + span: Span::unknown(), + }), + span: Span::unknown(), + }; + + let ret_stmt = ASTNode::Return { + value: Some(Box::new(ASTNode::Variable { + name: plan.loop_counter_name.clone(), + span: Span::unknown(), + })), + span: Span::unknown(), + }; + + builder.build_statement(ASTNode::If { + condition: Box::new(cond), + then_body: vec![ret_stmt], + else_body: None, + span: Span::unknown(), + })?; + + Ok(()) + } +}