feat(mir): Phase 131-11-E - TypeFacts/TypeDemands 分離(SSOT)

## 実装内容

### 1) Rust MIR Builder (ops.rs + lifecycle.rs)
- OperandTypeClass で型分類(String/Integer/Unknown)
- BinOp 型推論: Integer + Unknown → Integer
- lifecycle.rs に repropagate_binop_types() パス追加
  - PHI 型解決後に BinOp 型を再計算

### 2) JSON Emission (mir_json_emit.rs)
- 結果ベースの dst_type 発行に変更
- Integer → "i64", String → {kind: handle, box_type: StringBox}

### 3) Python LLVM Backend (binop.py)
- dst_type を確実な情報として使用
- dst_type != None なら優先して処理

## 結果
-  MIR: PHI/BinOp が Integer として正しく型付け
-  VM: `Result: 3` (正しい出力)
-  JSON: `dst_type: "i64"` を発行
-  LLVM: 別の codegen 問題の可能性あり

## SSOT 設計達成
- TypeFacts(事実): 定義命令から推論
- TypeDemands(要求): 使用箇所の coercion で吸収
- 後方伝播なし: Fail-Fast に統一

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-14 18:55:05 +09:00
parent 4b87b6cc88
commit d3b3bf5372
6 changed files with 398 additions and 129 deletions

View File

