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 db7e1fad..c6278ba4 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,7 +82,7 @@ pub enum CaseALoweringShape { } impl CaseALoweringShape { - /// Detect lowering shape from LoopFeatures + /// Detect lowering shape from LoopFeatures (legacy, use detect_with_updates when possible) /// /// # Phase 170-A Design Principle /// @@ -96,9 +96,8 @@ impl CaseALoweringShape { /// - Multiple carriers (2+) → likely IterationWithAccumulation /// - has_break/has_continue → affects Case-A eligibility /// - /// # Phase 170-B Future Work - /// - Analyze loop body AST for more precise classification - /// - Distinguish StringExamination vs ArrayAccumulation + /// # Phase 170-C Future Work + /// - Use detect_with_updates() for better single-carrier classification /// /// # Arguments /// * `features` - LoopFeatures (structure-based, name-agnostic) @@ -128,7 +127,7 @@ impl CaseALoweringShape { } 1 => { // Single carrier: could be StringExamination or ArrayAccumulation - // Further distinction requires analyzing loop body (Phase 170-B) + // Further distinction requires analyzing loop body (Phase 170-C) // For now, return Generic to allow both paths to be tried CaseALoweringShape::Generic } @@ -140,6 +139,83 @@ impl CaseALoweringShape { } } + /// Phase 170-C-1: Carrier pattern を使った精度向上版 + /// + /// carrier_count == 1 の場合に carrier 名パターンで StringExamination vs ArrayAccumulation を区別 + /// + /// # Design Notes + /// + /// 本来は LoopUpdateAnalyzer を使って AST レベルの更新式を解析する予定だったが、 + /// loop_to_join.rs は MIR レベルで動作するため AST にアクセスできない。 + /// + /// そのため、Phase 170-C-1 では以下の簡易的なヒューリスティックを使用: + /// - progress carrier の名前が 'i', 'e', 'idx' などの典型的なインデックス名 → StringExamination + /// - それ以外 → ArrayAccumulation + /// + /// # Future Work (Phase 170-C-2+) + /// + /// - MIR 命令を解析して更新パターンを抽出(BinOp の定数加算パターンなど) + /// - より正確な分類を実現 + /// + /// # Arguments + /// * `features` - LoopFeatures (structure-based) + /// * `carrier_count` - Number of carrier variables + /// * `has_progress_carrier` - Whether progress carrier exists + /// * `progress_carrier_name` - Name of progress carrier (if available) + /// + /// # Returns + /// More precise CaseALoweringShape classification + pub fn detect_with_carrier_name( + features: &crate::mir::loop_pattern_detection::LoopFeatures, + carrier_count: usize, + has_progress_carrier: bool, + progress_carrier_name: Option<&str>, + ) -> Self { + // Case-A requirement: must have a progress carrier + if !has_progress_carrier { + return CaseALoweringShape::NotCaseA; + } + + // Case-A requirement: no complex control flow (continue) + if features.has_continue { + return CaseALoweringShape::NotCaseA; + } + + match carrier_count { + 0 => CaseALoweringShape::NotCaseA, + 1 => { + // Phase 170-C-1: carrier 名パターンで StringExamination vs ArrayAccumulation を区別 + if let Some(name) = progress_carrier_name { + if Self::is_typical_index_name(name) { + // 'i', 'e', 'idx' などの典型的なインデックス名 → StringExamination (skip/trim 系) + CaseALoweringShape::StringExamination + } else { + // それ以外 → ArrayAccumulation + CaseALoweringShape::ArrayAccumulation + } + } else { + // carrier 名が不明な場合は Generic(従来通り) + CaseALoweringShape::Generic + } + } + 2.. => CaseALoweringShape::IterationWithAccumulation, + } + } + + /// Typical index variable name detection + /// + /// StringExamination パターン(skip/trim)で使われる典型的なインデックス名: + /// - 'i', 'e', 'idx', 'pos', 'start', 'end' + /// + /// ArrayAccumulation パターンは通常: + /// - より意味のある名前 ('result', 'items', 'defs' など) + fn is_typical_index_name(name: &str) -> bool { + matches!( + name, + "i" | "e" | "idx" | "index" | "pos" | "position" | "start" | "end" + ) + } + /// Legacy wrapper: Detect from LoopScopeShape (deprecated, use detect_from_features) /// /// Phase 170-A: Kept for backward compatibility during transition. diff --git a/src/mir/join_ir/lowering/loop_to_join.rs b/src/mir/join_ir/lowering/loop_to_join.rs index 94129b28..32c8a58b 100644 --- a/src/mir/join_ir/lowering/loop_to_join.rs +++ b/src/mir/join_ir/lowering/loop_to_join.rs @@ -382,14 +382,40 @@ impl LoopToJoinLowerer { // // This enables gradual migration: existing name-based code continues to work, // while new patterns can be added purely by structure detection. - #[allow(deprecated)] - let shape = CaseALoweringShape::detect(&scope); + + // Phase 170-C-1: Use carrier name-based detection for improved accuracy + // Extract progress carrier name from scope + let progress_carrier_name = scope.progress_carrier.as_deref(); + + // Construct minimal LoopFeatures from scope (for now) + // TODO: Pass real LoopFeatures from LoopPatternDetection when available + let stub_features = crate::mir::loop_pattern_detection::LoopFeatures { + has_break: false, // Unknown at this level + has_continue: false, // Unknown at this level + has_if: false, + has_if_else_phi: false, + carrier_count: scope.carriers.len(), + break_count: 0, + continue_count: 0, + }; + + let has_progress_carrier = scope.progress_carrier.is_some(); + let carrier_count = scope.carriers.len(); + + // Phase 170-C-1: Use new carrier name-based detection + let shape = CaseALoweringShape::detect_with_carrier_name( + &stub_features, + carrier_count, + has_progress_carrier, + progress_carrier_name, + ); if self.debug { eprintln!( - "[LoopToJoinLowerer] Phase 170-A: shape={:?}, name={:?}", + "[LoopToJoinLowerer] Phase 170-C-1: shape={:?}, name={:?}, carrier={:?}", shape.name(), - name + name, + progress_carrier_name ); }