feat(joinir): Phase 188.3 - Pattern6 (NestedLoopMinimal) 選択ロジック実装

## Phase 188.3 進捗: Phase 2 完了 (6/13 tasks)

### 実装完了 

**Phase 1: Fixture作成**
- apps/tests/phase1883_nested_minimal.hako 追加
  - Add/Compare のみ(乗算なし)
  - 期待 exit code: 9 (3×3 nested loops)
- 既存 lowering で fallback 動作確認

**Phase 2: 選択ロジック (SSOT)**
- LoopPatternContext に step_tree_max_loop_depth フィールド追加
- choose_pattern_kind() に Pattern6 選択ロジック実装:
  1. Cheap check (has_inner_loop)
  2. StepTree 構築 (max_loop_depth 取得)
  3. AST validation (is_pattern6_lowerable)
- pattern6_nested_minimal.rs モジュール作成 (stub)
- LOOP_PATTERNS に Pattern6 entry 追加
- **検証**: Pattern6 が正しく選択される 

### 設計原則 (確認済み)

1. **Fail-Fast**: Pattern6 選択後は Ok(None) で逃げない
2. **outer 変数 write-back 検出 → validation false** (Phase 188.4+)
3. **最小実装**: inner local だけ、Pattern1 モデル二重化
4. **cfg! 依存なし**: production で動作

### 検証結果

```
[choose_pattern_kind] has_inner_loop=true
[choose_pattern_kind] max_loop_depth=2
[choose_pattern_kind] is_pattern6_lowerable=true
 Pattern6 SELECTED!
```

Stub からの期待エラー:
```
[ERROR]  [Pattern6] Nested loop lowering not yet implemented
```

### 次: Phase 3 (Lowering 実装 - 推定4時間)

残りタスク:
- Phase 3-1: AST 抽出ヘルパー
- Phase 3-2: Validation ヘルパー
- Phase 3-3: Continuation 生成 (outer_step, inner_step, k_inner_exit)
- Phase 3-4: fixture が exit=9 を返すことを検証

### 変更ファイル

**新規**:
- apps/tests/phase1883_nested_minimal.hako
- src/mir/builder/control_flow/joinir/patterns/pattern6_nested_minimal.rs
- docs/development/current/main/phases/phase-188.{1,2,3}/README.md

**変更**:
- src/mir/builder/control_flow/joinir/routing.rs (Pattern6 選択)
- src/mir/builder/control_flow/joinir/patterns/router.rs (Context 拡張)
- src/mir/builder/control_flow/joinir/patterns/mod.rs (module 宣言)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-27 05:45:12 +09:00
parent 229553f7a4
commit a2c5fd90fe
32 changed files with 1780 additions and 42 deletions

View File

@ -127,8 +127,7 @@ pub(crate) fn extract_features(
break_count: if has_break { 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
update_summary: None,
..Default::default() // Phase 188.1: Use Default for nesting fields
}
}

View File

@ -79,6 +79,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 pattern4_carrier_analyzer;
pub(in crate::mir::builder) mod pattern4_with_continue;
pub(in crate::mir::builder) mod pattern6_nested_minimal; // Phase 188.3: 1-level nested loop (Pattern1 outer + Pattern1 inner)
pub(in crate::mir::builder) mod pattern6_scan_with_init; // Phase 254 P0: index_of/find/contains pattern
pub(in crate::mir::builder) mod pattern7_split_scan; // Phase 256 P0: split/tokenization with variable step
pub(in crate::mir::builder) mod pattern8_scan_bool_predicate; // Phase 259 P0: boolean predicate scan (is_integer/is_valid)

View File

@ -0,0 +1,48 @@
//! Phase 188.3: Pattern6 NestedLoopMinimal - 1-level nested loop lowering
//!
//! Handles loops of the form:
//! ```nyash
//! loop(outer_cond) {
//! loop(inner_cond) {
//! // inner body
//! }
//! // outer body (after inner loop)
//! }
//! ```
//!
//! Requirements (Pattern1 for both):
//! - Outer loop: no break, no continue (Pattern1)
//! - Inner loop: no break, no continue (Pattern1)
//! - Exactly 1 inner loop
//! - max_loop_depth == 2
//!
//! Strategy:
//! - Generate outer_step continuation (contains inner loop call)
//! - Generate inner_step continuation (tail recursion)
//! - Generate k_inner_exit (bridges to outer continuation)
//! - Wire continuations
use crate::mir::builder::control_flow::joinir::patterns::LoopPatternContext;
use crate::mir::builder::MirBuilder;
use crate::mir::loop_pattern_detection::LoopPatternKind;
use crate::mir::ValueId;
/// Detect if this context can be lowered as Pattern6 (NestedLoopMinimal)
///
/// Pattern selection happens in choose_pattern_kind() (SSOT).
/// This function just verifies ctx.pattern_kind matches.
pub(crate) fn can_lower(_builder: &MirBuilder, ctx: &LoopPatternContext) -> bool {
ctx.pattern_kind == LoopPatternKind::Pattern6NestedLoopMinimal
}
/// Lower Pattern6 (NestedLoopMinimal) to MIR
///
/// Phase 188.3: Full implementation with continuation generation
pub(crate) fn lower(
_builder: &mut MirBuilder,
_ctx: &LoopPatternContext,
) -> Result<Option<ValueId>, String> {
// Phase 188.3 stub - full implementation in Phase 3-3
// TODO: Implement continuation generation (outer_step, inner_step, k_inner_exit)
Err("[Pattern6] Nested loop lowering not yet implemented (Phase 188.3 stub)".to_string())
}

View File

@ -74,6 +74,11 @@ pub(crate) struct LoopPatternContext<'a> {
/// SSOT Principle: Avoid re-detecting ConditionalStep in lowering phase.
#[allow(dead_code)]
pub skeleton: Option<&'a LoopSkeleton>,
/// Phase 188.3: Cached StepTree max_loop_depth for Pattern6
/// None if not computed, Some(depth) if Pattern6 candidate
/// Avoids re-building StepTree in lowering phase
pub step_tree_max_loop_depth: Option<u32>,
}
impl<'a> LoopPatternContext<'a> {
@ -111,6 +116,7 @@ impl<'a> LoopPatternContext<'a> {
pattern_kind,
fn_body: None, // Phase 200-C: Default to None
skeleton: None, // Phase 92 P0-2: Default to None
step_tree_max_loop_depth: None, // Phase 188.3: Default to None
}
}
@ -386,6 +392,11 @@ pub(crate) struct LoopPatternEntry {
/// Note: func_name is now only used for debug logging, not pattern detection
/// Phase 286: Pattern5 removed (migrated to Plan-based routing)
pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
LoopPatternEntry {
name: "Pattern6_NestedLoopMinimal", // Phase 188.3: 1-level nested loop
detect: super::pattern6_nested_minimal::can_lower,
lower: super::pattern6_nested_minimal::lower,
},
LoopPatternEntry {
name: "Pattern4_WithContinue",
detect: super::pattern4_with_continue::can_lower,