Files
hakorune/docs/development/current/main/phases/phase-188.1/README.md

12 KiB
Raw Blame History

Phase 188.1: cap_missing/NestedLoop 解除strict gate unblock

Date: 2025-12-27 Goal: cap_missing/NestedLoop を解除して、selfhost_minimal を integration で PASS させるFail-Fastを崩さない Status: Capability gate unblock 完了 / Pattern 6検出・loweringは Phase 188.2+ に deferred


⚠️ Implementation Reality (Phase 188.1 Scope)

What Phase 188.1 actually did

  • StepTree capability gate: StepCapability::NestedLoop を strict allowlist に追加して、cap_missing/NestedLoop を解除した
  • Integration導線: selfhost_minimal の SKIP を撤去しても integration selfhost が FAIL=0 になることを確認した

What Phase 188.1 did NOT do

  • **Nested loop の自動検出LoopFormベース**は未実装
    loop_pattern_detection::extract_features()max_loop_depth=1 / has_inner_loops=false の固定値TODOで、Pattern 6 の分岐は到達しない
  • Pattern 6 lowering は未実装
    src/mir/join_ir/lowering/loop_patterns/nested_minimal.rs はインフラstubで、現状 None を返す

Why LoopForm-based nesting detection is impossible (current architecture)

Nesting depth は **StepTreeAST側**にはあるが、**LoopFormMIR側**には存在しない。

  • StepTree: StepTreeFeatures.max_loop_depthAST → StepTree 変換時に計算)
  • LoopForm: LoopForm = LoopShape は CFG ブロック参照だけを持ち、親子/深さ情報が無い

従って、ネスト深さの検査や Pattern 6 の自動検出を LoopFormレイヤーだけで完結させることはできない。 次の実装は Phase 188.2 で「StepTree側を使うか / LoopRegion親子構造を実装するか」を docs-first で決める。

Pattern 6 Specification: NestedLoop Minimal

Note: このセクションは「目標仕様design」であり、Phase 188.1 では gate unblock のみ完了。実装は Phase 188.2+。

Supported Forms (ONLY)

Pattern: Outer Pattern 1 + Inner Pattern 1

// Outer loop: Pattern 1 (simple while, no break/continue)
loop(outer_cond) {
  // ... outer loop body before inner ...

  // Inner loop: Pattern 1 ONLY (simple while, no break/continue)
  loop(inner_cond) {
    // ... inner loop body ...
  }

  // ... outer loop body after inner ...
}

Requirements:

  • Outer loop: Pattern 1 (Simple While) - no break/continue
  • Inner loop: Pattern 1 (Simple While) - no break/continue
  • Nesting depth: EXACTLY 1 level (max_loop_depth == 2)
  • No control flow: No break/continue in either loop
  • Sequential execution: Inner loop completes before outer continues

Unsupported Forms (Explicit Error)

Rejected with明示エラー (no silent fallback):

  1. Deeper nesting (max_loop_depth > 2):

    [joinir/nested_loop/depth_exceeded] max_loop_depth=3 exceeds limit (max=2)
    Hint: Refactor to avoid 3+ level nesting, or split into separate functions
    
  2. Inner loop with break/continue:

    [joinir/nested_loop/inner_control_flow] Inner loop has break/continue (not supported)
    Hint: Only simple while loops (Pattern 1) supported as inner loops
    
  3. Outer loop with break/continue:

    [joinir/nested_loop/outer_control_flow] Outer loop has break/continue (not supported)
    Hint: Only simple while loops (Pattern 1) supported as outer loops
    
  4. Multiple inner loops (siblings):

    [joinir/nested_loop/multiple_inner] Multiple inner loops detected (not supported)
    Hint: Only one inner loop per outer loop supported
    

JoinIR Lowering Strategy

Example Input (Nyash)

static box Main {
  main() {
    local outer_i = 0
    loop(outer_i < 3) {
      local inner_j = 0
      loop(inner_j < 2) {
        print(inner_j)
        inner_j = inner_j + 1
      }
      outer_i = outer_i + 1
    }
    return 0
  }
}

Expected Output (JoinIR Pseudocode)

fn main():
  Call(outer_step, [0, k_main_exit])

