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:
@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user