Files
hakorune/docs/development/current/main/design/loop-canonicalizer.md

420 lines
16 KiB
Markdown
Raw Normal View History

# Loop Canonicalizer設計 SSOT
Status: Phase 141 完了(ドキュメント充実)
Scope: ループ形の組み合わせ爆発を抑えるための "前処理" の設計fixture/shape guard/fail-fast と整合)
Related:
- SSOT (契約/不変条件): `docs/development/current/main/joinir-architecture-overview.md`
- SSOT (地図/入口): `docs/development/current/main/design/joinir-design-map.md`
- SSOT (パターン空間): `docs/development/current/main/loop_pattern_space.md`
## アーキテクチャ図
### データフロー
```mermaid
graph LR
A[AST Loop] --> B[Canonicalizer]
B --> C{LoopSkeleton}
B --> D{RoutingDecision}
C --> E[Capability Guard]
D --> E
E --> F{Pass?}
F -->|Yes| G[Pattern Router]
F -->|No| H[Fail-Fast Error]
G --> I[JoinIR Lowerer]
```
### モジュール構成
```
loop_canonicalizer/
├── skeleton_types.rs [Data Structures]
│ ├── LoopSkeleton
│ ├── SkeletonStep
│ ├── UpdateKind
│ └── CarrierSlot
├── capability_guard.rs [Validation]
│ ├── RoutingDecision
│ ├── CapabilityTag (enum)
│ └── Decision constructors
├── pattern_recognizer.rs [Pattern Detection]
│ └── detect patterns (ast_feature_extractor 呼び出し)
└── canonicalizer.rs [Main Logic]
└── canonicalize_loop_expr()
LoopSkeleton + RoutingDecision
Pattern Router (patterns/router.rs)
Pattern Lowerer (pattern1-5_*.rs)
```
### 処理フローPhase 140 完了後)
```mermaid
sequenceDiagram
participant AST as AST Loop
participant Canon as Canonicalizer
participant Guard as Capability Guard
participant Router as Pattern Router
participant Lower as JoinIR Lowerer
AST->>Canon: canonicalize_loop_expr()
Canon->>Canon: extract pattern (ast_feature_extractor)
Canon->>Canon: build LoopSkeleton
Canon->>Guard: validate capabilities
alt All capabilities satisfied
Guard->>Router: RoutingDecision(Pattern2)
Router->>Lower: lower to JoinIR
Lower-->>AST: MIR blocks
else Missing capabilities
Guard-->>AST: Fail-Fast error
end
```
## 目的
- 実アプリ由来のループ形を、fixture + shape guard + Fail-Fast の段階投入で飲み込む方針を維持したまま、
“パターン数を増やさない” 形でスケールさせる。
- ループ lowerer が「検出 + 正規化 + merge 契約」を同時に背負って肥大化するのを防ぎ、責務を前処理に寄せる。
## 推奨配置(結論)
**おすすめ**: `AST → LoopSkeleton → JoinIR(Structured)` の前処理として Canonicalizer を置く。
- 「組み合わせ爆発」が Pattern 検出/shape guard の手前で起きるため、Normalized 変換だけでは吸収しきれない。
- LoopSkeleton を SSOT にすると、lowerer は “骨格を吐く” だけの薄い箱になり、Fail-Fast の理由が明確になる。
代替案(参考):
- `Structured JoinIR → Normalized JoinIR` を実質 Canonicalizer とみなす(既存延長)。
ただし「検出/整理の肥大」は Structured 生成側に残りやすい。
## LoopSkeletonSSOT になる出力)
Canonicalizer の出力は “ループの骨格” に限る。例示フィールド:
- `steps: Vec<Step>`
- `HeaderCond`(あれば)
- `BodyInit`body-local 初期化を分離するなら)
- `BreakCheck` / `ContinueCheck`(あれば)
- `Updates`carrier 更新規則)
- `Tail`(継続呼び出し/次ステップ)
- `carriers: Vec<CarrierSlot>`loop var を含む。役割/更新規則/境界通過の契約)
- `exits: ExitContract`break/continue/return の有無と payload
- `captured: Vec<CapturedSlot>`(外側変数の取り込み)
- `derived: Vec<DerivedSlot>`digit_pos 等の派生値)
## Capability Guardshape guard の上位化)
Skeleton を生成できても、lower/merge 契約が成立するとは限らない。
そこで `SkeletonGuard` を “Capability の集合” として設計する。
例:
- `RequiresConstStepIncrement`i=i+const のみ)
- `BreakOnlyOnce` / `ContinueOnlyInTail`
- `NoSideEffectInHeader`header に副作用がない)
- `ExitBindingsComplete`(境界へ渡す値が過不足ない)
未達の場合は Fail-Fast理由を `RoutingDecision` に載せる)。
## RoutingDecision理由の SSOT
Canonicalizer は "できない理由" を機械的に返す。
- `RoutingDecision { chosen, missing_caps, notes, error_tags }`
- `missing_caps` は定型の語彙で出す(ログ/デバッグ/統計で集約可能にする)
## Capability Tags 対応表
### 各 Tag の詳細
| Tag | 必要な条件 | 対応Pattern | 検出方法 |
|-----|----------|------------|---------|
| `ConstStep` | キャリア更新が定数ステップ(`i = i + const` | P1, P2, P3 | UpdateKind 分析ConstStep variant |
| `SingleBreak` | break 文が単一箇所のみ | P2 | AST 走査でカウント(`count_break_checks() == 1` |
| `SingleContinue` | continue 文が単一箇所のみ | P1, P3 | AST 走査でカウント(`count_continue_checks() == 1` |
| `PureHeader` | ループ条件に副作用がない | P1, P2, P3, P4 | 副作用解析(将来実装) |
| `OuterLocalCond` | 条件変数が外側スコープで定義済み | P3 | Scope 分析BindingContext 参照) |
| `ExitBindings` | 境界へ渡す値が過不足ない | P2, P3 | Carrier 収支計算ExitContract 分析) |
| `CarrierPromotion` | LoopBodyLocal を昇格可能 | P3, P4 | Binding 解析promoted carriers 検出) |
| `BreakValueType` | break 値の型が一貫 | P2 | 型推論TypeContext 参照) |
### 各 Pattern の必須 CapabilityPhase 140 時点)
#### Pattern1 (Minimal)
-`ConstStep` - 定数ステップ増分
-`PureHeader` - 副作用なし条件
-`SingleContinue` - continue 単一箇所
#### Pattern2 (Break)
-`ConstStep` - 定数ステップ増分
-`PureHeader` - 副作用なし条件
-`SingleBreak` - break 単一箇所
-`ExitBindings` - 出口値の完全性
**例**: `skip_whitespace``has_break=true` なので Pattern2 へルーティングPhase 137-5
#### Pattern3 (IfPhi)
-`ConstStep` - 定数ステップ増分
-`PureHeader` - 副作用なし条件
-`OuterLocalCond` - 外側スコープ条件変数
-`CarrierPromotion` - LoopBodyLocal 昇格
**例**: Trim パターンPhase 133
#### Pattern4 (Composite)
-`PureHeader` - 副作用なし条件
-`CarrierPromotion` - LoopBodyLocal 昇格
-`ExitBindings` - 出口値の完全性
#### Pattern5 (Future)
- 🚧 TBD - 将来定義
### Capability 追加時のチェックリスト
新しい Capability を追加する際は以下を確認:
1. **enum 定義**: `capability_guard.rs``CapabilityTag` に variant 追加
2. **文字列変換**: `to_tag()` メソッドに対応を追加(`CAP_MISSING_*` 形式)
3. **説明文**: `description()` メソッドに説明を追加
4. **検出ロジック**: `canonicalizer.rs` に検出ロジックを実装
5. **対応表更新**: このドキュメントの対応表を更新
6. **Pattern 更新**: 必要に応じて各 Pattern の必須 Capability リストを更新
7. **テスト追加**: 新 Capability の検出テストを追加
## Corpus / Signature拡張のための仕組み
将来の規模増加に備え、ループ形の差分検知を Skeleton ベースで行えるようにする。
- `LoopSkeletonSignature = hash(steps + exit_contract + carrier_roles + required_caps)`
- 既知集合との差分が出たら “fixture 化候補” として扱う(設計上の導線)。
## 実装の境界(非目標)
- 新しい言語仕様/ルール実装はしない(既存の意味論を保つ)。
- 非 JoinIR への退避prohibited fallbackは導入しない。
- 既定挙動は変えない(必要なら dev-only で段階投入する)。
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
## LoopSkeleton の最小フィールドSSOT 境界)
Canonicalizer の出力は以下のフィールドに限定する(これ以上細かくしない):
```rust
/// ループの骨格Canonicalizer の唯一の出力)
pub struct LoopSkeleton {
/// ステップの列HeaderCond, BodyInit, BreakCheck, Updates, Tail
pub steps: Vec<SkeletonStep>,
/// キャリア(ループ変数・更新規則・境界通過の契約)
pub carriers: Vec<CarrierSlot>,
/// 出口契約break/continue/return の有無と payload
pub exits: ExitContract,
/// 外部キャプチャ(省略可: 外側変数の取り込み)
pub captured: Option<Vec<CapturedSlot>>,
}
/// ステップの種類(最小限)
pub enum SkeletonStep {
/// ループ継続条件loop(cond) の cond
HeaderCond { expr: AstExpr },
/// 早期終了チェックif cond { break }
BreakCheck { cond: AstExpr, has_value: bool },
/// スキップチェックif cond { continue }
ContinueCheck { cond: AstExpr },
/// キャリア更新i = i + 1 など)
Update { carrier_name: String, update_kind: UpdateKind },
/// 本体(その他の命令)
Body { stmts: Vec<AstStmt> },
}
/// キャリアの更新種別
pub enum UpdateKind {
/// 定数ステップi = i + const
ConstStep { delta: i64 },
/// 条件付き更新if cond { x = a } else { x = b }
Conditional { then_value: AstExpr, else_value: AstExpr },
/// 任意更新(上記以外)
Arbitrary,
}
/// 出口契約
pub struct ExitContract {
pub has_break: bool,
pub has_continue: bool,
pub has_return: bool,
pub break_has_value: bool,
}
/// キャリアスロット
pub struct CarrierSlot {
pub name: String,
pub role: CarrierRole,
pub update_kind: UpdateKind,
}
/// キャリアの役割
pub enum CarrierRole {
/// ループカウンタi < n i
Counter,
/// アキュムレータsum += x の sum
Accumulator,
/// 条件変数while(is_valid) の is_valid
ConditionVar,
/// 派生値digit_pos 等)
Derived,
}
```
### SSOT 境界の原則
- **入力**: ASTLoopExpr
- **出力**: LoopSkeleton のみJoinIR は生成しない)
- **禁止**: Skeleton に JoinIR 固有の情報を含めないBlockId, ValueId 等)
---
## 実装の入口(現状)
feat(mir): Loop Canonicalizer Phase 3 - skip_whitespace pattern recognition ## Summary skip_whitespace パターンを Skeleton→Decision で認識可能に。 dev-only 観測で chosen=Pattern3IfPhi / missing_caps=[] を固定。 ## Changes - src/mir/loop_canonicalizer/mod.rs: - try_extract_skip_whitespace_pattern() 追加 - loop(cond) { ... if check { p = p + 1 } else { break } } パターン認識 - carrier name, delta, body statements を抽出 - canonicalize_loop_expr() 拡張(skip_whitespace 対応) - Pattern3IfPhi 成功時は RoutingDecision::success 返却 - Skeleton に HeaderCond, Body, Update ステップ追加 - CarrierSlot に Counter role 設定 - ExitContract に has_break=true 設定 - Phase 3 unit tests 追加 - test_skip_whitespace_pattern_recognition: 基本パターン - test_skip_whitespace_with_body_statements: body 付きパターン - test_skip_whitespace_fails_without_else: else なし失敗 - test_skip_whitespace_fails_with_wrong_delta: 減算パターン失敗 - Phase 2 obsolete tests 削除 - src/mir/builder/control_flow/joinir/routing.rs: - Debug 出力拡張(chosen pattern 表示) ## Tests - cargo test --release --lib loop_canonicalizer::tests: PASS(11 tests) - cargo test --release --lib: PASS(1044 tests, 退行なし) - HAKO_JOINIR_DEBUG=1 test_pattern3_skip_whitespace.hako: - chosen=Pattern3IfPhi ✅ - missing_caps=[] ✅ ## Validation - ✅ dev-only 観測(HAKO_JOINIR_DEBUG=1)のときだけログ出力 - ✅ フラグ OFF 時は完全不変 - ✅ skip_whitespace パターンで SUCCESS 固定 - ✅ unit tests で全パターン固定 Phase 137-3 complete
2025-12-16 05:38:18 +09:00
実装Phase 12はここ
- `src/mir/loop_canonicalizer/mod.rs`
注意:
feat(mir): Loop Canonicalizer Phase 3 - skip_whitespace pattern recognition ## Summary skip_whitespace パターンを Skeleton→Decision で認識可能に。 dev-only 観測で chosen=Pattern3IfPhi / missing_caps=[] を固定。 ## Changes - src/mir/loop_canonicalizer/mod.rs: - try_extract_skip_whitespace_pattern() 追加 - loop(cond) { ... if check { p = p + 1 } else { break } } パターン認識 - carrier name, delta, body statements を抽出 - canonicalize_loop_expr() 拡張(skip_whitespace 対応) - Pattern3IfPhi 成功時は RoutingDecision::success 返却 - Skeleton に HeaderCond, Body, Update ステップ追加 - CarrierSlot に Counter role 設定 - ExitContract に has_break=true 設定 - Phase 3 unit tests 追加 - test_skip_whitespace_pattern_recognition: 基本パターン - test_skip_whitespace_with_body_statements: body 付きパターン - test_skip_whitespace_fails_without_else: else なし失敗 - test_skip_whitespace_fails_with_wrong_delta: 減算パターン失敗 - Phase 2 obsolete tests 削除 - src/mir/builder/control_flow/joinir/routing.rs: - Debug 出力拡張(chosen pattern 表示) ## Tests - cargo test --release --lib loop_canonicalizer::tests: PASS(11 tests) - cargo test --release --lib: PASS(1044 tests, 退行なし) - HAKO_JOINIR_DEBUG=1 test_pattern3_skip_whitespace.hako: - chosen=Pattern3IfPhi ✅ - missing_caps=[] ✅ ## Validation - ✅ dev-only 観測(HAKO_JOINIR_DEBUG=1)のときだけログ出力 - ✅ フラグ OFF 時は完全不変 - ✅ skip_whitespace パターンで SUCCESS 固定 - ✅ unit tests で全パターン固定 Phase 137-3 complete
2025-12-16 05:38:18 +09:00
- Phase 2 で `canonicalize_loop_expr(...) -> Result<(LoopSkeleton, RoutingDecision), String>` を導入し、JoinIR ループ入口で dev-only 観測できるようにした(既定挙動は不変)。
- 観測ポイントJoinIR ループ入口): `src/mir/builder/control_flow/joinir/routing.rs``joinir_dev_enabled()` 配下)
feat(mir): Phase 137-5 - Decision Policy SSOT化完了 ## 目的 Canonicalizer の RoutingDecision.chosen を「lowerer 選択の最終結果」にする (構造クラス名ではなく ExitContract ベースの決定) ## 実装内容 ### 1. Canonicalizer の決定ロジック修正 - `src/mir/loop_canonicalizer/mod.rs` - `skip_whitespace` パターン認識で ExitContract (has_break=true) を考慮 - Pattern3IfPhi → Pattern2Break に修正(構造は似ているが break あり) - 単体テスト更新(Pattern2Break 期待に変更) ### 2. Parity 検証テスト修正 - `src/mir/builder/control_flow/joinir/routing.rs` - `test_parity_check_mismatch_detected` → `test_parity_check_skip_whitespace_match` - Canonicalizer と Router の一致を検証(ミスマッチ検出からマッチ検証へ) - Phase 137-5 の SSOT 原則を反映 ### 3. ドキュメント更新 - `docs/development/current/main/design/loop-canonicalizer.md` - Phase 137-5: Decision Policy SSOT セクション追加 - ExitContract 優先の原則を明記 - skip_whitespace の例を追加 - `docs/development/current/main/phases/phase-137/README.md` - Phase 4 完了マーク追加 - Phase 5 完了セクション追加(実装・検証・効果) ## 検証結果 - ✅ 単体テスト: `cargo test --release --lib loop_canonicalizer::tests` (11/11 passed) - ✅ Parity テスト: `cargo test --release --lib 'routing::tests::test_parity'` (2/2 passed) - ✅ Strict モード: `HAKO_JOINIR_STRICT=1` で skip_whitespace parity OK ## 効果 - Router と Canonicalizer の pattern 選択が一致 - ExitContract が pattern 決定の SSOT として明確化 - 構造的特徴(if-else 等)は notes に記録(将来拡張に備える) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 06:17:03 +09:00
- Phase 3 で `skip_whitespace` の最小形を `Pattern3IfPhi` として安定に識別できるようにしたdev-only 観測)。
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
## Capability の語彙Fail-Fast reason タグ)
Skeleton を生成できても lower/merge できるとは限らない。以下の Capability で判定する:
| Capability | 説明 | 未達時の理由タグ |
|--------------------------|------------------------------------------|-------------------------------------|
| `ConstStepIncrement` | キャリア更新が定数ステップi=i+const | `CAP_MISSING_CONST_STEP` |
| `SingleBreakPoint` | break が単一箇所のみ | `CAP_MISSING_SINGLE_BREAK` |
| `SingleContinuePoint` | continue が単一箇所のみ | `CAP_MISSING_SINGLE_CONTINUE` |
| `NoSideEffectInHeader` | ループ条件に副作用がない | `CAP_MISSING_PURE_HEADER` |
| `OuterLocalCondition` | 条件変数が外側スコープで定義済み | `CAP_MISSING_OUTER_LOCAL_COND` |
| `ExitBindingsComplete` | 境界へ渡す値が過不足ない | `CAP_MISSING_EXIT_BINDINGS` |
| `CarrierPromotion` | LoopBodyLocal を昇格可能 | `CAP_MISSING_CARRIER_PROMOTION` |
| `BreakValueConsistent` | break 値の型が一貫 | `CAP_MISSING_BREAK_VALUE_TYPE` |
### 語彙の安定性
- reason タグは `CAP_MISSING_*` プレフィックスで統一
- 新規追加時は `loop-canonicalizer.md` に先に追記してからコード実装
- ログ / 統計 / error_tags で集約可能
---
## RoutingDecision の出力先
Canonicalizer の判定結果は `RoutingDecision` に集約し、以下に流す:
```rust
pub struct RoutingDecision {
/// 選択された PatternNone = Fail-Fast
feat(mir): Phase 137-5 - Decision Policy SSOT化完了 ## 目的 Canonicalizer の RoutingDecision.chosen を「lowerer 選択の最終結果」にする (構造クラス名ではなく ExitContract ベースの決定) ## 実装内容 ### 1. Canonicalizer の決定ロジック修正 - `src/mir/loop_canonicalizer/mod.rs` - `skip_whitespace` パターン認識で ExitContract (has_break=true) を考慮 - Pattern3IfPhi → Pattern2Break に修正(構造は似ているが break あり) - 単体テスト更新(Pattern2Break 期待に変更) ### 2. Parity 検証テスト修正 - `src/mir/builder/control_flow/joinir/routing.rs` - `test_parity_check_mismatch_detected` → `test_parity_check_skip_whitespace_match` - Canonicalizer と Router の一致を検証(ミスマッチ検出からマッチ検証へ) - Phase 137-5 の SSOT 原則を反映 ### 3. ドキュメント更新 - `docs/development/current/main/design/loop-canonicalizer.md` - Phase 137-5: Decision Policy SSOT セクション追加 - ExitContract 優先の原則を明記 - skip_whitespace の例を追加 - `docs/development/current/main/phases/phase-137/README.md` - Phase 4 完了マーク追加 - Phase 5 完了セクション追加(実装・検証・効果) ## 検証結果 - ✅ 単体テスト: `cargo test --release --lib loop_canonicalizer::tests` (11/11 passed) - ✅ Parity テスト: `cargo test --release --lib 'routing::tests::test_parity'` (2/2 passed) - ✅ Strict モード: `HAKO_JOINIR_STRICT=1` で skip_whitespace parity OK ## 効果 - Router と Canonicalizer の pattern 選択が一致 - ExitContract が pattern 決定の SSOT として明確化 - 構造的特徴(if-else 等)は notes に記録(将来拡張に備える) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 06:17:03 +09:00
/// Phase 137-5: ExitContract に基づく最終 lowerer 選択を反映
feat(mir): Loop Canonicalizer Phase 3 - skip_whitespace pattern recognition ## Summary skip_whitespace パターンを Skeleton→Decision で認識可能に。 dev-only 観測で chosen=Pattern3IfPhi / missing_caps=[] を固定。 ## Changes - src/mir/loop_canonicalizer/mod.rs: - try_extract_skip_whitespace_pattern() 追加 - loop(cond) { ... if check { p = p + 1 } else { break } } パターン認識 - carrier name, delta, body statements を抽出 - canonicalize_loop_expr() 拡張(skip_whitespace 対応) - Pattern3IfPhi 成功時は RoutingDecision::success 返却 - Skeleton に HeaderCond, Body, Update ステップ追加 - CarrierSlot に Counter role 設定 - ExitContract に has_break=true 設定 - Phase 3 unit tests 追加 - test_skip_whitespace_pattern_recognition: 基本パターン - test_skip_whitespace_with_body_statements: body 付きパターン - test_skip_whitespace_fails_without_else: else なし失敗 - test_skip_whitespace_fails_with_wrong_delta: 減算パターン失敗 - Phase 2 obsolete tests 削除 - src/mir/builder/control_flow/joinir/routing.rs: - Debug 出力拡張(chosen pattern 表示) ## Tests - cargo test --release --lib loop_canonicalizer::tests: PASS(11 tests) - cargo test --release --lib: PASS(1044 tests, 退行なし) - HAKO_JOINIR_DEBUG=1 test_pattern3_skip_whitespace.hako: - chosen=Pattern3IfPhi ✅ - missing_caps=[] ✅ ## Validation - ✅ dev-only 観測(HAKO_JOINIR_DEBUG=1)のときだけログ出力 - ✅ フラグ OFF 時は完全不変 - ✅ skip_whitespace パターンで SUCCESS 固定 - ✅ unit tests で全パターン固定 Phase 137-3 complete
2025-12-16 05:38:18 +09:00
pub chosen: Option<LoopPatternKind>,
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
/// 不足している Capability のリスト
pub missing_caps: Vec<&'static str>,
/// 選択理由(デバッグ用)
pub notes: Vec<String>,
/// error_tags への追記contract_checks 用)
feat(mir): Loop Canonicalizer Phase 3 - skip_whitespace pattern recognition ## Summary skip_whitespace パターンを Skeleton→Decision で認識可能に。 dev-only 観測で chosen=Pattern3IfPhi / missing_caps=[] を固定。 ## Changes - src/mir/loop_canonicalizer/mod.rs: - try_extract_skip_whitespace_pattern() 追加 - loop(cond) { ... if check { p = p + 1 } else { break } } パターン認識 - carrier name, delta, body statements を抽出 - canonicalize_loop_expr() 拡張(skip_whitespace 対応) - Pattern3IfPhi 成功時は RoutingDecision::success 返却 - Skeleton に HeaderCond, Body, Update ステップ追加 - CarrierSlot に Counter role 設定 - ExitContract に has_break=true 設定 - Phase 3 unit tests 追加 - test_skip_whitespace_pattern_recognition: 基本パターン - test_skip_whitespace_with_body_statements: body 付きパターン - test_skip_whitespace_fails_without_else: else なし失敗 - test_skip_whitespace_fails_with_wrong_delta: 減算パターン失敗 - Phase 2 obsolete tests 削除 - src/mir/builder/control_flow/joinir/routing.rs: - Debug 出力拡張(chosen pattern 表示) ## Tests - cargo test --release --lib loop_canonicalizer::tests: PASS(11 tests) - cargo test --release --lib: PASS(1044 tests, 退行なし) - HAKO_JOINIR_DEBUG=1 test_pattern3_skip_whitespace.hako: - chosen=Pattern3IfPhi ✅ - missing_caps=[] ✅ ## Validation - ✅ dev-only 観測(HAKO_JOINIR_DEBUG=1)のときだけログ出力 - ✅ フラグ OFF 時は完全不変 - ✅ skip_whitespace パターンで SUCCESS 固定 - ✅ unit tests で全パターン固定 Phase 137-3 complete
2025-12-16 05:38:18 +09:00
pub error_tags: Vec<String>,
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
}
```
feat(mir): Phase 137-5 - Decision Policy SSOT化完了 ## 目的 Canonicalizer の RoutingDecision.chosen を「lowerer 選択の最終結果」にする (構造クラス名ではなく ExitContract ベースの決定) ## 実装内容 ### 1. Canonicalizer の決定ロジック修正 - `src/mir/loop_canonicalizer/mod.rs` - `skip_whitespace` パターン認識で ExitContract (has_break=true) を考慮 - Pattern3IfPhi → Pattern2Break に修正(構造は似ているが break あり) - 単体テスト更新(Pattern2Break 期待に変更) ### 2. Parity 検証テスト修正 - `src/mir/builder/control_flow/joinir/routing.rs` - `test_parity_check_mismatch_detected` → `test_parity_check_skip_whitespace_match` - Canonicalizer と Router の一致を検証(ミスマッチ検出からマッチ検証へ) - Phase 137-5 の SSOT 原則を反映 ### 3. ドキュメント更新 - `docs/development/current/main/design/loop-canonicalizer.md` - Phase 137-5: Decision Policy SSOT セクション追加 - ExitContract 優先の原則を明記 - skip_whitespace の例を追加 - `docs/development/current/main/phases/phase-137/README.md` - Phase 4 完了マーク追加 - Phase 5 完了セクション追加(実装・検証・効果) ## 検証結果 - ✅ 単体テスト: `cargo test --release --lib loop_canonicalizer::tests` (11/11 passed) - ✅ Parity テスト: `cargo test --release --lib 'routing::tests::test_parity'` (2/2 passed) - ✅ Strict モード: `HAKO_JOINIR_STRICT=1` で skip_whitespace parity OK ## 効果 - Router と Canonicalizer の pattern 選択が一致 - ExitContract が pattern 決定の SSOT として明確化 - 構造的特徴(if-else 等)は notes に記録(将来拡張に備える) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 06:17:03 +09:00
### Phase 137-5: Decision Policy SSOT
**原則**: `RoutingDecision.chosen` は「lowerer 選択の最終結果」を返す(構造クラス名ではなく)。
- **ExitContract が優先**: `has_break=true` なら `Pattern2Break``has_continue=true` なら `Pattern4Continue`
- **構造的特徴は notes へ**: 「if-else 構造がある」等の情報は `notes` フィールドに記録
- **一致保証**: Router と Canonicalizer の pattern 選択が一致することを parity check で検証
**例**: `skip_whitespace` パターン
- 構造: if-else 形式Pattern3IfPhi に似ている)
- ExitContract: `has_break=true`
- **chosen**: `Pattern2Break`ExitContract が決定)
- **notes**: "if-else structure with break in else branch"(構造特徴を記録)
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
### 出力先マッピング
| 出力先 | 条件 | 用途 |
|----------------------------|-------------------------------|-----------------------------------|
| `error_tags` | `chosen.is_none()` | Fail-Fast のエラーメッセージ |
| `contract_checks` | debug build + 契約違反時 | Phase 135 P1 の verifier に統合 |
| JoinIR dev/debug | `joinir_dev_enabled()==true` | 開発時のルーティング追跡 |
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
| 統計 JSON | 将来拡張 | Corpus 分析Skeleton Signature |
### error_tags との統合
- `RoutingDecision` の Fail-Fast 文言は `src/mir/join_ir/lowering/error_tags.rs` の語彙に寄せる
- 既存のエラータグ(例: `error_tags::freeze(...)`)を使用し、文字列直書きを増やさない
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
---
## 最初の対象ループ: skip_whitespace受け入れ基準
### 対象ファイル
`tools/selfhost/test_pattern3_skip_whitespace.hako`
```hako
loop(p < len) {
local ch = s.substring(p, p + 1)
local is_ws = ... // whitespace 判定
if is_ws == 1 {
p = p + 1
} else {
break
}
}
```
### Skeleton 差分
| フィールド | 値 |
|-------------------|-------------------------------------------|
| `steps[0]` | `HeaderCond { expr: p < len }` |
| `steps[1]` | `Body { ... }` (ch, is_ws 計算) |
| `steps[2]` | `BreakCheck { cond: is_ws == 0 }` |
| `steps[3]` | `Update { carrier: "p", ConstStep(1) }` |
| `carriers[0]` | `{ name: "p", role: Counter, ConstStep }` |
| `exits` | `{ has_break: true, break_has_value: false }` |
### 必要 Capability
-`ConstStepIncrement` (p = p + 1)
-`SingleBreakPoint` (else { break } のみ)
-`OuterLocalCondition` (p, len は外側定義)
-`ExitBindingsComplete` (p を境界に渡す)
### 受け入れ基準
1. `LoopCanonicalizer::canonicalize(ast)` が上記 Skeleton を返す
2. `RoutingDecision.chosen == Some(Pattern3)`
3. `RoutingDecision.missing_caps == []`
4. 既存 smoke `phase135_trim_mir_verify.sh` が退行しない
---
## 追加・変更チェックリスト
- [ ] 追加するループ形を最小 fixture に落とす(再現固定)
- [ ] LoopSkeleton の差分steps/exits/carriersを明示する
- [ ] 必要 Capability を列挙し、未達は Fail-Fast理由が出る
- [ ] 既存 smoke/verify が退行しないquick は重くしない)
docs: finalize loop canonicalizer design (P0 implementation-ready) ## Summary Loop Canonicalizer の設計を「実装可能」レベルまで固めた。 ## P0: 設計詳細化 ### LoopSkeleton の最小フィールド確定 - LoopSkeleton struct(steps/carriers/exits/captured) - SkeletonStep enum(HeaderCond/BreakCheck/ContinueCheck/Update/Body) - UpdateKind enum(ConstStep/Conditional/Arbitrary) - ExitContract, CarrierSlot, CarrierRole の定義 - SSOT 境界の原則(入力: AST、出力: Skeleton のみ) ### Capability の語彙固定(Fail-Fast reason タグ) - CAP_MISSING_* プレフィックスで統一 - 8 つの Capability を定義(ConstStepIncrement, SingleBreakPoint 等) - 新規追加時は設計書を先に更新するルール ### RoutingDecision の出力先決定 - error_tags: Fail-Fast エラーメッセージ - contract_checks: Phase 135 P1 verifier に統合 - NYASH_LOOP_ROUTING_TRACE: 開発時のルーティング追跡 - ErrorTagCollector を使用(新規 Box は作らない) ### 最初の対象ループ(skip_whitespace)の受け入れ基準 - Skeleton 差分を表形式で明示 - 必要 Capability を列挙 - 受け入れ基準 4 項目を定義 ## P1/P2: 確認完了 - joinir-design-map.md に loop-canonicalizer.md へのリンク済み - quick を重くしない運用は joinir-design-map.md に記載済み 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 04:39:52 +09:00
- [ ] 新規 Capability は先に `loop-canonicalizer.md` に追記してから実装