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

@ -1,12 +1,36 @@
# Self Current Task — Now (main)
## Current Focus: Phase 29ypost self-host, docs-first
## Current Focus: Phase 188.3 (Nested Loop Lowering)
Phase 285 の "weak + hidden root + LLVM one-pass検出/設定含む)" は完全完了P4 Post-Completion 含む)。次は post self-host の Phase 29yMIR lifecycle vocab freeze相談を docs-first で進める。
**2025-12-27: Phase 188.2 完了**
- StepTreeの `max_loop_depth` を SSOT に採用Option A
- strict mode で depth > 2 を明示エラー化Fail-Fast
- quick 154/154 PASS、integration selfhost FAIL=0 維持
- 次: `docs/development/current/main/phases/phase-188.3/README.md`depth=2 を JoinIR lowering で通す / 変数はread-only capture→write-backは次フェーズ
**2025-12-27: Phase S0.1 完了**
- integration selfhost を「落ちない状態」に収束FAIL=0
- canary テスト opt-in 化SMOKES_ENABLE_SELFHOST=1、9本
- baseline テスト条件付き SKIP該当ログの時だけ、unknown は FAIL 維持)
- quick 154/154 PASS 維持、Fail-Fast 原則遵守
- SSOT: [selfhost-integration-limitations.md](investigations/selfhost-integration-limitations.md)
**2025-12-27: Phase S0 Selfhost Integration 安定化(実ログベース)完了**
- **実ログ採取完了**: 5本のスクリプト直叩き + 全体ログで事実確定(推定排除)
- **確認済みエラーパターン**(実ログベース):
- Pattern 1: Loop lowering failed / StepTree lowering returned NoneJoinIR loop pattern gap
- Pattern 2: cap_missing/NestedLoopJoinIR caps gap
- Pattern 3: strict mode panicNYASH_JOINIR_STRICT=1 削除で対応)
- Pattern 4: Argument list too longOS limitation
- **条件付き SKIP 実装**: selfhost_minimal.sh, phase150, mir_min_vm, canary 4本該当ログの時だけ、それ以外はFAIL
- **進捗**: 12 FAIL → 10 FAILselfhost_minimal, mir_min_vm が PASS に)
- **quick smoke**: 154/154 PASS 維持 ✅
- **SSOT**: [selfhost-integration-limitations.md](investigations/selfhost-integration-limitations.md)
- **未確認**: String+Integer 型エラー(実ログで未検出、追加しない)
**2025-12-27: Phase 29y.1pilot plumbing完了**
- docs SSOTABI/RC insertion/observabilityを Phase 29y に集約
- 後続実装へ迷わず切るための最小導線 を追加(意味論は変更しない)
- "後続実装へ迷わず切るための最小導線" を追加(意味論は変更しない)
- NyRT handle ABI shim`crates/nyash_kernel/src/ffi/lifecycle.rs`
- RC insertion pass 入口no-op skeleton
- leak report に root categorieshandlesのみを追加Phase 1 limitation 明記)

View File

