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:
@ -71,6 +71,7 @@ pub(crate) fn detect_break_in_body(body: &[ASTNode]) -> bool {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
|
/// * `condition` - Loop condition AST node (Phase 131-11: for infinite loop detection)
|
||||||
/// * `body` - Loop body statements to analyze
|
/// * `body` - Loop body statements to analyze
|
||||||
/// * `has_continue` - Pre-computed continue presence (for optimization)
|
/// * `has_continue` - Pre-computed continue presence (for optimization)
|
||||||
/// * `has_break` - Pre-computed break presence (for optimization)
|
/// * `has_break` - Pre-computed break presence (for optimization)
|
||||||
@ -78,7 +79,12 @@ pub(crate) fn detect_break_in_body(body: &[ASTNode]) -> bool {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A LoopFeatures struct containing all detected structural characteristics
|
/// A LoopFeatures struct containing all detected structural characteristics
|
||||||
pub(crate) fn extract_features(body: &[ASTNode], has_continue: bool, has_break: bool) -> LoopFeatures {
|
pub(crate) fn extract_features(
|
||||||
|
condition: &ASTNode,
|
||||||
|
body: &[ASTNode],
|
||||||
|
has_continue: bool,
|
||||||
|
has_break: bool,
|
||||||
|
) -> LoopFeatures {
|
||||||
// Phase 212.5: Detect ANY if statement in loop body (structural detection)
|
// Phase 212.5: Detect ANY if statement in loop body (structural detection)
|
||||||
let has_if = detect_if_in_body(body);
|
let has_if = detect_if_in_body(body);
|
||||||
|
|
||||||
@ -88,6 +94,9 @@ pub(crate) fn extract_features(body: &[ASTNode], has_continue: bool, has_break:
|
|||||||
// Count carrier variables (approximation based on assignments)
|
// Count carrier variables (approximation based on assignments)
|
||||||
let carrier_count = count_carriers_in_body(body);
|
let carrier_count = count_carriers_in_body(body);
|
||||||
|
|
||||||
|
// Phase 131-11: Detect infinite loop (condition == true)
|
||||||
|
let is_infinite_loop = detect_infinite_loop(condition);
|
||||||
|
|
||||||
LoopFeatures {
|
LoopFeatures {
|
||||||
has_break,
|
has_break,
|
||||||
has_continue,
|
has_continue,
|
||||||
@ -96,11 +105,31 @@ pub(crate) fn extract_features(body: &[ASTNode], has_continue: bool, has_break:
|
|||||||
carrier_count,
|
carrier_count,
|
||||||
break_count: if has_break { 1 } else { 0 },
|
break_count: if has_break { 1 } else { 0 },
|
||||||
continue_count: if has_continue { 1 } else { 0 },
|
continue_count: if has_continue { 1 } else { 0 },
|
||||||
|
is_infinite_loop,
|
||||||
// Phase 170-C-2b: AST-based extraction doesn't have carrier names yet
|
// Phase 170-C-2b: AST-based extraction doesn't have carrier names yet
|
||||||
update_summary: None,
|
update_summary: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 131-11: Detect infinite loop (condition == Literal(Bool(true)))
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `condition` - Loop condition AST node
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// `true` if condition is a boolean literal with value true
|
||||||
|
fn detect_infinite_loop(condition: &ASTNode) -> bool {
|
||||||
|
matches!(
|
||||||
|
condition,
|
||||||
|
ASTNode::Literal {
|
||||||
|
value: crate::ast::LiteralValue::Bool(true),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Phase 212.5: Detect ANY if statement in loop body (structural detection)
|
/// Phase 212.5: Detect ANY if statement in loop body (structural detection)
|
||||||
///
|
///
|
||||||
/// This function detects any if statement, regardless of whether it has an else branch.
|
/// This function detects any if statement, regardless of whether it has an else branch.
|
||||||
|
|||||||
@ -55,6 +55,7 @@ pub(in crate::mir::builder) mod pattern2_with_break;
|
|||||||
pub(in crate::mir::builder) mod pattern3_with_if_phi;
|
pub(in crate::mir::builder) mod pattern3_with_if_phi;
|
||||||
pub(in crate::mir::builder) mod pattern4_carrier_analyzer;
|
pub(in crate::mir::builder) mod pattern4_carrier_analyzer;
|
||||||
pub(in crate::mir::builder) mod pattern4_with_continue;
|
pub(in crate::mir::builder) mod pattern4_with_continue;
|
||||||
|
pub(in crate::mir::builder) mod pattern5_infinite_early_exit; // Phase 131-11
|
||||||
pub(in crate::mir::builder) mod pattern_pipeline;
|
pub(in crate::mir::builder) mod pattern_pipeline;
|
||||||
pub(in crate::mir::builder) mod router;
|
pub(in crate::mir::builder) mod router;
|
||||||
pub(in crate::mir::builder) mod trim_loop_lowering; // Phase 180: Dedicated Trim/P5 lowering module
|
pub(in crate::mir::builder) mod trim_loop_lowering; // Phase 180: Dedicated Trim/P5 lowering module
|
||||||
|
|||||||
@ -0,0 +1,155 @@
|
|||||||
|
//! Pattern 5: Infinite Loop with Early Exit (Phase 131-11)
|
||||||
|
//!
|
||||||
|
//! # Pattern Overview
|
||||||
|
//!
|
||||||
|
//! Handles `loop(true)` with both `break` and `continue` statements.
|
||||||
|
//! This is a specialized pattern for infinite loops with early exit conditions.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! ```nyash
|
||||||
|
//! local counter = 0
|
||||||
|
//! loop (true) {
|
||||||
|
//! counter = counter + 1
|
||||||
|
//! if counter == 3 { break }
|
||||||
|
//! continue
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Shape Guard (Fail-Fast)
|
||||||
|
//!
|
||||||
|
//! - Condition MUST be `true` literal (infinite loop)
|
||||||
|
//! - MUST have exactly 1 break statement
|
||||||
|
//! - MUST have exactly 1 continue statement
|
||||||
|
//! - Carriers: MUST be exactly 1 counter-like variable
|
||||||
|
//! - No nested loops (not yet supported)
|
||||||
|
//!
|
||||||
|
//! # Implementation Status
|
||||||
|
//!
|
||||||
|
//! Phase 131-11-C: Minimal skeleton with Fail-Fast guards
|
||||||
|
//! - Shape validation implemented
|
||||||
|
//! - Lowering logic: TODO (will fail with explicit error)
|
||||||
|
|
||||||
|
use super::super::trace;
|
||||||
|
use crate::mir::builder::MirBuilder;
|
||||||
|
use crate::mir::loop_pattern_detection::LoopPatternKind;
|
||||||
|
use crate::mir::ValueId;
|
||||||
|
|
||||||
|
use super::router::LoopPatternContext;
|
||||||
|
|
||||||
|
/// Phase 131-11: Pattern detection for InfiniteEarlyExit
|
||||||
|
///
|
||||||
|
/// This function checks if the loop matches Pattern 5 characteristics.
|
||||||
|
/// Uses Fail-Fast approach: narrow shape guard to avoid false positives.
|
||||||
|
pub(crate) fn can_lower(_builder: &MirBuilder, ctx: &LoopPatternContext) -> bool {
|
||||||
|
let debug = ctx.debug;
|
||||||
|
|
||||||
|
// Step 1: Check pattern classification
|
||||||
|
if ctx.pattern_kind != LoopPatternKind::InfiniteEarlyExit {
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern5/detect",
|
||||||
|
&format!(
|
||||||
|
"Pattern kind mismatch: expected InfiniteEarlyExit, got {:?}",
|
||||||
|
ctx.pattern_kind
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Shape guard - infinite loop condition (true literal)
|
||||||
|
if !ctx.features.is_infinite_loop {
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug("pattern5/detect", "Not an infinite loop (condition != true)");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Shape guard - exactly 1 break
|
||||||
|
if ctx.features.break_count != 1 {
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern5/detect",
|
||||||
|
&format!(
|
||||||
|
"Break count mismatch: expected 1, got {}",
|
||||||
|
ctx.features.break_count
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Shape guard - exactly 1 continue
|
||||||
|
if ctx.features.continue_count != 1 {
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern5/detect",
|
||||||
|
&format!(
|
||||||
|
"Continue count mismatch: expected 1, got {}",
|
||||||
|
ctx.features.continue_count
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Shape guard - exactly 1 carrier (counter-like)
|
||||||
|
// Phase 131-11-C: Start with minimal carrier requirement
|
||||||
|
if ctx.features.carrier_count != 1 {
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern5/detect",
|
||||||
|
&format!(
|
||||||
|
"Carrier count mismatch: expected 1, got {}",
|
||||||
|
ctx.features.carrier_count
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All shape guards passed
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern5/detect",
|
||||||
|
&format!(
|
||||||
|
"Pattern 5 detected: infinite={}, break={}, continue={}, carriers={}",
|
||||||
|
ctx.features.is_infinite_loop,
|
||||||
|
ctx.features.break_count,
|
||||||
|
ctx.features.continue_count,
|
||||||
|
ctx.features.carrier_count
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 131-11: Lower InfiniteEarlyExit pattern to JoinIR
|
||||||
|
///
|
||||||
|
/// # Implementation Status
|
||||||
|
///
|
||||||
|
/// Phase 131-11-C: Minimal skeleton - returns Fail-Fast error
|
||||||
|
/// Phase 131-11-D: TODO - implement actual lowering logic
|
||||||
|
pub(crate) fn lower(
|
||||||
|
_builder: &mut MirBuilder,
|
||||||
|
ctx: &LoopPatternContext,
|
||||||
|
) -> Result<Option<ValueId>, String> {
|
||||||
|
let debug = ctx.debug;
|
||||||
|
|
||||||
|
if debug {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern5/lower",
|
||||||
|
"Phase 131-11-C: Pattern 5 lowering not yet implemented",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 131-11-C: Fail-Fast with explicit error message
|
||||||
|
Err(format!(
|
||||||
|
"Pattern 5 (InfiniteEarlyExit) lowering not yet implemented (Phase 131-11-C skeleton)\n\
|
||||||
|
Detected: loop(true) with {} break(s), {} continue(s), {} carrier(s)\n\
|
||||||
|
Next step: Implement lowering logic in Phase 131-11-D",
|
||||||
|
ctx.features.break_count, ctx.features.continue_count, ctx.features.carrier_count
|
||||||
|
))
|
||||||
|
}
|
||||||
@ -69,6 +69,7 @@ impl<'a> LoopPatternContext<'a> {
|
|||||||
/// Phase 194+: Automatically detects continue/break statements in body
|
/// Phase 194+: Automatically detects continue/break statements in body
|
||||||
/// Phase 192: Extract features and classify pattern from AST
|
/// Phase 192: Extract features and classify pattern from AST
|
||||||
/// Phase 193: Feature extraction delegated to ast_feature_extractor module
|
/// Phase 193: Feature extraction delegated to ast_feature_extractor module
|
||||||
|
/// Phase 131-11: Detects infinite loop condition
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
condition: &'a ASTNode,
|
condition: &'a ASTNode,
|
||||||
body: &'a [ASTNode],
|
body: &'a [ASTNode],
|
||||||
@ -80,7 +81,8 @@ impl<'a> LoopPatternContext<'a> {
|
|||||||
let has_break = ast_features::detect_break_in_body(body);
|
let has_break = ast_features::detect_break_in_body(body);
|
||||||
|
|
||||||
// Phase 193: Extract features using modularized extractor
|
// Phase 193: Extract features using modularized extractor
|
||||||
let features = ast_features::extract_features(body, has_continue, has_break);
|
// Phase 131-11: Pass condition for infinite loop detection
|
||||||
|
let features = ast_features::extract_features(condition, body, has_continue, has_break);
|
||||||
|
|
||||||
// Phase 192: Classify pattern based on features
|
// Phase 192: Classify pattern based on features
|
||||||
let pattern_kind = crate::mir::loop_pattern_detection::classify(&features);
|
let pattern_kind = crate::mir::loop_pattern_detection::classify(&features);
|
||||||
@ -135,10 +137,14 @@ pub(crate) struct LoopPatternEntry {
|
|||||||
/// Static table of all registered loop patterns.
|
/// Static table of all registered loop patterns.
|
||||||
/// Patterns are tried in priority order (lowest first).
|
/// Patterns are tried in priority order (lowest first).
|
||||||
///
|
///
|
||||||
/// # Current Patterns (Phase 192: Structure-based detection)
|
/// # Current Patterns (Phase 131-11: Pattern 5 added)
|
||||||
///
|
///
|
||||||
/// All patterns now use structure-based detection via LoopFeatures and classify():
|
/// All patterns now use structure-based detection via LoopFeatures and classify():
|
||||||
///
|
///
|
||||||
|
/// - Pattern 5 (priority 1): Infinite Loop with Early Exit (llvm_stage3_loop_only.hako) [Phase 131-11]
|
||||||
|
/// - Detection: pattern_kind == InfiniteEarlyExit
|
||||||
|
/// - Structure: is_infinite_loop && has_break && has_continue
|
||||||
|
///
|
||||||
/// - Pattern 4 (priority 5): Loop with Continue (loop_continue_pattern4.hako)
|
/// - Pattern 4 (priority 5): Loop with Continue (loop_continue_pattern4.hako)
|
||||||
/// - Detection: pattern_kind == Pattern4Continue
|
/// - Detection: pattern_kind == Pattern4Continue
|
||||||
/// - Structure: has_continue && !has_break
|
/// - Structure: has_continue && !has_break
|
||||||
@ -157,9 +163,15 @@ pub(crate) struct LoopPatternEntry {
|
|||||||
///
|
///
|
||||||
/// Note: func_name is now only used for debug logging, not pattern detection
|
/// Note: func_name is now only used for debug logging, not pattern detection
|
||||||
pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
|
pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
|
||||||
|
LoopPatternEntry {
|
||||||
|
name: "Pattern5_InfiniteEarlyExit",
|
||||||
|
priority: 1, // Highest priority - most specific (infinite loop with break+continue)
|
||||||
|
detect: super::pattern5_infinite_early_exit::can_lower,
|
||||||
|
lower: super::pattern5_infinite_early_exit::lower,
|
||||||
|
},
|
||||||
LoopPatternEntry {
|
LoopPatternEntry {
|
||||||
name: "Pattern4_WithContinue",
|
name: "Pattern4_WithContinue",
|
||||||
priority: 5, // Highest priority - continue is most specific
|
priority: 5, // Second priority - continue without break
|
||||||
detect: super::pattern4_with_continue::can_lower,
|
detect: super::pattern4_with_continue::can_lower,
|
||||||
lower: super::pattern4_with_continue::lower,
|
lower: super::pattern4_with_continue::lower,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -164,6 +164,10 @@ pub fn try_lower_loop_pattern_to_joinir(
|
|||||||
return Some(inst);
|
return Some(inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LoopPatternKind::InfiniteEarlyExit => {
|
||||||
|
// Phase 131-11: Not implemented yet in LoopForm-based router
|
||||||
|
eprintln!("[try_lower_loop_pattern] ⚠️ Pattern 5 (InfiniteEarlyExit) not implemented in LoopForm router");
|
||||||
|
}
|
||||||
LoopPatternKind::Unknown => {
|
LoopPatternKind::Unknown => {
|
||||||
eprintln!("[try_lower_loop_pattern] ❌ Unknown pattern, fallback to existing lowering");
|
eprintln!("[try_lower_loop_pattern] ❌ Unknown pattern, fallback to existing lowering");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -314,6 +314,7 @@ impl CaseALoweringShape {
|
|||||||
carrier_count,
|
carrier_count,
|
||||||
break_count: 0,
|
break_count: 0,
|
||||||
continue_count: 0,
|
continue_count: 0,
|
||||||
|
is_infinite_loop: false, // Phase 131-11: Unknown from LoopScopeShape alone
|
||||||
update_summary: Some(update_summary),
|
update_summary: Some(update_summary),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,7 @@ impl LoopViewBuilder {
|
|||||||
carrier_count: scope.carriers.len(),
|
carrier_count: scope.carriers.len(),
|
||||||
break_count: 0,
|
break_count: 0,
|
||||||
continue_count: 0,
|
continue_count: 0,
|
||||||
|
is_infinite_loop: false, // Phase 131-11: Unknown from LoopScopeShape alone
|
||||||
update_summary: Some(update_summary),
|
update_summary: Some(update_summary),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ use crate::mir::loop_form::LoopForm;
|
|||||||
|
|
||||||
/// Loop pattern classification based on structure.
|
/// 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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum LoopPatternKind {
|
pub enum LoopPatternKind {
|
||||||
/// Pattern 1: Simple While Loop
|
/// Pattern 1: Simple While Loop
|
||||||
@ -52,6 +52,12 @@ pub enum LoopPatternKind {
|
|||||||
/// - No break statements (for simplicity)
|
/// - No break statements (for simplicity)
|
||||||
Pattern4Continue,
|
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
|
/// Pattern not recognized
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
@ -66,13 +72,14 @@ impl LoopPatternKind {
|
|||||||
LoopPatternKind::Pattern2Break => "Pattern 2: Loop with Conditional Break",
|
LoopPatternKind::Pattern2Break => "Pattern 2: Loop with Conditional Break",
|
||||||
LoopPatternKind::Pattern3IfPhi => "Pattern 3: Loop with If-Else PHI",
|
LoopPatternKind::Pattern3IfPhi => "Pattern 3: Loop with If-Else PHI",
|
||||||
LoopPatternKind::Pattern4Continue => "Pattern 4: Loop with Continue",
|
LoopPatternKind::Pattern4Continue => "Pattern 4: Loop with Continue",
|
||||||
|
LoopPatternKind::InfiniteEarlyExit => "Pattern 5: Infinite Loop with Early Exit",
|
||||||
LoopPatternKind::Unknown => "Unknown Pattern",
|
LoopPatternKind::Unknown => "Unknown Pattern",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 193-3: Get numeric pattern ID
|
/// 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.
|
/// Useful for priority sorting.
|
||||||
pub fn pattern_id(&self) -> u8 {
|
pub fn pattern_id(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
@ -80,6 +87,7 @@ impl LoopPatternKind {
|
|||||||
LoopPatternKind::Pattern2Break => 2,
|
LoopPatternKind::Pattern2Break => 2,
|
||||||
LoopPatternKind::Pattern3IfPhi => 3,
|
LoopPatternKind::Pattern3IfPhi => 3,
|
||||||
LoopPatternKind::Pattern4Continue => 4,
|
LoopPatternKind::Pattern4Continue => 4,
|
||||||
|
LoopPatternKind::InfiniteEarlyExit => 5,
|
||||||
LoopPatternKind::Unknown => 0,
|
LoopPatternKind::Unknown => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +105,9 @@ impl LoopPatternKind {
|
|||||||
pub fn has_special_control_flow(&self) -> bool {
|
pub fn has_special_control_flow(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
LoopPatternKind::Pattern2Break | LoopPatternKind::Pattern4Continue
|
LoopPatternKind::Pattern2Break
|
||||||
|
| LoopPatternKind::Pattern4Continue
|
||||||
|
| LoopPatternKind::InfiniteEarlyExit
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +147,9 @@ pub struct LoopFeatures {
|
|||||||
/// Number of continue targets
|
/// Number of continue targets
|
||||||
pub continue_count: usize,
|
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
|
/// Phase 170-C-2b: Carrier update pattern summary
|
||||||
///
|
///
|
||||||
/// Contains UpdateKind (CounterLike/AccumulationLike/Other) for each carrier.
|
/// Contains UpdateKind (CounterLike/AccumulationLike/Other) for each carrier.
|
||||||
@ -152,14 +165,15 @@ impl LoopFeatures {
|
|||||||
/// Returns a formatted string showing all feature values for debugging.
|
/// Returns a formatted string showing all feature values for debugging.
|
||||||
pub fn debug_stats(&self) -> String {
|
pub fn debug_stats(&self) -> String {
|
||||||
format!(
|
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_break,
|
||||||
self.has_continue,
|
self.has_continue,
|
||||||
self.has_if,
|
self.has_if,
|
||||||
self.has_if_else_phi,
|
self.has_if_else_phi,
|
||||||
self.carrier_count,
|
self.carrier_count,
|
||||||
self.break_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,
|
carrier_count,
|
||||||
break_count,
|
break_count,
|
||||||
continue_count,
|
continue_count,
|
||||||
|
is_infinite_loop: false, // Phase 131-11: LoopForm doesn't have condition info, default to false
|
||||||
update_summary,
|
update_summary,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,19 +261,24 @@ pub(crate) fn extract_features(
|
|||||||
/// structure-based rules. It does NOT depend on function names or
|
/// structure-based rules. It does NOT depend on function names or
|
||||||
/// variable names like "sum".
|
/// 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`
|
/// 1. **Pattern 5 (InfiniteEarlyExit)**: `is_infinite_loop && has_break && has_continue`
|
||||||
/// - Priority: Check first (most specific)
|
/// - 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
|
/// - 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)
|
/// - 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
|
/// - 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
|
/// - Phase 212.5: Exclude loops with if statements
|
||||||
/// - No control flow alterations
|
/// - No control flow alterations
|
||||||
///
|
///
|
||||||
@ -274,8 +294,15 @@ pub(crate) fn extract_features(
|
|||||||
/// Both routers (`router.rs` and `loop_pattern_router.rs`) use this
|
/// Both routers (`router.rs` and `loop_pattern_router.rs`) use this
|
||||||
/// function to avoid duplicate detection logic.
|
/// function to avoid duplicate detection logic.
|
||||||
pub fn classify(features: &LoopFeatures) -> LoopPatternKind {
|
pub fn classify(features: &LoopFeatures) -> LoopPatternKind {
|
||||||
// Pattern 4: Continue (highest priority)
|
// Phase 131-11: Pattern 5: InfiniteEarlyExit (highest priority - most specific)
|
||||||
if features.has_continue {
|
// 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;
|
return LoopPatternKind::Pattern4Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +362,12 @@ pub fn classify_with_diagnosis(features: &LoopFeatures) -> (LoopPatternKind, Str
|
|||||||
LoopPatternKind::Pattern1SimpleWhile => {
|
LoopPatternKind::Pattern1SimpleWhile => {
|
||||||
"Simple while loop with no special control flow".to_string()
|
"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 => {
|
LoopPatternKind::Unknown => {
|
||||||
format!("Unknown pattern: {}", features.debug_stats())
|
format!("Unknown pattern: {}", features.debug_stats())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user