@ -0,0 +1,146 @@
# JoinIR Design Map現役の地図
Status: Active
Scope: JoinIR の「Loop/If を JoinIR 化して MIR に統合する」導線検出→shape guard→lower→merge→契約検証
Related:
- SSOT: [`docs/development/current/main/joinir-architecture-overview.md`](../joinir-architecture-overview.md)
- SSOT: [`docs/development/current/main/loop_pattern_space.md`](../loop_pattern_space.md)
- SSOT: [`docs/development/current/main/joinir-boundary-builder-pattern.md`](../joinir-boundary-builder-pattern.md)
このドキュメントは Phase ログではなく、「JoinIR を触る人が迷子にならず、どこを直すべきかが一発で分かる」ための設計図(地図)です。
詳細な経緯・作業ログは `docs/development/current/main/phases/``docs/development/current/main/investigations/` に分離します。
---
## 1枚図: レイヤーAST → JoinIR → MIR → Backend
```mermaid
flowchart LR
A[AST] -->|Frontend lowering| J1[JoinIR (Structured)]
J1 -->|Normalize / Shape guard| J2[JoinIR (Normalized)]
J2 -->|JoinIR → MIR bridge| M1[MIR Module]
M1 -->|Merge into host function| M2[MIR (in builder)]
M2 --> B[Backend\n(VM / LLVM / Cranelift)]
subgraph Frontend
A
J1
end
subgraph JoinIR Core
J2
end
subgraph MIR Builder
M1
M2
end
```
読み方:
- 「Loop/If の形が認識されない」: Pattern 検出Feature/Kindと shape guard を見る
- 「JoinIR は生成できるが統合で壊れる」: MergeValueId/PHI/ExitLine/Boundaryと契約検証を見る
- 「なぜこのエラータグが出たか」: ErrorTagsSSOTを起点に呼び出し元へ辿る
---
## “箱”の責務マップ(担当境界)
| 領域 | 役割(何を決めるか) | 主な入口/箱SSOT寄り | 主な出力 | Fail-Fast典型 |
|---|---|---|---|---|
| Pattern検出 | ループ形を分類し、どの lowerer に渡すか決める | [`src/mir/builder/control_flow/joinir/patterns/router.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/router.rs), [`src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs), [`src/mir/loop_pattern_detection/mod.rs`](../../../../../src/mir/loop_pattern_detection/mod.rs) | `LoopPatternKind` / Pattern 選択 | 「分類不能」→ 明示的に Errサイレントな非JoinIR退避は禁止 |
| shape guard | 「この shape なら lower/merge 契約が成立する」を保証する | [`src/mir/join_ir/normalized/shape_guard.rs`](../../../../../src/mir/join_ir/normalized/shape_guard.rs), `src/mir/builder/control_flow/joinir/patterns/*_validator.rs` | shape OK / 詳細診断 | shape 不一致を握りつぶさず Err |
| lowering | JoinIRStructured/Normalizedを生成する | [`src/mir/join_ir/lowering/mod.rs`](../../../../../src/mir/join_ir/lowering/mod.rs), `src/mir/builder/control_flow/joinir/patterns/pattern*_*.rs` | `JoinModule` | 未対応の構造は `error_tags::freeze(...)` 等で Err |
| merge | JoinIR→MIR 変換後、ホスト関数に統合する | [`src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs), [`src/mir/builder/control_flow/joinir/merge/mod.rs`](../../../../../src/mir/builder/control_flow/joinir/merge/mod.rs) | ホスト MIR のブロック/ValueId 更新 | ValueId 競合、ExitLine 未接続、PHI 破綻を Err |
| ExitMeta | 「出口でどの carrier をどの host slot に戻すか」のメタ | [`src/mir/join_ir/lowering/carrier_info.rs`](../../../../../src/mir/join_ir/lowering/carrier_info.rs), [`src/mir/builder/control_flow/joinir/merge/exit_line/meta_collector.rs`](../../../../../src/mir/builder/control_flow/joinir/merge/exit_line/meta_collector.rs) | `ExitMeta` / `exit_bindings` | carrier 不整合(不足/過剰)を Err |
| CarrierInit | carrier 初期化の SSOTFromHost/Const/LoopLocal | [`src/mir/builder/control_flow/joinir/merge/carrier_init_builder.rs`](../../../../../src/mir/builder/control_flow/joinir/merge/carrier_init_builder.rs), [`src/mir/join_ir/lowering/carrier_info.rs`](../../../../../src/mir/join_ir/lowering/carrier_info.rs) | 初期値 `ValueId` | 初期化経路の分岐が散らばらないSSOT を使う) |
| ErrorTags | エラータグ整形の SSOT検索性・一貫性 | [`src/mir/join_ir/lowering/error_tags.rs`](../../../../../src/mir/join_ir/lowering/error_tags.rs) | 文字列タグ | 文字列ハードコードを避け、タグを一元化 |
注:
- Pattern 検出は「関数名 by-name 分岐」に依存しない(構造で決める)。必要なら dev/診断限定のガードに閉じ込める。
- shape guard は「OK なら後工程が前提にできる契約」を固定する場所で、曖昧な許容をしない。
---
## 入口(コード側のエントリポイント)
### Loopbuilder 側の導線)
- Routerbuilder 入口): [`src/mir/builder/control_flow/joinir/routing.rs`](../../../../../src/mir/builder/control_flow/joinir/routing.rs)
- `MirBuilder::try_cf_loop_joinir(...)`JoinIR ルートへ入る最初の関数)
- `MirBuilder::cf_loop_joinir_impl(...)`pattern router → legacy binding の順)
- Pattern routerテーブル駆動: [`src/mir/builder/control_flow/joinir/patterns/router.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/router.rs)
- Feature extraction: [`src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs)
- Pattern 実体(代表):
- [`src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs)
- [`src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs)
- [`src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs)
- [`src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs)
- [`src/mir/builder/control_flow/joinir/patterns/pattern5_infinite_early_exit.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/pattern5_infinite_early_exit.rs)
- 変換パイプラインJoinIR→MIR→Merge の統一導線):
- [`src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`](../../../../../src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs)
- Merge統合の本体: [`src/mir/builder/control_flow/joinir/merge/mod.rs`](../../../../../src/mir/builder/control_flow/joinir/merge/mod.rs)
- ExitLine: [`src/mir/builder/control_flow/joinir/merge/exit_line/mod.rs`](../../../../../src/mir/builder/control_flow/joinir/merge/exit_line/mod.rs)
- Merge の契約検証debug: [`src/mir/builder/control_flow/joinir/merge/contract_checks.rs`](../../../../../src/mir/builder/control_flow/joinir/merge/contract_checks.rs)
### JoinIRIR/正規化/ブリッジ)
- JoinIR 定義・入口: [`src/mir/join_ir/mod.rs`](../../../../../src/mir/join_ir/mod.rs)
- Normalized / shape guard: [`src/mir/join_ir/normalized/shape_guard.rs`](../../../../../src/mir/join_ir/normalized/shape_guard.rs)
- JoinIR → MIR bridge: [`src/mir/join_ir_vm_bridge/mod.rs`](../../../../../src/mir/join_ir_vm_bridge/mod.rs)
### 共通(診断とタグ)
- TraceJoinIR ルートの統一トレース): [`src/mir/builder/control_flow/joinir/trace.rs`](../../../../../src/mir/builder/control_flow/joinir/trace.rs)
- Error tagsSSOT: [`src/mir/join_ir/lowering/error_tags.rs`](../../../../../src/mir/join_ir/lowering/error_tags.rs)
---
## 不変条件Fail-Fast
JoinIR を触るときは、次を破ったら「即エラーで止める」前提で設計・実装する。
### 形状shape
- Pattern は「認識できる shape だけ」を通し、曖昧な許容をしない。
- 形状が合わないときは `Ok(None)` で静かに進めない非JoinIRへの退避を作らない
- 例外: 明確な “routing” で「別 JoinIR 経路」を選ぶのは可(同一層内での選択)。
### ValueId / PHI / Boundary の世界
- JoinIR 内部JoinValueSpace 等)と host MIR builder の ValueId を混ぜない。
- Boundary は JoinIR↔host の橋渡し契約:
- `join_inputs``host_inputs` の対応が明示される
- Exit 側は “carrier 名” をキーにして reconnection されるExitMeta/exit_bindings
- PHI は「誰が確保するか」を固定し、衝突を許さないPHI dst の予約・再利用禁止)。
### ExitLine 契約
- ExitLine は「出口へ集約する」ための契約であり、未接続の経路を残さない。
- carrier/slot の不足・余剰・不整合は `error_tags::exit_line_contract(...)` 等で即エラーにする。
---
## 追加手順チェックリスト(新しいループ形を飲み込む最小手順)
「新しいループ形」を JoinIR で扱えるようにするときの最小手順。
1. Fixture を追加(再現可能に固定)
- `apps/tests/` または `apps/smokes/` に最小の `.hako` を追加(対象形が一目で分かるもの)
2. Pattern/feature を追加(検出)
- `src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs`(必要なら feature 抽出を拡張)
- `src/mir/loop_pattern_detection/`(分類/補助解析が必要ならここに追加)
3. shape guard を追加(契約の固定)
- 形状・前提条件を validator として分離し、失敗は Err にする
4. lower を追加JoinIR を生成)
- 既存 pattern のコピーではなく、「今回の shape が要求する最小構成」にする
- エラーは `src/mir/join_ir/lowering/error_tags.rs` を使いタグを固定する
5. merge/ExitLine を接続(契約が満たされるように)
- carrier/ExitMeta/Boundary が揃っているか確認する
6. Tests を追加(仕様固定)
- unit: pattern/validator/merge の局所テスト
- smoke: `tools/smokes/v2/` の profile に軽いケースを追加quick を重くしない)
7. Docs を更新(地図を更新)
- `docs/development/current/main/loop_pattern_space.md`(パターン空間に追記が必要なら)
- `docs/development/current/main/joinir-architecture-overview.md`(箱/契約が増えたなら)
- 本ファイル(入口・責務マップの更新)