diff --git a/src/mir/join_ir/lowering/loop_scope_shape/case_a_lowering_shape.rs b/src/mir/join_ir/lowering/loop_scope_shape/case_a_lowering_shape.rs index 0be17499..db7e1fad 100644 --- a/src/mir/join_ir/lowering/loop_scope_shape/case_a_lowering_shape.rs +++ b/src/mir/join_ir/lowering/loop_scope_shape/case_a_lowering_shape.rs @@ -82,32 +82,48 @@ pub enum CaseALoweringShape { } impl CaseALoweringShape { - /// Detect lowering shape from LoopScopeShape + /// Detect lowering shape from LoopFeatures /// - /// Phase 170-A: Heuristic-based shape detection + /// # Phase 170-A Design Principle /// - /// Returns NotCaseA if structural requirements not met. - /// Returns one of the above if structural analysis suggests a pattern. + /// **CaseALoweringShape does NOT look at function names.** + /// Input: LoopFeatures / LoopPatternKind only (structure-based detection). + /// + /// This is the core architectural invariant that enables generic routing. /// /// # Heuristics /// - Single carrier (1) → likely StringExamination or ArrayAccumulation /// - Multiple carriers (2+) → likely IterationWithAccumulation - /// - Pinned count → disambiguation hint + /// - has_break/has_continue → affects Case-A eligibility /// - /// Note: More sophisticated pattern matching (analyzing loop body structure) - /// is deferred to Phase 170-B. - pub fn detect(scope: &super::shape::LoopScopeShape) -> Self { - use super::shape::LoopScopeShape; + /// # Phase 170-B Future Work + /// - Analyze loop body AST for more precise classification + /// - Distinguish StringExamination vs ArrayAccumulation + /// + /// # Arguments + /// * `features` - LoopFeatures (structure-based, name-agnostic) + /// * `carrier_count` - Number of carrier variables from LoopScopeShape + /// * `has_progress_carrier` - Whether progress carrier exists + pub fn detect_from_features( + features: &crate::mir::loop_pattern_detection::LoopFeatures, + carrier_count: usize, + has_progress_carrier: bool, + ) -> Self { + // Case-A requirement: must have a progress carrier + if !has_progress_carrier { + return CaseALoweringShape::NotCaseA; + } - // Check if structurally Case-A - if scope.progress_carrier.is_none() { + // Case-A requirement: no complex control flow (continue) + // Note: break is allowed (StringExamination patterns use break) + if features.has_continue { return CaseALoweringShape::NotCaseA; } // Phase 170-A: Simple heuristic based on carrier count - match scope.carriers.len() { + match carrier_count { 0 => { - // This shouldn't happen if progress_carrier is Some, but be safe + // This shouldn't happen if has_progress_carrier is true, but be safe CaseALoweringShape::NotCaseA } 1 => { @@ -124,6 +140,33 @@ impl CaseALoweringShape { } } + /// Legacy wrapper: Detect from LoopScopeShape (deprecated, use detect_from_features) + /// + /// Phase 170-A: Kept for backward compatibility during transition. + #[deprecated( + since = "Phase 170-A", + note = "Use detect_from_features() with LoopFeatures instead" + )] + pub fn detect(scope: &super::shape::LoopScopeShape) -> Self { + // Construct minimal LoopFeatures from LoopScopeShape + // Note: This loses some information (has_break, has_continue not available) + let has_progress_carrier = scope.progress_carrier.is_some(); + let carrier_count = scope.carriers.len(); + + // Create stub features (Phase 170-B will use real LoopFeatures) + let stub_features = crate::mir::loop_pattern_detection::LoopFeatures { + has_break: false, // Unknown from LoopScopeShape alone + has_continue: false, // Unknown from LoopScopeShape alone + has_if: false, + has_if_else_phi: false, + carrier_count, + break_count: 0, + continue_count: 0, + }; + + Self::detect_from_features(&stub_features, carrier_count, has_progress_carrier) + } + /// Is this a recognized lowering shape? pub fn is_recognized(&self) -> bool { !matches!(self, CaseALoweringShape::NotCaseA | CaseALoweringShape::Generic)