fn outer_step(outer_i, k_outer_exit):
  // Exit condition check
  exit_cond = !(outer_i < 3)
  Jump(k_outer_exit, [], cond=exit_cond)  // Early exit if condition false

  // Initialize inner loop variables
  inner_j = 0

  // Inner loop step function (nested inside outer_step)
  fn inner_step(inner_j, k_inner_exit):
    exit_cond = !(inner_j < 2)
    Jump(k_inner_exit, [], cond=exit_cond)

    print(inner_j)
    inner_j_next = inner_j + 1
    Call(inner_step, [inner_j_next, k_inner_exit])  // Tail recursion

  // k_inner_exit continuation (resume outer loop body after inner completes)
  fn k_inner_exit():
    outer_i_next = outer_i + 1
    Call(outer_step, [outer_i_next, k_outer_exit])  // Outer tail recursion

  // Entry: call inner loop
  Call(inner_step, [inner_j, k_inner_exit])

fn k_main_exit():
  return 0

Key Points:

  • Nested functions: Inner step function is defined inside outer step function
  • Continuation wiring: k_inner_exit resumes outer loop body after inner completes
  • Carrier isolation: Outer carriers (outer_i) and inner carriers (inner_j) are separate
  • Same pattern as Pattern 1: Both loops use tail-recursive step function pattern

⚠️ Implementation Reality (Phase 188.1 Scope)

What Was Actually Implemented

Phase 188.1 delivered:

  1. StepTree capability gate: StepCapability::NestedLoop added to allowlist
  2. Pattern 6 enum: Pattern6NestedLoopMinimal classification added
  3. Lowering stub: nested_minimal.rs module created (infrastructure only)
  4. Test pass: selfhost_minimal conditional SKIP removed, 154/154 PASS maintained

Phase 188.1 did NOT implement:

  • Automatic nesting detection from LoopForm: LoopForm (= LoopShape) has NO nesting information
  • Pattern 6 lowering logic: lower_nested_loop_minimal_to_joinir() returns None (stub)
  • LoopRegion integration: LoopRegion parent/child structure exists but is NOT instantiated

Why Automatic Detection Is NOT Possible (Current Architecture)

LoopForm Limitation:

// src/mir/loop_form.rs
pub type LoopForm = crate::mir::control_form::LoopShape;

// LoopShape structure (src/mir/control_form.rs):
pub struct LoopShape {
    pub preheader: BasicBlockId,
    pub header: BasicBlockId,
    pub body: Vec<BasicBlockId>,
    pub latch: BasicBlockId,
    pub exit_blocks: Vec<BasicBlockId>,
    // ❌ NO parent field
    // ❌ NO children field
    // ❌ NO depth field
}

Nesting information exists ONLY in StepTree (AST level):

// src/mir/control_tree/step_tree/mod.rs (line 17-25)
pub struct StepTreeFeatures {
    pub max_loop_depth: u32,  // ← Detected during AST → StepTree conversion
    // ...
}
  • AST parsing time: Nesting depth calculated
  • MIR lowering time: LoopForm has NO access to this information

LoopRegion infrastructure exists but is NOT integrated:

// src/mir/control_form.rs (line 40-62) - Phase 32 definition
pub struct LoopRegion {
    pub parent: Option<LoopId>,   // ← Structure defined
    pub children: Vec<LoopId>,    // ← But NOT instantiated anywhere
}

Where Nesting Depth Checking MUST Happen

Possible locations:

  1. StepTree level (before LoopForm creation):

    • Use StepTreeFeatures.max_loop_depth during control flow analysis
    • Reject max_loop_depth > 2 at StepTree → LoopForm conversion time
  2. LoopRegion level (if integrated in Phase 188.2+):

    • Use LoopRegion.parent to compute actual nesting depth
    • Build LoopRegion tree and check depth constraints

Impossible location:

  • LoopForm level: No nesting information available (by design)

Phase 188.2 Design Decision Required

Choice A: StepTreeFeatures Integration

  • Pass StepTreeFeatures (AST-level) to JoinIR lowering
  • Use max_loop_depth from StepTree for Pattern 6 detection
  • Pro: Nesting info already exists
  • Con: AST-level info may not match MIR structure (optimizations)

