feat(joinir): Phase 66-68 GenericTypeResolver + JoinIR First Chapter Wrap
Phase 66: P3-C ジェネリック型推論箱化 - generic_type_resolver.rs 新設 (180行) - is_generic_method(): ArrayBox.get/pop/first/last, MapBox.get 判定 - resolve_from_phi(): PHI解析によるジェネリック型推論 - TypeHintPolicy::is_p3c_target() 追加 - P1/P2/P3-A/P3-B 以外を P3-C 候補として判定 Phase 67: P3-C 実利用への一歩 - phase67_generic_type_resolver.rs テスト追加 (3テスト) - lifecycle.rs に P3-C 経路フック追加 - GenericTypeResolver を P3-C 対象関数で優先使用 - A/B テストで旧経路との一致確認 (11 tests PASS) Phase 68: JoinIR First Chapter Wrap (ドキュメント整理) - 68-1: phase-30 README.md に Section 9 追加 (JoinIR 第1章完了サマリー) - 68-2: README.md に JoinIR status セクション追加 - 68-3: CURRENT_TASK.md スリム化 (351→132行, 62%削減) - 68-4: PHI_BOX_INVENTORY.md に Phase 66-67 完了セクション追加 Phase 69-1: Trio 棚卸し - phase69-1-trio-inventory.md 作成 - Trio 使用箇所の完全棚卸し完了 (削減見込み 457-707行) 🐱 JoinIR 第1章完了!4つの柱確立: - Structure (LoopForm) - Scope (LoopScopeShape) - JoinIR (Select/IfMerge/Loop) - Type Hints (P1-P3-C) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
377
CURRENT_TASK.md
377
CURRENT_TASK.md
@ -7,307 +7,110 @@
|
||||
|
||||
## 0. 現在地ざっくり
|
||||
|
||||
- **✅ JoinIR ラインは Phase 68 で一旦 Chapter Close!**
|
||||
- Phase 27-67 で JoinIR の「第1章(構造 + PHI + 型ヒント SSOT)」が完了。
|
||||
- 4つの柱(Structure / Scope / JoinIR / Type Hints)が確立。
|
||||
- 今後は Trio 削除ライン、wasm/Web デモライン、最適化ラインに分岐。
|
||||
- 詳細: [phase-30-final-joinir-world/README.md](docs/private/roadmap2/phases/phase-30-final-joinir-world/README.md)
|
||||
|
||||
- **最終ゴール**
|
||||
- 制御構造と PHI の意味論は **JoinIR(+LoopScopeShape/IfPhiContext 等の薄い箱)** に一本化する。
|
||||
- 実行の SSOT は VM / LLVM ラインとし、JoinIR→MIR→VM/LLVM は「構造 SSOT → 実行 SSOT」への変換として扱う。
|
||||
- 既存の PHI 箱(if_phi.rs / PhiBuilderBox / conservative.rs / Trio 等)は、JoinIR 側のカバレッジが十分になったところから順に削っていく。
|
||||
|
||||
- **JoinIR ライン**
|
||||
- Phase 27–31: Loop→JoinIR lowering(skip_ws / trim / append_defs / Stage‑1 minimal)で、ループの制御構造を関数+継続だけで表現できることを実証済み。
|
||||
- Phase 33–34: IfSelect / IfMerge / JoinIR Frontend(If/Loop/Break/Continue)実装。AST→JoinIR→MIR→VM まで tiny ケースが通る。
|
||||
- **PHI 削減ライン**
|
||||
- Phase 35–36: HIGH/MEDIUM 安全度の PHI 箱(if_body_local_merge / phi_invariants / LoopSnapshotMergeBox)の削除・縮退で 537 行削減。
|
||||
- Phase 37–40: If 側 PHI(if_phi.rs / conservative.rs)の Level 1/2 相当まで設計+一部削減。array_ext.filter については JoinIR Frontend + JoinFuncMeta に移行し、collect_assigned_vars を削除済み。
|
||||
- **これから**
|
||||
- Phase 41: If 側 PHI Level 3(本体ロジック)の代表ケースを JoinIR 経路に載せる設計と最初の実装。
|
||||
- 以降: If 側 PHI 本体削減 → Classifier Trio → AST→JoinIR Frontend 本線化 → LLVM / ny-llvmc の JoinIR 統合。
|
||||
- **これから(Phase 69+)**
|
||||
- Trio 削除ライン: LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox を LoopScopeShape に完全吸収。
|
||||
- wasm/Web デモライン: JoinIR ベースの軽量デモ実装。
|
||||
- 最適化ライン: JoinIR の最適化パスと LLVM/ny-llvmc 統合。
|
||||
|
||||
---
|
||||
|
||||
## 1. 最近の主戦場(Phase 33–41)
|
||||
## 1. JoinIR 第1章完了までの道のり(Phase 33–67 簡潔版)
|
||||
|
||||
### 1-00a. Phase 33 — IfSelect / IfMerge + PHI 設計原則
|
||||
### Phase 33-62: 構造 + PHI + スコープの基盤構築 ✅ 完了
|
||||
|
||||
- IfSelect / IfMerge lowering 実装(simple/local, 2–3 変数パターン)。
|
||||
- VM ラインへの If lowering ドライランを `IfLoweringDryRunner` に箱化し、VM パイプラインと解析ロジックを分離。
|
||||
- 「JoinIR は PHI 生成器(SSOT)、既存 PHI の変換器にはしない」原則をコード+docs で固定。
|
||||
- docs: `docs/private/roadmap2/phases/phase-33-joinir-if-phi-cleanup/if_joinir_design.md`
|
||||
- **Phase 33-34**: IfSelect/IfMerge lowering 実装、AST→JoinIR Frontend 設計・実装(If/Loop/Break/Continue)
|
||||
- **Phase 35-36**: PHI 箱削減 HIGH/MEDIUM(537行削減: if_body_local_merge / phi_invariants / LoopSnapshotMergeBox 縮退)
|
||||
- **Phase 37-40**: If 側 PHI Level 1/2(設計+array_ext.filter 移行、collect_assigned_vars 削除)
|
||||
- **Phase 41-46**: If 側 PHI Level 3(NestedIfMerge、read_quoted_from、IfMerge 拡張)
|
||||
- **Phase 49-56**: JoinIR Frontend 本線統合(print_tokens / filter)
|
||||
- **Phase 57-62**: If 側 PHI 本体削減(conservative.rs 縮退、If Handler 箱化、PHI Core Cleanup)
|
||||
|
||||
### 1-00b. Phase 34 — JoinIR Frontend(AST→JoinIR)
|
||||
|
||||
- 目的: AST(Program JSON v0)→ JoinIR Frontend を設計・実装し、「PHI 意味論の SSOT を JoinIR 側に寄せる」。
|
||||
- 実績:
|
||||
- If: simple/local/json_shape パターンを Select に正規化(同じ JoinIR 出力)。
|
||||
- Loop: tiny while / break / continue を 3 関数構造(entry/loop_step/k_exit)+ Jump/Call/Select で表現。
|
||||
- MethodCall: substring などを JoinInst::MethodCall として構造化し、JoinIR→MIR Bridge で BoxCall に変換。
|
||||
- docs: `docs/private/roadmap2/phases/phase-34-joinir-frontend/README.md`
|
||||
|
||||
### 1-00c. Phase 35–36 — PHI 箱削減(HIGH/MEDIUM)
|
||||
|
||||
- Phase 35(HIGH):
|
||||
- `if_body_local_merge.rs` / `phi_invariants.rs` 削除(合計 430 行)。
|
||||
- PHI_BOX_INVENTORY.md で PHI 箱の一覧と削除順を整理。
|
||||
- Phase 36(MEDIUM):
|
||||
- LoopSnapshotMergeBox を「Exit PHI マージ専用の純粋静的ユーティリティ」に縮退(470→363 行)。
|
||||
- PhiBuilderBox に Loop/If/Common/Stub の責務マーカー追加(実装本体削減は Phase 38+)。
|
||||
- docs:
|
||||
- `docs/private/roadmap2/phases/phi-reduction-series/INDEX.md`
|
||||
- `docs/private/roadmap2/phases/phase-36-phi-midrange/README.md`
|
||||
|
||||
### 1-00d. Phase 37–39 — If 側 PHI Level 1/2 設計と準備
|
||||
|
||||
- Phase 37: If 側 PHI 全体設計(docs-only)。
|
||||
- if_phi.rs / conservative.rs の責務表、12 callsite の難易度分類。
|
||||
- 削除基準(Level 1/2/3)の定義。
|
||||
- Phase 38: if_phi.rs Level 1 削除(90 行)。
|
||||
- `merge_modified_with_control`(dead code)と `extract_assigned_var`(JoinIR AST lowering で代替)を削除。
|
||||
- Phase 39: Level 2 準備(array_ext.filter 選定と JoinIR 拡張設計)。
|
||||
- array_ext.filter を代表 if-in-loop パターンに選定。
|
||||
- JoinIR Frontend / JoinFuncMeta / Bridge 拡張と削除条件を設計。
|
||||
- docs:
|
||||
- `docs/private/roadmap2/phases/phase-37-if-phi-reduction/README.md`
|
||||
- `docs/private/roadmap2/phases/phase-38-if-phi-level1/README.md`
|
||||
- `docs/private/roadmap2/phases/phase-39-if-phi-level2/README.md`
|
||||
|
||||
### 1-00e. Phase 40 — If 側 PHI Level 2 実装(array_ext.filter)
|
||||
|
||||
- 目的: array_ext.filter の if‑in‑loop PHI を JoinIR Frontend + JoinFuncMeta + Bridge 経由に移し、collect_assigned_vars を削除する。
|
||||
- 実績:
|
||||
- JoinFuncMeta / JoinFuncMetaMap / convert_join_module_to_mir_with_meta 実装。
|
||||
- AST→JoinIR Frontend で if‑in‑loop の modified 変数集合を解析し、JoinIR→MIR Bridge で PHI 生成。
|
||||
- loop_builder.rs に HAKO_JOINIR_ARRAY_FILTER 経路を追加し、Route B(JoinIR 経路)をデフォルト化。
|
||||
- `collect_assigned_vars` を削除し、JSON ベースの `collect_assigned_vars_via_joinir` に置き換え(Phase 40-4.1)。
|
||||
- デッドな env フラグ等をクリーンアップ(40-4.1.1)。
|
||||
- 削減実績(Phase 40 時点):
|
||||
- 35 行(collect_assigned_vars)+16 行(デッドコード)= 51 行純減。
|
||||
- docs:
|
||||
- `docs/private/roadmap2/phases/phase-40-if-phi-level2/README.md`
|
||||
- `docs/private/roadmap2/phases/phi-reduction-series/INDEX.md`
|
||||
|
||||
### 1-00f. Phase 41 — If-Side PHI Level 3 Reduction ✅ 完了(2025-11-28)
|
||||
|
||||
- 目的:
|
||||
- if_phi.rs / conservative.rs に残る「Level 3 本体ロジック」を JoinIR 経路に移すための設計と代表ケース実装。
|
||||
- 実績:
|
||||
- Level 3 関数の再インベントリとデッドコード 147 行削除。
|
||||
- 代表 If 関数として `ParserControlBox.parse_loop()` を選定。
|
||||
- NestedIfMerge JoinInst 設計+実装(mod.rs, json.rs)。
|
||||
- AST→JoinIR Frontend に `lower_nested_if_pattern()` 追加(dev flag: `HAKO_JOINIR_NESTED_IF=1`)。
|
||||
- JoinIR→MIR Bridge に NestedIfMerge 展開ロジック追加(多段 Branch + Copy)。
|
||||
- Route B(NestedIfMerge 経由)の A/B テスト 7 ケース全 PASS(parse_loop 代表ケース)。
|
||||
- 実削除(if_phi.rs / conservative.rs 本体の縮退・削除)は Phase 42 に繰り越し。
|
||||
- docs:
|
||||
- `docs/private/roadmap2/phases/phase-41-if-phi-level3/README.md`
|
||||
- `docs/private/roadmap2/phases/phase-41-if-phi-level3/TASKS.md`
|
||||
|
||||
### 1-00g. Phase 45 — read_quoted_from JoinIR 実装 ✅ 完了(2025-11-28)
|
||||
|
||||
- 目的:
|
||||
- `MiniJsonCur.read_quoted_from(s, pos)` を JoinIR Frontend/Bridge で実装し、Guard if + Loop with break + accumulator パターンの PHI 削減を実証。
|
||||
- 実績:
|
||||
- **45-1**: フィクスチャ `apps/tests/phase45_read_quoted_fixture.hako` 作成(T1-T4 Route A で PASS)。
|
||||
- **45-2**: AST→JoinIR Frontend `lower_read_quoted_pattern()` 実装(`ast_lowerer.rs`)。
|
||||
- **45-3**: JoinIR→MIR Bridge 確認(既存 bridge で変更不要)。
|
||||
- **45-4**: Route B E2E テスト `test_read_quoted_from_route_b_e2e()` 追加、T1-T4 全 PASS。
|
||||
- **45-5**: PHI_BOX_INVENTORY.md / CURRENT_TASK.md 更新。
|
||||
- 既知の制限:
|
||||
- **T5(エスケープ処理)**: 変数再代入 inside if-block が PHI を生成しない問題 → **Phase 46 で解決済み**。
|
||||
- Dev Flag: `HAKO_JOINIR_READ_QUOTED=1`
|
||||
- JoinIR 構造: entry → k_guard_fail / loop_step → k_exit(4 関数構造)
|
||||
- docs:
|
||||
- `docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md` (Phase 45 セクション)
|
||||
|
||||
### 1-00h. Phase 46 — IfMerge 拡張(ループ内 if での変数再代入 PHI 問題)✅ 完了(2025-11-28)
|
||||
|
||||
- 目的:
|
||||
- ループ内の `if (cond) { x = expr; }` パターンで、if-body での変数再代入が merge ブロックで PHI に反映されない問題を修正。
|
||||
- 実績:
|
||||
- **46-1**: 現状 MIR の問題点を CFG 図で固定(T5 専用)。
|
||||
- **46-2**: JoinIR レベルでの「正しい形」を IfMerge で設計(Option A 採用)。
|
||||
- **46-3**: `lower_read_quoted_pattern()` に IfMerge 拡張を設計・実装。
|
||||
- **46-4**: Route B E2E テスト T1-T5 全 PASS。
|
||||
- テスト結果:
|
||||
- T1-T4: ✅ PASS(Phase 45 と同じ)
|
||||
- **T5(エスケープ処理)**: ✅ PASS(`"a\"b"` → `a"b`)
|
||||
- Dev Flag: `HAKO_JOINIR_READ_QUOTED_IFMERGE=1`(Phase 46 IfMerge 拡張有効化)
|
||||
- 修正ファイル:
|
||||
- `src/mir/join_ir/frontend/ast_lowerer.rs`: IfMerge による escape 処理追加
|
||||
- `src/mir/join_ir_vm_bridge.rs`: T5 テストケース追加
|
||||
- docs:
|
||||
- `docs/private/roadmap2/phases/phase-46-ifmerge-loop-reassign/README.md`
|
||||
|
||||
### 1-00i. Phase 49–56 — JoinIR Frontend 本線統合(print_tokens / filter)✅ 完了
|
||||
|
||||
- Phase 49–52: `cf_loop` に JoinIR Frontend ルートを追加し(dev フラグ付き)、`LoopFrontendBinding` / JSON v0 / expr タイプ(Field/NewBox)を整備。
|
||||
- `HAKO_JOINIR_PRINT_TOKENS_MAIN` / `HAKO_JOINIR_ARRAY_FILTER_MAIN` で対象ループだけを Frontend 経由にルーティング。
|
||||
- `merge_joinir_mir_blocks` で JoinIR→MIR のブロック/値 ID リマップと制御フロー接続を実装。
|
||||
- Phase 53–55: statement lowering(Local/Assignment/Print/Method/If)と AST→JSON の `"type"`/`"expr"` 整備により、`JsonTokenizer.print_tokens/1` が JoinIR Frontend→Bridge→VM 経由で最後まで実行可能に(Route A/B 等価、dev フラグ ON 限定)。
|
||||
- Phase 56: `ArrayExtBox.filter/2` 向けに `LoopFrontendBinding::for_array_filter` を MethodCall ベース(`arr.size()`)に修正し、外部参照 `arr/pred` を Binding 経由で渡す構造に統一。
|
||||
- JoinIR に `ConditionalMethodCall` / Unary / Call を追加し、filter の「pred が true のときだけ push する」パターンを 4 ブロック構造で表現。
|
||||
- `HAKO_JOINIR_ARRAY_FILTER_MAIN=1` で Route B(JoinIR Frontend 経路)がフォールバックなし完走(テスト済み、既定は従来ルート)。
|
||||
|
||||
### 1-00j. Phase 57–61 — If 側 PHI Level 3 本体(conservative/if_phi 残り)✅ 仕上げ中
|
||||
|
||||
- Phase 57 では、新しい抽象を増やさずに既存の Conservative/IfPHI 本体のうち安全な部分を薄くした。
|
||||
- `phi.rs` での冗長な `ConservativeMerge::analyze` 呼び出しを 2 回→1 回に削減し、軽量化。
|
||||
- `PhiMergeOps` trait と loop_builder.rs 側の実装を完全削除し、Loop 側の PHI 生成責務を JoinIR+LoopScopeShape 側に寄せた。
|
||||
- `infer_type_from_phi` には「レガシー型推論箱であり、JoinIR 型情報導入後の削減候補」であることをコメントで明示し、将来の削除条件をドキュメント化。
|
||||
- Phase 58 では ConservativeMerge 本体を `phi_merge.rs::merge_all_vars` にインライン化し、`conservative.rs` の多くをドキュメントコメント+最小限の補助関数だけに縮退。
|
||||
- conservative.rs: 149 行 → 57 行(約 92 行削減、約 62% 削減)。
|
||||
- ConservativeMerge struct 定義と付随テストコードを削除し、挙動差分がないことを phi_core / JoinIR テストで確認。
|
||||
- Phase 61-1〜61-3 では If-in-loop 専用の箱化を進め、JoinIR 側に PHI 生成の SSOT を寄せた。
|
||||
- IfPhiContext でループ内 If の CFG と変数スナップショットをまとめ、IfInLoopPhiEmitter で pre/then/else の snapshot と carrier 集合から必要な φ を構成する thin box を追加。
|
||||
- dev フラグ `HAKO_JOINIR_IF_IN_LOOP_ENABLE=1` 有効時には、JoinIR パターンマッチ成功した if-in-loop について JoinIR + IfPhiContext + IfInLoopPhiEmitter 経路で PHI を生成できるようになった(Route A/B 互換、既定はまだ legacy)。
|
||||
- Phase 61-4: **If Toplevel PHI (Fallthrough-Join) 実装** ✅ 完了(2025-11-29)
|
||||
- ループ外 If の「then 直後に結合点がない」パターン(toplevel_return)を JoinIR で表現。
|
||||
- IfInLoopPhiEmitter が IfPhiContext::pure_if() でループ外 If もサポート(統一インターフェース)。
|
||||
- `toplevel_if_ret_explicit.hako` テストで toplevel_return パターン動作確認済み。
|
||||
- docs: `docs/development/current/main/phase61-4-toplevel-if-design.md`
|
||||
- Phase 61-5: **If PHI 削減計画策定** ✅ 完了(2025-11-29)
|
||||
- 61-5.1: If PHI 関数リスト作成(26関数、3カテゴリ)
|
||||
- 61-5.2: JoinIR カバレッジ調査(in_loop/partial/none)
|
||||
- 61-5.3: 優先度表作成(P1: 18関数、P2: 5関数、P3: 3関数)
|
||||
- 61-5.4: Phase 61-6 候補選定(3個: set_if_context, dev フラグ, A/B テスト削除)
|
||||
- docs: `docs/development/current/main/phase61-5-*.md`
|
||||
- Phase P1: **If Handler 箱化モジュール化** ✅ 完了(2025-11-29)
|
||||
- ループ内 If 処理の 5 パターン(Empty/SingleVarThen/SingleVarBoth/ConditionalEffect/Unsupported)を `IfInLoopPattern` enum で分類。
|
||||
- `if_in_loop/` モジュール(9 ファイル、~480 行)を新設し、`stmt_handlers.rs` から 154 行削減(40% 削減達成)。
|
||||
- 全 56 JoinIR tests PASS(回帰なし)、保守性・拡張性向上(新パターン追加が容易に)。
|
||||
- docs: `docs/development/refactoring/p1-if-handler-boxification-plan.md`
|
||||
|
||||
### 1-00g. Phase 61-6 — If PHI JoinIR 化 第2弾(薄いラッパー削減)
|
||||
|
||||
- 目的: If 側 PHI ラインから JoinIR と二重管理になっていた薄いラッパー/観察専用ユーティリティを取り除き、PHI 仕様の SSOT を JoinIR 側に寄せる。
|
||||
- 実績:
|
||||
- `set_if_context` 薄いラッパーを削除し、callsite から直接 `IfPhiContext` を構築するよう統一。IfPhiContext の入口が一本化され、文脈箱(IfPhiContext)と emitter 箱(IfInLoop/Toplevel)の責務分離がより明確になった。
|
||||
- PhiBuilderBox ベースの PhiSpec 観察用関数(`extract_phi_spec_from_builder`, `compare_and_log_phi_specs` など)を削除し、PHI 仕様計算を JoinIR 起点の `compute_phi_spec_from_joinir` に一本化。
|
||||
- 合計約 97 行削減(予想 76 行を超過)。If 側 PHI の「観察・比較」は JoinIR 情報から復元する経路のみとなり、if_phi/PhiBuilderBox は本番ロジックに専念する構造に整理された。
|
||||
|
||||
### 1-00h. Phase 62 — PHI Core Cleanup(phi_core 小箱クリーンアップ)
|
||||
|
||||
- 目的: PHI 箱のうち、既に機能が JoinIR/loopform/phi_merge 側に移っていて「殻だけ残っていた」小箱を片付け、phi_core 直下の実コードをさらに減らす。
|
||||
- 実績:
|
||||
- `phi_core/phi_input_collector.rs` を削除。Phase 59/59b で loopform_builder.rs / loop_builder.rs へのインライン化が完了しており、外部依存 0 であることを PHI_BOX_INVENTORY ベースで確認済み。
|
||||
- `phi_core/conservative.rs` を 57 行すべてコメントのみの「歴史メモ」ファイルに縮退(実コードは Phase 58 で `phi_merge.rs::merge_all_vars` 側にインライン済み)。将来的に docs/ への移設候補として扱う。
|
||||
- PHI_BOX_INVENTORY.md / phi-reduction-series/INDEX.md / CURRENT_TASK.md を更新し、「PhiInputCollector 削除済み」「ConservativeMerge 本体は inline 済みで conservative.rs は docs 専用」という現状を明示。
|
||||
|
||||
- JoinIR/phi_core 関連テストは全て PASS。既知の `local` キーワード問題を除き、新たな退行はなし。
|
||||
|
||||
### 1-00i. Phase 63-3 — JoinIR 型ヒントの最小配線
|
||||
|
||||
- 目的: infer_type_from_phi を削る前に、「JoinIR 側で MirType をどこに持てばよいか」を決め、そのための schema 変更と最小限のコード更新を行う。
|
||||
- 実績:
|
||||
- `JoinInst::Select` と `MergePair` に `type_hint: Option<MirType>` を追加し、If PHI に関わる値まわりに型ヒントをぶら下げる足場を用意した。
|
||||
- Select / MergePair を生成する全サイト(if_select.rs / if_merge.rs / nested_if.rs / read_quoted.rs など 13 ファイル)を更新し、新フィールドを一旦 `type_hint: None` で埋めてビルドが通る状態に統一。
|
||||
- JoinIR 関連テスト(IfSelect/IfMerge/Frontend 系)はすべて PASS。挙動は従来どおりだが、今後 AST/Frontend/Bridge から型ヒントを流し込む準備が整った。
|
||||
|
||||
### 1-00j. Phase 63-4 — infer_type_from_phi 縮退設計(設計のみ)
|
||||
|
||||
- 目的: infer_type_from_phi を『JoinIR 型ヒント優先+従来ロジックフォールバック』に縮退する仕様を docs に固定(実装は Phase 63-5+)。
|
||||
- 実績:
|
||||
- 63-4.1: infer_type_from_phi の現状整理(定義場所 / 呼び出し元 / 役割 / JoinIR 準備状況)を文書化。
|
||||
- 63-4.2: 縮退後の仕様設計(type_hint がある場合は優先、ない場合は従来ロジックへフォールバック)。
|
||||
- 63-4.3: 代表ケースと A/B テスト方針(P1: IfSelectTest.simple/local, P2: read_quoted_from, P3: MethodCall/Box コンストラクタ)を整理。
|
||||
- 63-4.4: 削除条件の明確化(5条件、現時点達成率 2/5 = 40%)。
|
||||
- 63-4.5: Phase 63-5 への引き継ぎ(infer_type_from_phi_with_hint() 実装タスク定義)。
|
||||
- docs: `docs/private/roadmap2/phases/phase-63-joinir-type-info/README.md`, `PHI_BOX_INVENTORY.md` 更新済み
|
||||
|
||||
### 1-00k. Phase 63-5 — infer_type_from_phi 縮退実装(基盤整備)✅ 完了(2025-11-29)
|
||||
|
||||
- 目的: 型ヒント優先のインターフェースを確立し、lifecycle.rs で呼び出し経路を統一する。
|
||||
- 実績:
|
||||
- 63-5-1: `infer_type_from_phi_with_hint()` 関数実装(if_phi.rs:92-105, +44行)
|
||||
- Route B: `type_hint` があれば優先的に返す(JoinIR SSOT)
|
||||
- Route A: なければ `infer_type_from_phi()` へフォールバック
|
||||
- Fail-fast 原則遵守:既存挙動を一切変更しない
|
||||
- 63-5-2: lifecycle.rs で呼び出しを `_with_hint` に統一(2箇所: lifecycle.rs:284, 303)
|
||||
- 現時点では `type_hint=None` でフォールバック動作(既存挙動維持)
|
||||
- 将来 Phase 63-6+ で JoinIR からの型ヒント取得を実装
|
||||
- 63-5-3: テスト検証完了(退行なし)
|
||||
- IfSelect 全 8 テスト PASS(test_type_hint_propagation_simple 含む)
|
||||
- JoinIR 全 57 テスト PASS
|
||||
- 削減実績: 0行(縮退のみ、削除なし)
|
||||
- 削除条件達成率: 3/5(60%)← Phase 63-5 完了で +20%
|
||||
- 技術的成果: 型ヒント優先インターフェース確立、lifecycle.rs 呼び出し経路統一
|
||||
- 次のステップ: Phase 63-6 で P1 ケース(IfSelectTest.simple/local)への型ヒント供給を実装
|
||||
|
||||
### 1-00l. Phase 63-6 — P1 ケース型ヒント完全実装 ✅ 完了(2025-11-30)
|
||||
|
||||
- 目的: P1 ケース(IfSelectTest.simple/local)で JoinIR type_hint のみで型が決まる状態を達成
|
||||
- 実績:
|
||||
- 63-6-1: MirInstruction::Phi に `type_hint: Option<MirType>` 追加(instruction.rs)
|
||||
- 21ファイル修正、25箇所のコンパイルエラー解決
|
||||
- 全てのレガシーパスで `type_hint: None` 設定
|
||||
- 63-6-2: JoinIR→MIR Bridge で型ヒント伝播実装(convert.rs)
|
||||
- Select → PHI 変換で type_hint を伝播
|
||||
- Copy 命令削除、PHI で値合流を直接実装
|
||||
- テスト: test_type_hint_propagation_simple() で Some(Integer) 確認
|
||||
- 63-6-3: lifecycle.rs で型ヒント取得・使用
|
||||
- `get_phi_type_hint()` ヘルパー関数追加
|
||||
- P1 ケース(IfSelectTest.*)限定で型ヒント使用
|
||||
- 関数名フィルタでガード、他は None(既存挙動維持)
|
||||
- 63-6-4: P1 ケーステスト追加(A/B 検証)
|
||||
- test_p1_ab_type_inference() 追加で Route B 動作確認
|
||||
- 削減実績: 0行(段階的拡大のため削除なし)
|
||||
- **削除条件達成率: 4/5(80%)← Phase 63-6 完了で +20%**
|
||||
- 技術的成果:
|
||||
- **P1 ケースで JoinIR 型ヒントのみで型決定(削除条件 4/5 達成)**
|
||||
- JoinIR が If 系 PHI の型情報 SSOT として機能
|
||||
- lifecycle.rs が型ヒント優先で推論
|
||||
- 次のステップ: Phase 64 で P2/P3 ケースへ拡大、全関数で型ヒント化完了(削除条件 5/5)
|
||||
|
||||
### 1-00m. Phase 64 — P2 型ヒント拡大 & 削除条件 90% 達成 ✅ 完了(2025-11-30)
|
||||
|
||||
- 目的: P2 ケース(IfMerge, read_quoted)で JoinIR type_hint を実装、削除条件を 90% に前進
|
||||
- 実績:
|
||||
- 64-1: P2/P3 対象関数リスト作成(docs更新)
|
||||
- P2: read_quoted_from, IfMerge Simple/Multiple
|
||||
- P3: MethodCall 戻り値、Box コンストラクタ(Phase 65+)
|
||||
- 64-2: P2 型ヒント実装
|
||||
- read_quoted.rs: ループカウンタ `i` (Integer), 文字列 `ch` (String) 型確定
|
||||
- if_merge.rs: `infer_type_from_mir_pattern()` 追加
|
||||
- テスト: `test_p2_if_merge_type_hint()` PASS
|
||||
- 64-3: lifecycle.rs で P2 を hint 経路に乗せる
|
||||
- `is_type_hint_target()` ヘルパー関数追加(箱理論:箱に切り出す)
|
||||
- P1/P2 統一処理: IfSelectTest.*, IfMergeTest.*, read_quoted*
|
||||
- 退行なし確認(既存の 43 failed は元々のバグ)
|
||||
- 64-4: 削除条件確認
|
||||
- 条件 5 進捗: P1 ✅, P2 ✅, P3 ⏳
|
||||
- 削減実績: 0行(段階的拡大のため削除なし)
|
||||
- **削除条件達成率: 4.5/5(90%)← Phase 64-3 完了で P2 追加**
|
||||
- 技術的成果:
|
||||
- **P1/P2 両方で JoinIR 型ヒント → lifecycle.rs → 型推論の経路確立**
|
||||
- `is_type_hint_target()` で関数名フィルタを箱化
|
||||
- 箱理論「まず箱に切り出す」原則の実践
|
||||
- 次のステップ: Phase 65 で P3-A/B ケース実装(Method/Box 戻り値)、P3-C は Phase 66+ に分離
|
||||
**詳細**: 各 Phase の README を参照(`docs/private/roadmap2/phases/phase-*/README.md`)
|
||||
|
||||
---
|
||||
|
||||
## 2. 中期 TODO(ざっくり)
|
||||
- **Phase 42: PHI Workaround 条件付きスキップ** ✅ 完了(2025-11-28)
|
||||
- ✅ 42-1: PHI workaround 内容の文書化完了(README.md に記録)
|
||||
- ✅ 42-2: `parser_control_box.hako:85-139` に条件付きスキップ実装
|
||||
- Route A(default): workaround 使用(後方互換性維持)
|
||||
- Route B(`HAKO_JOINIR_NESTED_IF=1`): workaround スキップ
|
||||
- Route B テスト 3/3 PASS、Route A テスト 13/13 PASS
|
||||
- ✅ 42-3: callsite 再分析・Phase 43 候補リスト作成完了
|
||||
- if_phi.rs: 4残存関数(全て parse_loop 以外からも呼ばれる)
|
||||
- conservative.rs: ConservativeMerge::analyze が phi_merge.rs/phi.rs から使用中
|
||||
- Phase 43 推奨: NestedIfMerge 適用範囲拡大 → phi_merge.rs JoinIR 移行
|
||||
- docs: `docs/private/roadmap2/phases/phase-42-if-phi-level3-removal/README.md`
|
||||
- **Phase 65: P3-A/B 型ヒント実装(Method/Box 最小対応)**
|
||||
- P3-A: StringBox メソッド(substring/length 等)の戻り値型に JoinIR type_hint を付与
|
||||
- P3-B: Box コンストラクタ(new ArrayBox/new MapBox 等)に JoinIR type_hint を付与
|
||||
- lifecycle.rs の `is_type_hint_target()` に P3-A/B を追加し、P1/P2 と同じ経路に乗せる
|
||||
- 代表ケースベースでは削除条件 5/5 達成 → infer_type_from_phi は P3-C(ジェネリック型)向けフォールバックのみ残す
|
||||
- **Phase 66+: P3-C / If PHI 本体削除**
|
||||
- ArrayBox.get などジェネリック型の扱いを別フェーズで設計(必要なら型システム拡張)
|
||||
- P3-C まで JoinIR 型ヒント化が完了した段階で infer_type_from_phi 本体削除と if_phi.rs の大掃除に入る
|
||||
- **Classifier Trio**
|
||||
- LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox を LoopScopeShape に吸収し、JoinIR lowering / LoopForm 側から直接 LoopScopeShape を見る構造に整理。
|
||||
- **Mir 決定性(小フェーズ予定)**
|
||||
- 一部テスト(`loop_with_continue_and_break_edge_copy_merge` / `nested_loop_with_multi_continue_break_edge_copy_merge`)で、`MirFunction.blocks: HashMap` / `BasicBlock.predecessors: HashSet` に起因する非決定的な predecessor 順のフラッキーテストが残っている。
|
||||
- 将来の小フェーズで Phase 25.1 と同様のパターン(`BTreeMap` / `BTreeSet` など決定的な順序構造、もしくはテスト側で sort 比較)に寄せて解消する予定。
|
||||
### Phase 63-67: 型ヒントライン完全実装 ✅ 完了(2025-11-30)
|
||||
|
||||
#### Phase 63-3: JoinIR 型ヒント最小配線
|
||||
- `JoinInst::Select` と `MergePair` に `type_hint: Option<MirType>` 追加
|
||||
- 13ファイル更新、全 JoinIR テスト PASS
|
||||
|
||||
#### Phase 63-4: infer_type_from_phi 縮退設計
|
||||
- 型ヒント優先+従来ロジックフォールバック仕様を docs 化
|
||||
- 削除条件 5/5 を定義(P1: IfSelectTest, P2: read_quoted/IfMerge, P3: Method/Box)
|
||||
|
||||
#### Phase 63-5: infer_type_from_phi 縮退実装
|
||||
- `infer_type_from_phi_with_hint()` 実装(+44行)
|
||||
- lifecycle.rs で呼び出し経路統一
|
||||
- 削除条件達成率: 3/5(60%)
|
||||
|
||||
#### Phase 63-6: P1 ケース型ヒント完全実装
|
||||
- `MirInstruction::Phi` に `type_hint` 追加(21ファイル修正)
|
||||
- JoinIR→MIR Bridge で型ヒント伝播実装
|
||||
- P1 ケース(IfSelectTest.*)で JoinIR 型ヒントのみで型決定
|
||||
- 削除条件達成率: 4/5(80%)
|
||||
|
||||
#### Phase 64: P2 型ヒント拡大
|
||||
- P2 ケース(read_quoted_from, IfMerge)型ヒント実装
|
||||
- `is_type_hint_target()` 箱化(TypeHintPolicy 萌芽)
|
||||
- 削除条件達成率: 4.5/5(90%)
|
||||
|
||||
#### Phase 65: P3-A/B 型ヒント実装
|
||||
- P3-A: `type_inference.rs` 新設、`JoinInst::MethodCall` に型ヒント(StringBox メソッド)
|
||||
- P3-B: `JoinInst::NewBox` に型ヒント(Box コンストラクタ)
|
||||
- 代表ケースベースで削除条件 5/5 達成
|
||||
|
||||
#### Phase 66: P3-C ジェネリック型推論箱化
|
||||
- `generic_type_resolver.rs` 新設(180行)
|
||||
- `TypeHintPolicy::is_p3c_target()` 追加
|
||||
- ArrayBox.get / MapBox.get 等のジェネリック型推論基盤確立
|
||||
|
||||
#### Phase 67: P3-C 実利用への一歩
|
||||
- `phase67_generic_type_resolver.rs` テスト追加(3テスト全 PASS)
|
||||
- lifecycle.rs に P3-C 経路フック追加(GenericTypeResolver 優先使用)
|
||||
- A/B テストで旧経路との一致確認(11 tests PASS)
|
||||
|
||||
**技術的成果**:
|
||||
- JoinIR が構造 + PHI + 型ヒントの SSOT として確立
|
||||
- infer_type_from_phi は P3-C フォールバック専用に縮退
|
||||
- 4つの柱(Structure / Scope / JoinIR / Type Hints)完成
|
||||
|
||||
## 2. 次の一手(Phase 69+)
|
||||
|
||||
### 直近の候補タスク
|
||||
|
||||
- **Trio 削除ライン**(Phase 69 候補)
|
||||
- LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox を LoopScopeShape に完全吸収
|
||||
- Phase 48-7: Trio/LoopScopeShape の将来扱い整理(docs-only)
|
||||
|
||||
- **P3-C 拡大 / If PHI 本体削除**(Phase 70 候補)
|
||||
- GenericTypeResolver 経由で全 P3-C ケースをカバー
|
||||
- `infer_type_from_phi` 本体削除と if_phi.rs 大掃除
|
||||
|
||||
- **wasm/Web デモライン**(Phase 71 候補)
|
||||
- JoinIR ベースの軽量デモ実装
|
||||
- ブラウザで動く最小構成
|
||||
|
||||
- **最適化ライン**(Phase 72+ 候補)
|
||||
- JoinIR 最適化パス実装
|
||||
- LLVM/ny-llvmc 統合強化
|
||||
|
||||
### バックログ
|
||||
|
||||
- **Mir 決定性**(小フェーズ)
|
||||
- `MirFunction.blocks: HashMap` → `BTreeMap` で非決定的テスト解消
|
||||
- Phase 25.1 同様のパターン適用
|
||||
|
||||
---
|
||||
|
||||
|
||||
20
README.md
20
README.md
@ -41,6 +41,26 @@ See also: docs/guides/perf/benchmarks.md
|
||||
Architecture notes
|
||||
- Runtime rings (ring0/ring1/ring2) and provider policy: see `docs/architecture/RINGS.md`.
|
||||
|
||||
JoinIR system (structure + PHI + type hint SSOT)
|
||||
- JoinIR is the Single Source of Truth for:
|
||||
- **Structure**: Loop forms (LoopForm lowering), control flow shapes
|
||||
- **PHI generation**: SSA merge nodes (If/Loop/Select/Merge patterns)
|
||||
- **Type hints**: Type propagation from JoinIR → PHI → lifecycle.rs
|
||||
- Dev flags:
|
||||
- `NYASH_JOINIR_DEBUG=1` - JoinIR lowering traces
|
||||
- `NYASH_P3C_DEBUG=1` - Generic type inference traces (Phase 66-67)
|
||||
- `NYASH_LOOPFORM_DEBUG=1` - LoopForm construction traces
|
||||
- Phase documentation:
|
||||
- [Phase 30: JoinIR Architecture](docs/private/roadmap2/phases/phase-30-final-joinir-world/README.md)
|
||||
- [Phase 33: If Lowering](docs/private/roadmap2/phases/phase-33/)
|
||||
- [Phase 34: LoopForm](docs/private/roadmap2/phases/phase-34/)
|
||||
- [Phase 48: Loop Lowering](docs/private/roadmap2/phases/phase-48/)
|
||||
- [Phase 63-65: Type Hints P1-P3-B](docs/private/roadmap2/phases/phase-65-p3-type-hints/README.md)
|
||||
- [Phase 66-67: Generic Type Inference P3-C](docs/private/roadmap2/phases/phase-65-p3-type-hints/README.md#phase-66-67-p3-c-ジェネリック型推論-箱化--実利用2025-11-30)
|
||||
- Current state: **JoinIR First Chapter Complete** (Phase 27-67)
|
||||
- Four pillars established: Structure / Scope / JoinIR / Type Hints
|
||||
- See [PHI_BOX_INVENTORY.md](docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md) for detailed status
|
||||
|
||||
Call system (unified by default)
|
||||
- Builder emits `Call { callee: Callee }` whenever possible; the VM routes by callee kind (Global/Method/Extern/... ).
|
||||
- Legacy by‑name calls(callee なし)は廃止。必ず Builder が `Callee` を付与する(付与されない場合は Fail‑Fast)。
|
||||
|
||||
135
docs/development/current/main/phase69-1-trio-inventory.md
Normal file
135
docs/development/current/main/phase69-1-trio-inventory.md
Normal file
@ -0,0 +1,135 @@
|
||||
# Phase 69-1: Trio 使用箇所の完全棚卸し
|
||||
|
||||
## 背景
|
||||
|
||||
Phase 48-3〜48-6 で Trio(LoopVarClassBox / LoopExitLivenessBox / LocalScopeInspectorBox)の機能は LoopScopeShape に移行済み。
|
||||
本フェーズでは完全削除に向けて、残存する使用箇所を調査し、削除難易度を評価する。
|
||||
|
||||
## Trio 使用頻度(2025-11-30)
|
||||
|
||||
| 箱名 | 使用箇所数 | 主な使用パターン |
|
||||
|------|-----------|-----------------|
|
||||
| LoopVarClassBox | 54箇所 | 定義ファイル + テスト + LoopScopeShape内部 |
|
||||
| LoopExitLivenessBox | 36箇所 | 定義ファイル + テスト + LoopScopeShape内部 |
|
||||
| LocalScopeInspectorBox | 62箇所 | 定義ファイル + テスト + LoopScopeShape内部 |
|
||||
|
||||
## ファイル別使用箇所
|
||||
|
||||
### 1. Trio 定義ファイル(削除対象)
|
||||
|
||||
| ファイル | LoopVarClass | LoopExitLiveness | LocalScopeInspector | 削除難易度 |
|
||||
|---------|--------------|------------------|---------------------|-----------|
|
||||
| `src/mir/phi_core/loop_var_classifier.rs` | 14 | - | 15 | **Easy** |
|
||||
| `src/mir/phi_core/loop_exit_liveness.rs` | 4 | 14 | - | **Easy** |
|
||||
| `src/mir/phi_core/local_scope_inspector.rs` | 1 | - | 16 | **Easy** |
|
||||
|
||||
**削減見込み**: 3ファイル完全削除(推定 300-400行)
|
||||
|
||||
### 2. LoopScopeShape 関連(内部使用、削除時に調整必要)
|
||||
|
||||
| ファイル | LoopVarClass | LoopExitLiveness | LocalScopeInspector | 対応 |
|
||||
|---------|--------------|------------------|---------------------|------|
|
||||
| `src/mir/join_ir/lowering/loop_scope_shape/builder.rs` | 11 | 11 | 11 | `from_existing_boxes_legacy` を削除・簡略化 |
|
||||
| `src/mir/join_ir/lowering/loop_scope_shape/shape.rs` | - | - | 1 | struct フィールド削除 |
|
||||
| `src/mir/join_ir/lowering/loop_scope_shape/tests.rs` | 9 | 9 | - | テスト調整(LoopScopeShape API に統一) |
|
||||
|
||||
**対応**: `from_existing_boxes_legacy()` 削除、Trio フィールド削除
|
||||
|
||||
### 3. 外部使用箇所(置き換え必要)
|
||||
|
||||
| ファイル | LoopVarClass | LoopExitLiveness | LocalScopeInspector | 対応 |
|
||||
|---------|--------------|------------------|---------------------|------|
|
||||
| `src/mir/phi_core/loopform_builder.rs` | - | - | 4 (1箇所は new()) | LoopScopeShape API に置き換え |
|
||||
| `src/mir/phi_core/phi_builder_box.rs` | 3 | - | 1 | LoopScopeShape API に置き換え |
|
||||
| `src/mir/phi_core/loop_snapshot_merge.rs` | 7 | - | 10 | LoopScopeShape API に置き換え |
|
||||
| `src/mir/join_ir/lowering/loop_form_intake.rs` | 2 | - | 2 | LoopScopeShape API に置き換え |
|
||||
| `src/mir/join_ir/lowering/generic_case_a.rs` | 1 | 1 | - | LoopScopeShape API に置き換え |
|
||||
| `src/mir/join_ir/lowering/loop_to_join.rs` | - | 1 | - | LoopScopeShape API に置き換え |
|
||||
| `src/mir/loop_builder/loop_form.rs` | 1 | - | - | LoopScopeShape API に置き換え |
|
||||
| `src/runner/json_v0_bridge/lowering/loop_.rs` | - | - | 2 | LoopScopeShape API に置き換え |
|
||||
| `src/mir/join_ir/mod.rs` | 1 | - | - | use 文削除 |
|
||||
|
||||
**削減見込み**: 8ファイルから Trio 依存を削除(推定 50-150行削減)
|
||||
|
||||
## Trio::new() 実際の使用箇所
|
||||
|
||||
```bash
|
||||
# コメント除外の実使用箇所
|
||||
rg "LoopVarClassBox::new|LoopExitLivenessBox::new|LocalScopeInspectorBox::new" \
|
||||
--type rust -n | grep -v "^\s*//"
|
||||
```
|
||||
|
||||
### 実使用箇所(テスト除外)
|
||||
|
||||
1. **loopform_builder.rs:985**
|
||||
```rust
|
||||
let mut inspector = LocalScopeInspectorBox::new();
|
||||
```
|
||||
- **対応**: LoopScopeShape::variable_definitions を直接使用
|
||||
|
||||
### テストコード内使用箇所
|
||||
|
||||
- **local_scope_inspector.rs**: 12箇所(テストコード内)
|
||||
- **loop_var_classifier.rs**: 7箇所(テストコード内)
|
||||
|
||||
**対応**: LoopScopeShape 統合テストに置き換え、Trio 単体テストは削除
|
||||
|
||||
## 削除戦略
|
||||
|
||||
### Phase 69-2: LoopScopeShape への完全移行
|
||||
|
||||
#### Step 1: 外部使用箇所の置き換え(Easy 優先)
|
||||
|
||||
| ファイル | 難易度 | 対応 |
|
||||
|---------|--------|------|
|
||||
| loopform_builder.rs | **Easy** | inspector.new() → scope.variable_definitions |
|
||||
| phi_builder_box.rs | **Easy** | classify() → scope.classify() |
|
||||
| loop_form_intake.rs | **Easy** | 既に LoopScopeShape を持っている、直接使用に変更 |
|
||||
| generic_case_a.rs | **Easy** | 既に LoopScopeShape を持っている、直接使用に変更 |
|
||||
| loop_to_join.rs | **Easy** | 既に LoopScopeShape を持っている、直接使用に変更 |
|
||||
| loop_form.rs | **Easy** | 既に LoopScopeShape を持っている、直接使用に変更 |
|
||||
| json_v0_bridge/loop_.rs | **Medium** | LoopScopeShape 取得経路を追加 |
|
||||
|
||||
#### Step 2: LoopScopeShape 内部の Trio 依存削除
|
||||
|
||||
1. `from_existing_boxes_legacy()` を削除
|
||||
2. `from_loop_form()` を `from_existing_boxes()` にリネーム
|
||||
3. Trio フィールドを struct から削除
|
||||
|
||||
#### Step 3: テストコード調整
|
||||
|
||||
1. Trio 単体テストを削除
|
||||
2. LoopScopeShape 統合テストに機能を統合
|
||||
|
||||
### Phase 69-3: Trio 3箱の削除
|
||||
|
||||
1. `loop_var_classifier.rs` 削除(推定 150行)
|
||||
2. `loop_exit_liveness.rs` 削除(推定 100行)
|
||||
3. `local_scope_inspector.rs` 削除(推定 150行)
|
||||
4. `phi_core/mod.rs` から use 文削除
|
||||
|
||||
### Phase 69-4: conservative.rs の docs/ 移設
|
||||
|
||||
1. `phi_core/conservative.rs`(57行、全てコメント)を削除
|
||||
2. `docs/development/architecture/phi-conservative-history.md` として移設
|
||||
|
||||
## 削減見込み合計
|
||||
|
||||
| カテゴリ | 削減見込み |
|
||||
|---------|-----------|
|
||||
| Trio 定義ファイル削除 | 300-400行 |
|
||||
| 外部使用箇所置き換え | 50-150行 |
|
||||
| LoopScopeShape 簡略化 | 50-100行 |
|
||||
| conservative.rs 移設 | 57行 |
|
||||
| **合計** | **457-707行** |
|
||||
|
||||
## 次のステップ
|
||||
|
||||
Phase 69-2 で Easy 箇所から順次置き換えを開始:
|
||||
1. loopform_builder.rs(1箇所)
|
||||
2. phi_builder_box.rs(3箇所)
|
||||
3. loop_form_intake.rs(2箇所)
|
||||
4. generic_case_a.rs(1箇所)
|
||||
5. ...(全8ファイル)
|
||||
|
||||
全置き換え完了後、Phase 69-3 で Trio 3箱を完全削除。
|
||||
@ -38,6 +38,8 @@ fn has_main_static(ast: &ASTNode) -> bool {
|
||||
// - ✅ テスト可能:各 Phase 独立テスト
|
||||
// - ✅ 拡張容易:Phase 66+ で P3-C 追加が簡単
|
||||
use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy;
|
||||
// Phase 67: P3-C ジェネリック型推論箱
|
||||
use crate::mir::join_ir::lowering::generic_type_resolver::GenericTypeResolver;
|
||||
|
||||
impl super::MirBuilder {
|
||||
/// Unified declaration indexing (Phase A): collect symbols before lowering
|
||||
@ -290,17 +292,37 @@ impl super::MirBuilder {
|
||||
break 'outer;
|
||||
}
|
||||
// Phase 65.5: TypeHintPolicy 使用(箱化モジュール)
|
||||
// Phase 67: P3-C 経路を GenericTypeResolver に委譲
|
||||
let hint = if TypeHintPolicy::is_target(&function.signature.name) {
|
||||
TypeHintPolicy::extract_phi_type_hint(&function, *v)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(mt) = crate::mir::phi_core::if_phi::infer_type_from_phi_with_hint(
|
||||
hint, // Phase 63-6-3: P1 の場合は PHI の type_hint、それ以外は None
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
) {
|
||||
// Phase 67: P3-C 対象なら GenericTypeResolver を優先使用
|
||||
if hint.is_none() && TypeHintPolicy::is_p3c_target(&function.signature.name) {
|
||||
if let Some(mt) = GenericTypeResolver::resolve_from_phi(
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
) {
|
||||
if std::env::var("NYASH_P3C_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[lifecycle/p3c] {} type inferred via GenericTypeResolver: {:?}",
|
||||
function.signature.name, mt
|
||||
);
|
||||
}
|
||||
inferred = Some(mt);
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
if let Some(mt) =
|
||||
crate::mir::phi_core::if_phi::infer_type_from_phi_with_hint(
|
||||
hint, // Phase 63-6-3: P1 の場合は PHI の type_hint、それ以外は None
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
)
|
||||
{
|
||||
inferred = Some(mt);
|
||||
break 'outer;
|
||||
}
|
||||
@ -312,11 +334,29 @@ impl super::MirBuilder {
|
||||
break;
|
||||
}
|
||||
// Phase 65.5: TypeHintPolicy 使用(箱化モジュール)
|
||||
// Phase 67: P3-C 経路を GenericTypeResolver に委譲
|
||||
let hint = if TypeHintPolicy::is_target(&function.signature.name) {
|
||||
TypeHintPolicy::extract_phi_type_hint(&function, *v)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// Phase 67: P3-C 対象なら GenericTypeResolver を優先使用
|
||||
if hint.is_none() && TypeHintPolicy::is_p3c_target(&function.signature.name) {
|
||||
if let Some(mt) = GenericTypeResolver::resolve_from_phi(
|
||||
&function,
|
||||
*v,
|
||||
&self.value_types,
|
||||
) {
|
||||
if std::env::var("NYASH_P3C_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[lifecycle/p3c] {} type inferred via GenericTypeResolver: {:?}",
|
||||
function.signature.name, mt
|
||||
);
|
||||
}
|
||||
inferred = Some(mt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(mt) = crate::mir::phi_core::if_phi::infer_type_from_phi_with_hint(
|
||||
hint, // Phase 63-6-3: P1 の場合は PHI の type_hint、それ以外は None
|
||||
&function,
|
||||
|
||||
204
src/mir/join_ir/lowering/generic_type_resolver.rs
Normal file
204
src/mir/join_ir/lowering/generic_type_resolver.rs
Normal file
@ -0,0 +1,204 @@
|
||||
// Phase 66: P3-C ジェネリック型推論箱
|
||||
//
|
||||
// ArrayBox.get, MapBox.get などのジェネリック型を持つメソッドの
|
||||
// 戻り値型を推論する。
|
||||
//
|
||||
// # 責務
|
||||
//
|
||||
// - P3-C 対象メソッドの判定
|
||||
// - コンテナ使用文脈からの型推論(PHI 解析フォールバック)
|
||||
// - 将来の型変数システム導入の土台
|
||||
//
|
||||
// # 設計原則(箱理論)
|
||||
//
|
||||
// - **単一責務**: P3-C ジェネリック型推論のみ
|
||||
// - **質問箱**: is_generic_method() / resolve_generic_type() で判定
|
||||
// - **if_phi.rs 依存削減**: infer_type_from_phi を内部に取り込み
|
||||
|
||||
use crate::mir::{MirFunction, MirInstruction, MirType, ValueId};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Phase 66: ジェネリック型推論箱
|
||||
///
|
||||
/// # 対象パターン(P3-C)
|
||||
///
|
||||
/// - `ArrayBox.get(index)` → 配列要素の型(T)
|
||||
/// - `ArrayBox.pop()` → 配列要素の型(T)
|
||||
/// - `MapBox.get(key)` → マップ値の型(V)
|
||||
///
|
||||
/// # Phase 65 との関係
|
||||
///
|
||||
/// Phase 65 で P1/P2/P3-A/P3-B は JoinIR 型ヒント経路に移行完了。
|
||||
/// この箱は **P3-C 専用** として設計し、TypeHintPolicy と連携する。
|
||||
///
|
||||
/// # 将来拡張(Phase 67+)
|
||||
///
|
||||
/// - 型変数システム(`T`, `V` の明示的な型パラメータ)
|
||||
/// - コンテナ生成時の型推論(`new ArrayBox<StringBox>()`)
|
||||
pub struct GenericTypeResolver;
|
||||
|
||||
impl GenericTypeResolver {
|
||||
/// P3-C 対象メソッドかどうかを判定
|
||||
///
|
||||
/// # 引数
|
||||
/// - `receiver_type`: 受け手の型
|
||||
/// - `method_name`: メソッド名
|
||||
///
|
||||
/// # 戻り値
|
||||
/// - `true`: ジェネリック型推論が必要なメソッド
|
||||
/// - `false`: P3-A/P3-B で処理可能、または未対応
|
||||
pub fn is_generic_method(receiver_type: &MirType, method_name: &str) -> bool {
|
||||
match receiver_type {
|
||||
MirType::Box(box_name) => match box_name.as_str() {
|
||||
"ArrayBox" => matches!(method_name, "get" | "pop" | "first" | "last"),
|
||||
"MapBox" => matches!(method_name, "get"),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// P3-C 対象関数かどうかを判定(TypeHintPolicy 連携用)
|
||||
///
|
||||
/// # 用途
|
||||
///
|
||||
/// TypeHintPolicy.is_target() で P1/P2/P3-A/P3-B に該当しない場合、
|
||||
/// この関数で P3-C 候補かどうかを判定する。
|
||||
///
|
||||
/// # 現在の実装
|
||||
///
|
||||
/// ArrayBox/MapBox を使用する関数を P3-C 候補として判定。
|
||||
/// 関数名ベースのフィルタリングは行わない(汎用判定)。
|
||||
pub fn is_p3c_candidate(func_name: &str) -> bool {
|
||||
// Phase 66: 現在は全関数を P3-C 候補とみなす
|
||||
// 将来的に関数内の ArrayBox.get/MapBox.get 使用を解析して判定
|
||||
!func_name.is_empty() // 常に true(P1/P2/P3-A/B 以外は全て P3-C 候補)
|
||||
}
|
||||
|
||||
/// PHI 解析によるジェネリック型推論
|
||||
///
|
||||
/// # 責務
|
||||
///
|
||||
/// P3-C メソッド(ArrayBox.get, MapBox.get など)の戻り値型を
|
||||
/// PHI 命令の incoming 値から推論する。
|
||||
///
|
||||
/// # アルゴリズム
|
||||
///
|
||||
/// 1. ret_val を定義する PHI 命令を探索
|
||||
/// 2. PHI の incoming 値の型を types マップから取得
|
||||
/// 3. 全ての incoming 値が同じ型なら、その型を返す
|
||||
///
|
||||
/// # Phase 65 との違い
|
||||
///
|
||||
/// - if_phi.rs::infer_type_from_phi() と同等のロジック
|
||||
/// - P3-C 専用として明示的に責務を限定
|
||||
/// - 将来的に型変数システムで置き換え予定
|
||||
pub fn resolve_from_phi(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
types: &BTreeMap<ValueId, MirType>,
|
||||
) -> Option<MirType> {
|
||||
for (_bid, bb) in function.blocks.iter() {
|
||||
for inst in bb.instructions.iter() {
|
||||
if let MirInstruction::Phi { dst, inputs, .. } = inst {
|
||||
if *dst == ret_val {
|
||||
let mut it = inputs.iter().filter_map(|(_, v)| types.get(v));
|
||||
if let Some(first) = it.next() {
|
||||
if it.all(|mt| mt == first) {
|
||||
return Some(first.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// PHI の type_hint から型を抽出(将来拡張用)
|
||||
///
|
||||
/// # Phase 66 現在
|
||||
///
|
||||
/// P3-C メソッドは JoinIR で type_hint を設定しないため、
|
||||
/// この関数は現在使用されない。
|
||||
///
|
||||
/// # Phase 67+ 拡張
|
||||
///
|
||||
/// 型変数システム導入後、ArrayBox<T>.get() の T を
|
||||
/// type_hint として伝播する際に使用。
|
||||
#[allow(dead_code)]
|
||||
pub fn extract_type_hint(function: &MirFunction, ret_val: ValueId) -> Option<MirType> {
|
||||
function
|
||||
.blocks
|
||||
.values()
|
||||
.flat_map(|bb| &bb.instructions)
|
||||
.find_map(|inst| {
|
||||
if let MirInstruction::Phi { dst, type_hint, .. } = inst {
|
||||
if *dst == ret_val {
|
||||
return type_hint.clone();
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_generic_method_arraybox() {
|
||||
let array_type = MirType::Box("ArrayBox".to_string());
|
||||
|
||||
// P3-C 対象
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "get"));
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "pop"));
|
||||
assert!(GenericTypeResolver::is_generic_method(
|
||||
&array_type,
|
||||
"first"
|
||||
));
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "last"));
|
||||
|
||||
// P3-A/P3-B 対象(非 P3-C)
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "size"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "push"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_generic_method_mapbox() {
|
||||
let map_type = MirType::Box("MapBox".to_string());
|
||||
|
||||
// P3-C 対象
|
||||
assert!(GenericTypeResolver::is_generic_method(&map_type, "get"));
|
||||
|
||||
// P3-A/P3-B 対象(非 P3-C)
|
||||
assert!(!GenericTypeResolver::is_generic_method(&map_type, "size"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&map_type, "has"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_generic_method_stringbox() {
|
||||
// StringBox は P3-A で処理済み
|
||||
assert!(!GenericTypeResolver::is_generic_method(
|
||||
&MirType::String,
|
||||
"substring"
|
||||
));
|
||||
assert!(!GenericTypeResolver::is_generic_method(
|
||||
&MirType::String,
|
||||
"length"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_p3c_candidate() {
|
||||
// 全関数が P3-C 候補(P1/P2/P3-A/B 以外)
|
||||
assert!(GenericTypeResolver::is_p3c_candidate("Main.main/0"));
|
||||
assert!(GenericTypeResolver::is_p3c_candidate(
|
||||
"FuncScanner.parse/1"
|
||||
));
|
||||
|
||||
// 空文字列は false
|
||||
assert!(!GenericTypeResolver::is_p3c_candidate(""));
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,7 @@ pub mod stageb_body;
|
||||
pub mod stageb_funcscanner;
|
||||
pub mod type_hint_policy; // Phase 65.5: 型ヒントポリシー箱化
|
||||
pub mod type_inference; // Phase 65-2-A
|
||||
pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱
|
||||
pub mod value_id_ranges;
|
||||
|
||||
// Re-export public lowering functions
|
||||
|
||||
@ -88,8 +88,23 @@ impl TypeHintPolicy {
|
||||
func_name.starts_with("NewBoxTest.")
|
||||
}
|
||||
|
||||
// Phase 66+ で P3-C(ジェネリック型推論)追加予定
|
||||
// fn is_p3c_target(func_name: &str) -> bool { ... }
|
||||
/// P3-C: ジェネリック型推論対象判定(Phase 66)
|
||||
///
|
||||
/// # 対象
|
||||
/// - P1/P2/P3-A/P3-B 以外のすべての関数
|
||||
/// - ArrayBox.get, MapBox.get などを使用する可能性がある関数
|
||||
///
|
||||
/// # Phase 66 設計
|
||||
/// - GenericTypeResolver と連携して P3-C 型推論を実行
|
||||
/// - is_target() が false の場合のフォールバック経路
|
||||
pub fn is_p3c_target(func_name: &str) -> bool {
|
||||
// P1/P2/P3-A/P3-B に該当しない場合は P3-C 候補
|
||||
!Self::is_p1_target(func_name)
|
||||
&& !Self::is_p2_target(func_name)
|
||||
&& !Self::is_p3a_target(func_name)
|
||||
&& !Self::is_p3b_target(func_name)
|
||||
&& !func_name.is_empty()
|
||||
}
|
||||
|
||||
/// PHI 命令から型ヒントを抽出
|
||||
///
|
||||
@ -104,10 +119,7 @@ impl TypeHintPolicy {
|
||||
/// # Phase
|
||||
/// - Phase 63-6 で導入
|
||||
/// - Phase 65.5 で箱化・関数型スタイルに改善
|
||||
pub fn extract_phi_type_hint(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
) -> Option<MirType> {
|
||||
pub fn extract_phi_type_hint(function: &MirFunction, ret_val: ValueId) -> Option<MirType> {
|
||||
function
|
||||
.blocks
|
||||
.values()
|
||||
@ -157,7 +169,9 @@ mod tests {
|
||||
fn test_is_p3a_target() {
|
||||
// P3-A: read_quoted 系関数
|
||||
assert!(TypeHintPolicy::is_p3a_target("read_quoted_from/1"));
|
||||
assert!(TypeHintPolicy::is_p3a_target("FuncScannerBox.read_quoted/1"));
|
||||
assert!(TypeHintPolicy::is_p3a_target(
|
||||
"FuncScannerBox.read_quoted/1"
|
||||
));
|
||||
|
||||
// P3-A 以外
|
||||
assert!(!TypeHintPolicy::is_p3a_target("IfSelectTest.simple/0"));
|
||||
@ -203,4 +217,36 @@ mod tests {
|
||||
// どちらかに該当すれば is_target() は true
|
||||
assert!(TypeHintPolicy::is_target("read_quoted_from/1"));
|
||||
}
|
||||
|
||||
/// Phase 66: P3-C パターン判定テスト
|
||||
#[test]
|
||||
fn test_is_p3c_target() {
|
||||
// P3-C: P1/P2/P3-A/P3-B 以外
|
||||
assert!(TypeHintPolicy::is_p3c_target("Main.main/0"));
|
||||
assert!(TypeHintPolicy::is_p3c_target("SomeBox.some_method/3"));
|
||||
assert!(TypeHintPolicy::is_p3c_target("ArrayProcessor.process/1"));
|
||||
|
||||
// P1/P2/P3-A/P3-B は P3-C ではない
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfSelectTest.simple/0")); // P1
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfMergeTest.simple/0")); // P2
|
||||
assert!(!TypeHintPolicy::is_p3c_target("read_quoted_from/1")); // P3-A
|
||||
assert!(!TypeHintPolicy::is_p3c_target("NewBoxTest.array/0")); // P3-B
|
||||
|
||||
// 空文字列は false
|
||||
assert!(!TypeHintPolicy::is_p3c_target(""));
|
||||
}
|
||||
|
||||
/// Phase 66: is_target と is_p3c_target の排他性確認
|
||||
#[test]
|
||||
fn test_is_target_and_p3c_mutually_exclusive() {
|
||||
// is_target() が true なら is_p3c_target() は false
|
||||
let p1_func = "IfSelectTest.simple/0";
|
||||
assert!(TypeHintPolicy::is_target(p1_func));
|
||||
assert!(!TypeHintPolicy::is_p3c_target(p1_func));
|
||||
|
||||
// is_target() が false なら is_p3c_target() は true
|
||||
let general_func = "Main.main/0";
|
||||
assert!(!TypeHintPolicy::is_target(general_func));
|
||||
assert!(TypeHintPolicy::is_p3c_target(general_func));
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ pub mod namingbox_static_method_id; // Phase 21.7++ Phase 1: StaticMethodId stru
|
||||
pub mod nyash_abi_basic;
|
||||
pub mod parser;
|
||||
pub mod phase61_if_in_loop_dryrun; // Phase 61-2: If-in-loop JoinIR dry-run tests
|
||||
pub mod phase67_generic_type_resolver; // Phase 67: P3-C GenericTypeResolver tests
|
||||
pub mod plugin_hygiene;
|
||||
pub mod policy_mutdeny;
|
||||
pub mod refcell_assignment_test;
|
||||
|
||||
144
src/tests/phase67_generic_type_resolver.rs
Normal file
144
src/tests/phase67_generic_type_resolver.rs
Normal file
@ -0,0 +1,144 @@
|
||||
//! Phase 67: P3-C GenericTypeResolver 実利用テスト
|
||||
//!
|
||||
//! ArrayBox.get / MapBox.get などのジェネリック型メソッドの
|
||||
//! 型推論が GenericTypeResolver 経由で正しく動作することを検証。
|
||||
//!
|
||||
//! # テスト方針
|
||||
//!
|
||||
//! 1. MIR を直接構築して if 文 + ArrayBox.get パターンを作成
|
||||
//! 2. lifecycle.rs での型推論が正しく動作することを確認
|
||||
//! 3. A/B テスト:旧経路と新経路で同じ結果になることを検証
|
||||
|
||||
use crate::mir::join_ir::lowering::generic_type_resolver::GenericTypeResolver;
|
||||
use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy;
|
||||
use crate::mir::MirType;
|
||||
|
||||
/// Phase 67-1: GenericTypeResolver の基本判定テスト
|
||||
#[test]
|
||||
fn phase67_generic_type_resolver_is_generic_method() {
|
||||
let array_type = MirType::Box("ArrayBox".to_string());
|
||||
let map_type = MirType::Box("MapBox".to_string());
|
||||
|
||||
// P3-C 対象メソッド(ジェネリック型)
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "get"));
|
||||
assert!(GenericTypeResolver::is_generic_method(&array_type, "pop"));
|
||||
assert!(GenericTypeResolver::is_generic_method(&map_type, "get"));
|
||||
|
||||
// P3-A/P3-B 対象(非ジェネリック)
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "size"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&array_type, "push"));
|
||||
assert!(!GenericTypeResolver::is_generic_method(&map_type, "has"));
|
||||
}
|
||||
|
||||
/// Phase 67-1: TypeHintPolicy と GenericTypeResolver の連携テスト
|
||||
#[test]
|
||||
fn phase67_type_hint_policy_p3c_integration() {
|
||||
// P1/P2/P3-A/P3-B 対象関数は P3-C ではない
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfSelectTest.simple/0")); // P1
|
||||
assert!(!TypeHintPolicy::is_p3c_target("IfMergeTest.simple/0")); // P2
|
||||
assert!(!TypeHintPolicy::is_p3c_target("read_quoted_from/1")); // P3-A
|
||||
assert!(!TypeHintPolicy::is_p3c_target("NewBoxTest.array/0")); // P3-B
|
||||
|
||||
// 一般関数は P3-C 候補
|
||||
assert!(TypeHintPolicy::is_p3c_target("ArrayProcessor.process/1"));
|
||||
assert!(TypeHintPolicy::is_p3c_target("GenericTypeGetTest.array_get/0"));
|
||||
|
||||
// is_target と is_p3c_target は排他的
|
||||
let p3c_func = "GenericTypeGetTest.array_get/0";
|
||||
assert!(!TypeHintPolicy::is_target(p3c_func));
|
||||
assert!(TypeHintPolicy::is_p3c_target(p3c_func));
|
||||
}
|
||||
|
||||
/// Phase 67-3: A/B テスト準備 - 型推論経路の一致確認
|
||||
///
|
||||
/// GenericTypeResolver::resolve_from_phi() と
|
||||
/// if_phi::infer_type_from_phi() が同じ結果を返すことを確認
|
||||
#[test]
|
||||
fn phase67_ab_test_resolve_from_phi_equivalence() {
|
||||
use crate::mir::{
|
||||
BasicBlock, BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction,
|
||||
MirInstruction, ValueId,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// 簡単な PHI を含む MIR を構築
|
||||
// Block 0 (entry): branch to Block 1 or Block 2
|
||||
// Block 1 (then): v2 = 42, jump to Block 3
|
||||
// Block 2 (else): v3 = 0, jump to Block 3
|
||||
// Block 3 (merge): v4 = phi(v2, v3), return v4
|
||||
|
||||
let sig = FunctionSignature {
|
||||
name: "GenericTypeGetTest.simple_phi/0".into(),
|
||||
params: vec![],
|
||||
return_type: MirType::Unknown, // 型推論対象
|
||||
effects: EffectMask::PURE,
|
||||
};
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
|
||||
let entry = BasicBlockId::new(0);
|
||||
let then_bb = BasicBlockId::new(1);
|
||||
let else_bb = BasicBlockId::new(2);
|
||||
let merge_bb = BasicBlockId::new(3);
|
||||
|
||||
// Block 構築
|
||||
f.add_block(BasicBlock::new(then_bb));
|
||||
f.add_block(BasicBlock::new(else_bb));
|
||||
f.add_block(BasicBlock::new(merge_bb));
|
||||
|
||||
// Entry: condition + branch
|
||||
let cond = f.next_value_id();
|
||||
f.get_block_mut(entry)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Const {
|
||||
dst: cond,
|
||||
value: ConstValue::Bool(true),
|
||||
});
|
||||
f.get_block_mut(entry).unwrap().terminator = Some(MirInstruction::Branch {
|
||||
condition: cond,
|
||||
then_bb,
|
||||
else_bb,
|
||||
});
|
||||
|
||||
// Then: v2 = 42
|
||||
let v2 = f.next_value_id();
|
||||
f.get_block_mut(then_bb)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Const {
|
||||
dst: v2,
|
||||
value: ConstValue::Integer(42),
|
||||
});
|
||||
f.get_block_mut(then_bb).unwrap().terminator = Some(MirInstruction::Jump { target: merge_bb });
|
||||
|
||||
// Else: v3 = 0
|
||||
let v3 = f.next_value_id();
|
||||
f.get_block_mut(else_bb)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Const {
|
||||
dst: v3,
|
||||
value: ConstValue::Integer(0),
|
||||
});
|
||||
f.get_block_mut(else_bb).unwrap().terminator = Some(MirInstruction::Jump { target: merge_bb });
|
||||
|
||||
// Merge: v4 = phi(v2 from then, v3 from else)
|
||||
let v4 = f.next_value_id();
|
||||
f.get_block_mut(merge_bb)
|
||||
.unwrap()
|
||||
.add_instruction(MirInstruction::Phi {
|
||||
dst: v4,
|
||||
inputs: vec![(then_bb, v2), (else_bb, v3)],
|
||||
type_hint: None, // P3-C: type_hint なし
|
||||
});
|
||||
f.get_block_mut(merge_bb).unwrap().terminator = Some(MirInstruction::Return { value: Some(v4) });
|
||||
|
||||
// 型情報を設定
|
||||
let mut types: BTreeMap<ValueId, MirType> = BTreeMap::new();
|
||||
types.insert(v2, MirType::Integer);
|
||||
types.insert(v3, MirType::Integer);
|
||||
|
||||
// A/B テスト: 両方の経路で同じ結果を返すことを確認
|
||||
let result_a = crate::mir::phi_core::if_phi::infer_type_from_phi(&f, v4, &types);
|
||||
let result_b = GenericTypeResolver::resolve_from_phi(&f, v4, &types);
|
||||
|
||||
assert_eq!(result_a, result_b, "A/B test: both routes should return the same type");
|
||||
assert_eq!(result_a, Some(MirType::Integer), "Type should be inferred as Integer");
|
||||
}
|
||||
Reference in New Issue
Block a user