@ -0,0 +1,285 @@
# Selfhost Integration Test Limitations
**Date**: 2025-12-27 (Updated with actual log findings)
**Context**: Phase S0 selfhost integration stabilization
**Investigator**: Claude Code
**Status**: Actual Log-Based Analysis (No Speculation)
---
## Executive Summary
Integration selfhost tests show 12 FAILs out of 33 tests. This document is based on **actual test execution logs** collected on 2025-12-27.
**Key Principle**: This analysis uses ONLY confirmed error patterns from real logs. No speculation or estimation.
**Log Collection**:
- Full integration selfhost run: `/tmp/integration_selfhost_full.log`
- Individual script logs: `/tmp/selfhost_minimal.log`, `/tmp/phase150.log`, etc.
**Resolution Strategy**: Conditional SKIP (該当ログが出た時だけ、それ以外はFAIL)
---
## 実ログ確認済みエラーパターン
### Pattern 1: JoinIR Loop Lowering Failure
**Error Tag**: `[joinir/freeze] Loop lowering failed`
**Full Error Message**:
```
[ERROR] ❌ MIR compilation error: [joinir/freeze] Loop lowering failed: JoinIR does not support this pattern, and LoopBuilder has been removed.
Function: BundleResolver.resolve/4
Hint: This loop pattern is not supported. All loops must use JoinIR lowering.
```
**Confirmed in**:
- `selfhost_minimal.sh` (BundleResolver.resolve/4)
- `selfhost_mir_min_vm.sh` (MirVmMin._str_to_int)
**Root Cause**: Phase 188 JoinIR loop patterns don't support all loop constructs. Legacy LoopBuilder was removed in Phase 187.
**Category**: JoinIR loop pattern gap
---
### Pattern 2: JoinIR Caps Gap (NestedLoop)
**Error Tag**: `cap_missing/NestedLoop`
**Full Error Message**:
```
[joinir/control_tree] missing cap: NestedLoop in BundleResolver.resolve/4
[ERROR] ❌ MIR compilation error: [joinir/control_tree/cap_missing/NestedLoop] NestedLoop detected in 'BundleResolver.resolve/4' (step_tree_sig=967e04269f051967) Hint: refactor to avoid nested loops (not supported yet) or run without HAKO_JOINIR_STRICT=1
```
**Confirmed in**:
- `selfhost_minimal.sh` (visible in full integration log)
**Root Cause**: JoinIR control_tree lacks NestedLoop capability
**Category**: JoinIR caps gap
**Note**: This error appears BEFORE Pattern 1 in selfhost_minimal.sh, suggesting the script encounters Pattern 2 first.
---
### Pattern 3: Strict-Only Canary (Pattern Not Matched)
**Error Tag**: `strict mode: pattern not matched`
**Full Error Message**:
```
thread 'main' panicked at src/mir/builder/if_form.rs:328:29:
[joinir/if] strict mode: pattern not matched for IfSelectTest.test/1 (if_form.rs)
```
**Confirmed in**:
- `selfhost_phase150_depth1_smoke.sh` (testing joinir_if_select_simple.hako)
- Runs with `NYASH_JOINIR_STRICT=1`
**Root Cause**: if_form.rs strict mode validation catches unmatched pattern
**Category**: strict-only canary
**Design Intent**: Strict mode is intentionally strict to catch edge cases. Not meant for baseline stability.
---
### Pattern 4: Selfhost Child Spawn Limitation
**Error Tag**: `Argument list too long (os error 7)`
**Full Error Message**:
```
[selfhost-child] spawn failed: Argument list too long (os error 7)
```
**Confirmed in**:
- `selfhost_minimal.sh`
**Root Cause**: OS kernel limitation (ARG_MAX) for subprocess argument list length
**Category**: OS limitation
**Note**: This error appears FIRST in selfhost_minimal.sh execution, before any JoinIR errors.
---
## FAIL スクリプト一覧(実ログベース・テーブル化)
| Script Path | Error Tag | Category | Action |
|-------------|-----------|----------|--------|
| `selfhost_minimal.sh` | `Argument list too long` + `Loop lowering failed` | Pattern 4 + Pattern 1 | 条件付き SKIP |
| `selfhost_phase150_depth1_smoke.sh` | `strict mode: pattern not matched` | Pattern 3 | 条件付き SKIP |
| `selfhost_mir_min_vm.sh` | `loop pattern is not supported` | Pattern 1 | 条件付き SKIP |
| `selfhost_s1_s2_from_builder_canary_vm.sh` | rc=1 (no error detail in log) | Unknown | 条件付き SKIP (known patterns only) |
| `selfhost_s1_s2_from_builder_compare_ret_canary_vm.sh` | rc=1 (no error detail) | Unknown | 条件付き SKIP (known patterns only) |
| `selfhost_s1_s2_from_builder_compare_cfg_canary_vm.sh` | rc=1 (no error detail) | Unknown | 条件付き SKIP (known patterns only) |
| `selfhost_v0_s1s2_repeat_canary_vm.sh` | rc=1 (no error detail) | Unknown | 条件付き SKIP (known patterns only) |
| `selfhost_v1_primary_rc42_canary_vm.sh` | rc=1 (no error detail) | Unknown | 条件付き SKIP (known patterns only) |
| `selfhost_v1_provider_primary_rc42_canary_vm.sh` | rc=1 (no error detail) | Unknown | 条件付き SKIP (known patterns only) |
| `selfhost_v0_core_exec_rc42_canary_vm.sh` | rc=1 (no error detail) | Unknown | 条件付き SKIP (known patterns only) |
**Total FAILs**: 12 (from full integration run on 2025-12-27)
**Total PASSes**: 21
**Total Tests**: 33
---
## 未確認パターン(実ログで確認されなかった)
### String+Integer Type Error (NOT confirmed)
**Previous Speculation** (from Task agent):
- "6-8 tests fail due to String + Integer auto-conversion not supported"
- Example: `print("" + integer_value)`
**Actual Log Finding**: ❌ **NOT confirmed in any collected logs**
**Conclusion**: Either:
1. This pattern doesn't occur in current selfhost tests, OR
2. Tests were fixed to use `.toString()`, OR
3. The speculation was incorrect
**Action**: Do NOT add SKIP for this pattern. Only add if confirmed in actual logs.
---
## Resolution Strategy (Phase S0 & S0.1)
### Phase S0.1 Update: Canary Tests Opt-In
**Canary Tests**: Opt-in via `SMOKES_ENABLE_SELFHOST=1` (Phase S0.1) - not required for baseline integration
**Affected Tests** (9 canary tests):
- `phase2047/*_canary_vm.sh` (5 tests)
- `phase2051/*_canary_vm.sh` (4 tests)
**Rationale**: These are advanced/experimental selfhost tests. Baseline integration stability doesn't require them to pass.
### Principle: 条件付き SKIPConditional SKIP Only)
**Approach**: SKIP only when specific error pattern appears in logs, otherwise FAIL
**Implementation Example** (Pattern 1):
```bash
# Phase S0: JoinIR loop lowering failure - conditional SKIP
# SSOT: docs/development/current/main/investigations/selfhost-integration-limitations.md
if [ "$exit_code" -ne 0 ]; then
if echo "$output" | grep -q "Loop lowering failed"; then
log_skip "selfhost_*: Pattern 1 (JoinIR loop pattern gap - Phase 188 limitation)"
exit 0
fi
# それ以外のエラーは FAIL のまま(回帰を隠さない)
log_error "selfhost_*: FAIL (unknown error, not Pattern 1)"
echo "$output"
exit 1
fi
```
### Critical Constraints
-**quick 154/154 PASS 維持** (一切触らない)
-**Phase 29y 凍結** (新しい lifecycle/RC 実装拡張はしない)
-**Fail-Fast** (silent fallback 禁止)
-**最小差分** (SKIP マーカー追加のみ)
### Prohibited Actions
- ❌ 無条件 SKIP (unconditional SKIP)
- ❌ 新規 env var 追加
- ❌ 直読みstd::env::var増殖
- ❌ quick を重くする変更
- ❌ silent fallback
---
## Root Cause Analysis
### Why Pattern 1 & 2 (JoinIR Gaps)?
**Phase 187**: Removed LoopBuilder (legacy loop implementation)
**Phase 188**: Implemented 3 basic JoinIR loop patterns (80% coverage goal)
**Result**: Some complex loop patterns not yet supported:
- Multiple continue statements in single loop
- Nested loops (NestedLoop capability)
- Complex control flow combinations
**Design Trade-off**: Phase 188 prioritized common patterns to ship quickly. Complex patterns deferred.
**Fix Scope**: Requires Phase 188 continuation (JoinIR pattern expansion) - NOT in scope for Phase S0
### Why Pattern 3 (Strict Mode)?
**Design Intent**: `NYASH_JOINIR_STRICT=1` is a canary mode to catch unmatched patterns early
**Purpose**: Development/debugging, not baseline stability
**Resolution**: Either remove NYASH_JOINIR_STRICT=1 from baseline tests, OR conditional SKIP for strict mode errors
### Why Pattern 4 (Argument List Too Long)?
**Root Cause**: Linux kernel ARG_MAX limitation (typically ~2MB on modern systems)
**Context**: selfhost_build.sh passes large amounts of data via command-line arguments
**Fix Scope**: Requires architectural change (use files/stdin instead of argv) - NOT in scope for Phase S0
---
## Future Work (Out of Scope for Phase S0)
### Phase 188 Continuation (JoinIR Pattern Expansion)
**Patterns Needed**:
- NestedLoop capability (Pattern 2)
- Complex control flow with multiple continue (Pattern 1)
- Infinite loops with early exits
**Effort**: ~2-5 days per pattern (based on Phase 188 experience)
**Priority**: Medium (selfhost compiler .hako files need these patterns)
### Selfhost Build Architecture
**Issue**: Pattern 4 (Argument list too long)
**Solution**: Replace argv-based data passing with file-based or stdin-based approach
**Effort**: ~1-2 days
**Priority**: Low (affects only selfhost_minimal.sh currently)
---
## References
- **Log Collection**: `/tmp/integration_selfhost_full.log`, `/tmp/selfhost_minimal.log`, etc.
- **Phase S0 Plan**: `/home/tomoaki/.claude/plans/functional-chasing-clover.md`
- **JoinIR Architecture**: `docs/development/current/main/joinir-architecture-overview.md`
- **Phase 188 Inventory**: `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/inventory.md`
- **VM Implementation**: `src/backend/mir_interpreter/`
---
## Conclusion
**Fact-Based Analysis**: All findings confirmed by actual test execution logs on 2025-12-27
**12 FAILs** categorized into 4 confirmed patterns:
1. **Pattern 1**: JoinIR loop lowering failure (2+ tests)
2. **Pattern 2**: JoinIR caps gap - NestedLoop (1 test)
3. **Pattern 3**: strict mode panic (1 test)
4. **Pattern 4**: Argument list too long (1 test, appears with Pattern 1)
**Canary Tests**: 7 tests fail with rc=1 but no error detail in logs
**String+Integer speculation**: ❌ NOT confirmed in actual logs
**Next Step**: Implement conditional SKIP for confirmed patterns only (Task 2)
**Quick Profile Safety**: 154/154 PASS maintained ✅

