feat(joinir): Phase 131-11 A-C - InfiniteEarlyExit パターン追加(検出部分)

## Step A: Feature Detection
- LoopPatternKind::InfiniteEarlyExit (Pattern 5) 追加
- LoopFeatures::is_infinite_loop フィールド追加
- detect_infinite_loop() で loop(true) 検出

## Step B: Classification Logic
- classify() を更新: Pattern 5 を Pattern 4 より優先
- Pattern 4 を狭化: has_continue && !has_break のみ
- 誤ルーティング完全除去

## Step C: Pattern Module
- pattern5_infinite_early_exit.rs 新規作成
- Fail-Fast 設計: 超狭い shape guard
- lowering はスケルトン(Phase 131-11-D で実装)

## 動作確認
- Pattern 5 正常検出 
- Shape guards 動作(1 break, 1 continue, 1 carrier)
- Pattern 4 誤ルーティング回避 

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-14 09:59:34 +09:00
parent e1d706d2e0
commit 233a49d902
8 changed files with 253 additions and 17 deletions

View File

@ -28,7 +28,7 @@ use crate::mir::loop_form::LoopForm;
/// Loop pattern classification based on structure.
///
/// This enum represents the 4 main loop patterns we support.
/// This enum represents the 5 main loop patterns we support.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LoopPatternKind {
/// Pattern 1: Simple While Loop
@ -52,6 +52,12 @@ pub enum LoopPatternKind {
/// - No break statements (for simplicity)
Pattern4Continue,
/// Pattern 5: Infinite Loop with Early Exit (Phase 131-11)
/// - Infinite loop: condition is `loop(true)`
/// - Has both break AND continue
/// - Minimal carrier (1 counter-like variable)
InfiniteEarlyExit,
/// Pattern not recognized
Unknown,
}
@ -66,13 +72,14 @@ impl LoopPatternKind {
LoopPatternKind::Pattern2Break => "Pattern 2: Loop with Conditional Break",
LoopPatternKind::Pattern3IfPhi => "Pattern 3: Loop with If-Else PHI",
LoopPatternKind::Pattern4Continue => "Pattern 4: Loop with Continue",
LoopPatternKind::InfiniteEarlyExit => "Pattern 5: Infinite Loop with Early Exit",
LoopPatternKind::Unknown => "Unknown Pattern",
}
}
/// Phase 193-3: Get numeric pattern ID
///
/// Returns the pattern number (1-4) or 0 for unknown.
/// Returns the pattern number (1-5) or 0 for unknown.
/// Useful for priority sorting.
pub fn pattern_id(&self) -> u8 {
match self {
@ -80,6 +87,7 @@ impl LoopPatternKind {
LoopPatternKind::Pattern2Break => 2,
LoopPatternKind::Pattern3IfPhi => 3,
LoopPatternKind::Pattern4Continue => 4,
LoopPatternKind::InfiniteEarlyExit => 5,
LoopPatternKind::Unknown => 0,
}
}
@ -97,7 +105,9 @@ impl LoopPatternKind {
pub fn has_special_control_flow(&self) -> bool {
matches!(
self,
LoopPatternKind::Pattern2Break | LoopPatternKind::Pattern4Continue
LoopPatternKind::Pattern2Break
| LoopPatternKind::Pattern4Continue
| LoopPatternKind::InfiniteEarlyExit
)
}
@ -137,6 +147,9 @@ pub struct LoopFeatures {
/// Number of continue targets
pub continue_count: usize,
/// Phase 131-11: Is this an infinite loop? (condition == true)
pub is_infinite_loop: bool,
/// Phase 170-C-2b: Carrier update pattern summary
///
/// Contains UpdateKind (CounterLike/AccumulationLike/Other) for each carrier.
@ -152,14 +165,15 @@ impl LoopFeatures {
/// Returns a formatted string showing all feature values for debugging.
pub fn debug_stats(&self) -> String {
format!(
"LoopFeatures {{ break: {}, continue: {}, if: {}, if_else_phi: {}, carriers: {}, break_count: {}, continue_count: {} }}",
"LoopFeatures {{ break: {}, continue: {}, if: {}, if_else_phi: {}, carriers: {}, break_count: {}, continue_count: {}, infinite: {} }}",
self.has_break,
self.has_continue,
self.has_if,
self.has_if_else_phi,
self.carrier_count,
self.break_count,
self.continue_count
self.continue_count,
self.is_infinite_loop
)
}
@ -236,6 +250,7 @@ pub(crate) fn extract_features(
carrier_count,
break_count,
continue_count,
is_infinite_loop: false, // Phase 131-11: LoopForm doesn't have condition info, default to false
update_summary,
}
}
@ -246,19 +261,24 @@ pub(crate) fn extract_features(
/// structure-based rules. It does NOT depend on function names or
/// variable names like "sum".
///
/// # Pattern Classification Rules (Phase 212.5: Structural if detection)
/// # Pattern Classification Rules (Phase 131-11: InfiniteEarlyExit added)
///
/// 1. **Pattern 4 (Continue)**: `has_continue == true`
/// - Priority: Check first (most specific)
/// 1. **Pattern 5 (InfiniteEarlyExit)**: `is_infinite_loop && has_break && has_continue`
/// - Priority: Check first (most specific - infinite loop with both break and continue)
/// - Phase 131-11: New pattern for `loop(true) { break + continue }`
///
/// 2. **Pattern 3 (If-PHI)**: `has_if && carrier_count >= 1 && !has_break && !has_continue`
/// 2. **Pattern 4 (Continue)**: `has_continue && !has_break`
/// - Priority: Check second (has continue but no break)
/// - Phase 131-11: Narrowed to exclude break+continue cases
///
/// 3. **Pattern 3 (If-PHI)**: `has_if && carrier_count >= 1 && !has_break && !has_continue`
/// - Phase 212.5: Changed from carrier_count > 1 to structural if detection
/// - Includes single-carrier if-update patterns (e.g., if-sum with 1 carrier)
///
/// 3. **Pattern 2 (Break)**: `has_break && !has_continue`
/// 4. **Pattern 2 (Break)**: `has_break && !has_continue`
/// - Has break but no continue
///
/// 4. **Pattern 1 (Simple While)**: `!has_break && !has_continue && !has_if`
/// 5. **Pattern 1 (Simple While)**: `!has_break && !has_continue && !has_if`
/// - Phase 212.5: Exclude loops with if statements
/// - No control flow alterations
///
@ -274,8 +294,15 @@ pub(crate) fn extract_features(
/// Both routers (`router.rs` and `loop_pattern_router.rs`) use this
/// function to avoid duplicate detection logic.
pub fn classify(features: &LoopFeatures) -> LoopPatternKind {
// Pattern 4: Continue (highest priority)
if features.has_continue {
// Phase 131-11: Pattern 5: InfiniteEarlyExit (highest priority - most specific)
// MUST check before Pattern 4 to avoid misrouting break+continue cases
if features.is_infinite_loop && features.has_break && features.has_continue {
return LoopPatternKind::InfiniteEarlyExit;
}
// Pattern 4: Continue (no break)
// Phase 131-11: Narrowed to exclude break+continue (those go to Pattern 5)
if features.has_continue && !features.has_break {
return LoopPatternKind::Pattern4Continue;
}
@ -335,6 +362,12 @@ pub fn classify_with_diagnosis(features: &LoopFeatures) -> (LoopPatternKind, Str
LoopPatternKind::Pattern1SimpleWhile => {
"Simple while loop with no special control flow".to_string()
}
LoopPatternKind::InfiniteEarlyExit => {
format!(
"Infinite loop (loop(true)) with both break and continue (break_count={}, continue_count={})",
features.break_count, features.continue_count
)
}
LoopPatternKind::Unknown => {
format!("Unknown pattern: {}", features.debug_stats())
}