Choice B: LoopRegion Integration

  • Instantiate LoopRegion with parent/child relationships
  • Compute nesting depth from MIR control flow graph
  • Pro: MIR-level truth (accurate after optimizations)
  • Con: Requires implementing LoopRegion builder (Phase 32 infrastructure not yet wired)

Decision timeline: Phase 188.2 planning session (docs-first approach)


Implementation Files

New Files Created

  1. src/mir/join_ir/lowering/loop_patterns/nested_minimal.rs
    • Phase 188.1: インフラstub。現状 lower_nested_loop_minimal_to_joinir()None を返す

Modified Files

  1. src/mir/loop_pattern_detection/mod.rs (~15 lines)

    • Add Pattern6NestedLoopMinimal enum variant
    • Add max_loop_depth, has_inner_loops to LoopFeatures
    • Update extract_features(), classify()
  2. src/mir/join_ir/lowering/loop_patterns/mod.rs (~2 lines)

    • Export nested_minimal module
  3. src/mir/join_ir/lowering/loop_pattern_router.rs (~10 lines)

    • Add Pattern 6 routing case
    • Add explicit error for max_loop_depth > 2
  4. src/mir/builder/control_flow/joinir/control_tree_capability_guard.rs (~1 line)

    • Add StepCapability::NestedLoop to allowlist
  5. tools/smokes/v2/profiles/integration/selfhost/selfhost_minimal.sh (~6 lines removed)

    • Remove conditional SKIP for cap_missing/NestedLoop

Integration Points

Detection Pipeline

  1. AST → StepTree (step_tree.rs lines 461-463):

    if features.max_loop_depth > 1 {
        facts.add_capability(StepCapability::NestedLoop);
    }
    
  2. StepTree → Contract (automatic capability contract check)

  3. Contract → Guard (control_tree_capability_guard.rs line 44):

    StepCapability::NestedLoop,  // Phase 188.1: Now in allowlist
    
  4. LoopForm → Pattern Detection (loop_pattern_detection::classify()):

    // Phase 188.1: Pattern 6 enum defined, but detection logic is STUB
    // Currently always returns max_loop_depth = 1 (default)
    // because LoopForm has NO nesting information.
    //
    // TODO (Phase 188.2): Integrate StepTreeFeatures or LoopRegion
    // to enable actual nesting detection.
    if features.max_loop_depth == 2
        && features.has_inner_loops
        && !features.has_break
        && !features.has_continue
    {
        return LoopPatternKind::Pattern6NestedLoopMinimal;  // Never reached (stub)
    }
    
  5. Pattern → Lowering (loop_pattern_router.rs):

    LoopPatternKind::Pattern6NestedLoopMinimal => {
        super::loop_patterns::lower_nested_loop_minimal_to_joinir(loop_form, lowerer)
    }
    

Success Criteria

Functional Requirements

  • selfhost_minimal.sh: Remove conditional SKIP, test PASS (or explicit error)
  • integration --filter "selfhost_": FAIL=0 maintained
  • quick: 154/154 PASS unchanged

Quality Requirements

  • Explicit errors for unsupported forms (no silent Ok(None))
  • Phase 286 Fail-Fast principle maintained (no silent fallback)
  • Minimal diff (~180 lines total)

Out of Scope (Future Work)

Deferred to Phase 188.2+:

  • Pattern 6 の実装ネスト検出のSSOT決定 + lowering 実装)
  • break/continue in nested loops (Pattern 2/4 inner/outer combinations)
  • Multiple inner loops (siblings)
  • 2+ level nesting (3+ loop depth)
  • Nested loops with PHI (Pattern 3 inner/outer combinations)
  • Shared carriers between outer/inner loops

Rationale: Phase 188.1 is minimal PoC to unblock selfhost_minimal. Complex patterns deferred to avoid scope creep.


References

  • Phase 188 Overview: docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/README.md
  • Pattern Classification: docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/pattern-classification.md
  • JoinIR Architecture: docs/development/current/main/joinir-architecture-overview.md
  • Selfhost Integration Limitations: docs/development/current/main/investigations/selfhost-integration-limitations.md

End of Phase 188.1 Documentation

Status: Infrastructure complete, detection logic deferred to Phase 188.2 Reality: Pattern 6 enum exists, but automatic detection is NOT implemented (LoopForm limitation) Total Estimated Effort: 4-5 hours (infrastructure only) Date Completed: 2025-12-27