View File

@ -0,0 +1,360 @@
# 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_depth`AST → 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
```nyash
// 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)
```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)
```text
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**:
```rust
// 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):
```rust
// src/mir/control_tree/step_tree.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**:
```rust
// 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):
```rust
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):
```rust
StepCapability::NestedLoop, // Phase 188.1: Now in allowlist
```
4. **LoopForm → Pattern Detection** (`loop_pattern_detection::classify()`):
```rust
// 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`):
```rust
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

View File

@ -0,0 +1,133 @@
# Phase 188.2: StepTree nesting depth SSOT (Option A) — strict Fail-Fast
**Date**: 2025-12-27
**Status**: ✅ Option A implemented / ❌ Pattern 6 lowering deferred (Phase 188.3+)
**Goal**: `StepTreeFeatures.max_loop_depth` を SSOT として、strict mode で depth > 2 を明示エラーにする
---
## ✅ Decision: Option A Adopted (2025-12-27)
**Chosen Approach**: StepTreeFeatures Integration
**What Phase 188.2 Implements**:
- Use `StepTree.features.max_loop_depth` as SSOT for nesting depth
- Add explicit error for `max_loop_depth > 2` in strict mode (capability_guard.rs)
- Update NestedLoop capability hint to reflect current support
**Implementation Location**:
- `src/mir/builder/control_flow/joinir/control_tree_capability_guard.rs` (lines 32-76)
**Status**: Option A depth checking implemented, Option B deferred
---
## What Phase 188.2 delivered
- ✅ strict mode の depth 制約を SSOT 化(`max_loop_depth > 2` は明示エラー)
- ✅ NestedLoop capability hint を現実に合わせて更新1-levelは許可、2+ level は depth_exceeded
- ✅ unit tests 更新depth=2 PASS / depth=3 FAIL
- ✅ quick/integration は不変(回帰なし)
### Verification (reference)
- quick: `./tools/smokes/v2/run.sh --profile quick`
- integration selfhost: `./tools/smokes/v2/run.sh --profile integration --filter "selfhost_"`
---
## Background
Phase 188.1 delivered infrastructure (capability allowlist, enum, stub module), but **detection and lowering are NOT implemented** due to architectural limitations.
**See**: `docs/development/current/main/phases/phase-188.1/README.md` § Implementation Reality
---
## Design Decision Required (Choose A or B)
### Option A: StepTreeFeatures Integration
**Approach**:
- Pass `StepTreeFeatures` from StepTree to LoopForm creation
- Store `max_loop_depth` in LoopForm (add field) or pass via context
- Use AST-level nesting depth for Pattern 6 detection
**Pros**:
- Nesting info already exists in StepTree
- No new detection logic required
- Fast implementation
**Cons**:
- AST-level info may diverge from MIR structure (after optimizations)
- Adding fields to LoopForm breaks separation of concerns
**Estimated Effort**: 1-2 days
---
### Option B: LoopRegion Integration
**Approach**:
- Implement LoopRegion builder (instantiate parent/child structure)
- Build LoopRegion tree from MIR control flow graph
- Compute nesting depth from LoopRegion.parent traversal
- Replace LoopForm with LoopRegion in lowering pipeline
**Pros**:
- MIR-level truth (accurate after optimizations)
- Leverages Phase 32 infrastructure
- Clean separation (LoopRegion is designed for nesting)
**Cons**:
- Requires implementing LoopRegion builder (non-trivial)
- Larger architectural change
- May affect other loop analysis code
**Estimated Effort**: 1-2 weeks
---
## Planning Session Agenda
**Step 1: Docs-First Design Review**
- Review Option A vs B trade-offs
- Consider impact on selfhost_minimal requirements
- Decide on approach based on scope/timeline
**Step 2: Detailed Implementation Plan**
- Write step-by-step implementation guide
- Identify critical files
- Estimate effort per task
**Step 3: Implementation**
- Execute chosen approach
- Test with selfhost_minimal
- Verify 154/154 PASS maintained
---
## Out of Scope (Phase 188.2)
Still deferred to Phase 188.3+:
- Break/continue in nested loops (Pattern 2/4 combinations)
- Multiple inner loops (siblings)
- 2+ level nesting (depth > 2) の loweringPhase 188.2 は strict Fail-Fast のみ)
**Rationale**: Phase 188.2 focuses on 1-level nesting detection only (minimal scope).
---
## References
- **Phase 188.1 Reality**: `docs/development/current/main/phases/phase-188.1/README.md` § Implementation Reality
- **LoopRegion Definition**: `src/mir/control_form.rs` (lines 40-62)
- **StepTreeFeatures Definition**: `src/mir/control_tree/step_tree.rs` (lines 17-25)
- **LoopForm/LoopShape Definition**: `src/mir/loop_form.rs`, `src/mir/control_form.rs`
---
## End of Phase 188.2 Planning Stub
**Status**: Option A is complete; remaining work is Phase 188.3+
**Dependencies**: Phase 188.1 “Implementation Reality” remains SSOT

View File

@ -0,0 +1,104 @@
# Phase 188.3: Nested loop lowering (1-level) — make Pattern 6 real
**Date**: TBD
**Status**: Planning (docs-first)
**Prereq**: Phase 188.2 Option A is complete (StepTree depth SSOT + strict Fail-Fast)
---
## Goal
`max_loop_depth == 2`1-level nested loop**JoinIR lowering で実際に通す**
- 既知の事実: `LoopForm (=LoopShape)` にはネスト情報が無いので、**LoopFormベースの Pattern6 検出/ルーティングでは実装できない**
- 実装は **StepTreeAST側**を SSOT として扱うPhase 188.2 Option A を継続)
---
## Scope (minimal)
対応するのは “NestedLoop Minimal” の 1形だけに限定する。
- depth: `max_loop_depth == 2` のみ
- inner loop: Pattern1相当break/continue 無し)
- outer loop: Pattern1相当break/continue 無し)を優先
- それ以外:
- strict mode: 明示エラーPhase 188.2 の depth check とは別タグで良い)
- non-strict mode: 既存の fallback 経路に任せる(ただし silent fallback を増やさない)
---
## SSOT (what to rely on)
- nesting depth SSOT: `StepTreeFeatures.max_loop_depth`
- depth > 2: strict mode で `control_tree/nested_loop/depth_exceeded`Phase 188.2
---
## Scope & Variable Model (SSOT)
Nyash の変数スコープ方針に合わせて、nested loop lowering でも以下を SSOT として固定する。
### Visibility (read)
- inner loop から outer の binding は参照できるlexical scope: “1つ上は見える”
- ただし JoinIR lowering では「見える」を **明示的な引数/継続で表現**する(暗黙キャプチャを増やさない)
### Mutation (write-back)
Phase 188.3 では段階的に進める:
- **P188.3 (minimal)**: outer 変数の **read-only capture** を許すinner から outer を読む)
- **P188.4+ (generalize)**: outer 変数の **write-back** を対応するinner で outer に代入した値を `k_inner_exit(...)` で戻す)
この分離により、PHI/exit binding の複雑さを Phase 188.3 に持ち込まずに済む。
---
## Lowering sketch (how it should look)
Nested loop は JoinIR の「tail recursion + continuation」を再帰的に合成して表現する。
- outer: `outer_step(state..., k_outer_exit)`
- inner: `inner_step(state..., k_inner_exit)`
- inner が終わったら `k_inner_exit(...)` で outer の“残り”へ戻る
この `k_inner_exit` がスコープ境界として働くので、将来の write-back もここに集約できる。
---
## Deliverables
1. **Fixture + integration smokeexit code SSOT**
- 1-level nested loop を最小で再現する `.hako` を追加
- integration で実行し、exit code で判定stdout比較はしない
2. **StepTree-based lowering implementation**
- StepTree を辿って、inner loop を outer loop の中で正しく lowering できるようにする
- 入口は “StepTree→JoinIR” のどこかLoopFormベースの router は使わない)
3. **Docs update**
- Phase 188.1 の “Pattern6 specification” が design であることは維持
- Phase 188.3 で “実装済み/未実装の境界” を明確に書く
---
## Acceptance Criteria
- `./tools/smokes/v2/run.sh --profile quick` が常にグリーン維持
- integration selfhost が FAIL=0 を維持
- 追加した nested loop fixture が PASSJoinIR lowering が使われたことをログ/タグで確認可能)
---
## Next (schedule)
- **Phase 188.3**: depth=2 の最小形を “確実に通す” + PoC fixture を smoke 固定
- **Phase 188.4+**: write-backouter carrier reconnectionと “再帰 lowering の一般化depthを増やしても壊れない” を docs-first で設計してから実装
---
## Out of Scope
- nested loop + break/continue の一般対応
- LoopRegion を使った MIR-level nesting SSOTOption B