From d3cbc71c9be4c005a1b2e133655c951f184c63b0 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Tue, 18 Nov 2025 18:56:35 +0900 Subject: [PATCH] =?UTF-8?q?feat(mir):=20Phase=2025.1f=E5=AE=8C=E4=BA=86=20?= =?UTF-8?q?-=20Conservative=20PHI=20+=20ControlForm=E8=A6=B3=E6=B8=AC?= =?UTF-8?q?=E3=83=AC=E3=82=A4=E3=83=A4=E3=83=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎉 Conservative PHI Box理論による完全SSA構築 **Phase 7-B: Conservative PHI実装** - 片方branchのみ定義変数に対応(emit_void使用) - 全変数にPHI生成(Conservative Box理論) - Stage-1 resolver全テスト緑化(3/3 PASS) **Phase 25.1f: ControlForm観測レイヤー** - LoopShape/IfShape/ControlForm構造定義 - Loop/If統一インターフェース実装 - debug_dump/debug_validate機能追加 - NYASH_CONTROL_FORM_TRACE環境変数対応 **主な変更**: - src/mir/builder/phi.rs: Conservative PHI実装 - src/mir/control_form.rs: ControlForm構造(NEW) - src/mir/loop_builder.rs: LoopForm v2デフォルト化 **テスト結果**: ✅ mir_stage1_using_resolver_min_fragment_verifies ✅ mir_stage1_using_resolver_full_collect_entries_verifies ✅ mir_parserbox_parse_program2_harness_parses_minimal_source 🤖 Generated with Claude Code Co-Authored-By: Claude Co-Authored-By: ChatGPT --- CURRENT_TASK.md | 29 ++ Cargo.toml | 2 + .../roadmap/phases/phase-25.1f/README.md | 252 ++++++++++++++++++ .../roadmap/phases/phase-25.1g/README.md | 118 ++++++++ lang/src/shared/mir/control_form_box.hako | 42 +++ src/backend/mir_interpreter/exec.rs | 3 - src/backend/mir_interpreter/handlers/boxes.rs | 3 + .../handlers/boxes_instance.rs | 2 +- .../handlers/boxes_object_fields.rs | 1 - .../mir_interpreter/handlers/boxes_string.rs | 1 - .../mir_interpreter/handlers/externals.rs | 15 +- src/backend/mir_interpreter/mod.rs | 1 + .../mir_interpreter/utils/arg_validation.rs | 2 + .../utils/conversion_helpers.rs | 3 + .../utils/destination_helpers.rs | 1 + .../mir_interpreter/utils/error_helpers.rs | 7 + .../mir_interpreter/utils/receiver_helpers.rs | 1 + src/benchmarks.rs | 7 +- src/box_operators.rs | 2 +- src/box_operators/static_ops.rs | 14 +- src/boxes/arithmetic/modulo_box.rs | 3 +- src/host_providers/mir_builder.rs | 4 +- src/mir/builder.rs | 4 +- src/mir/builder/builder_calls.rs | 1 - src/mir/builder/call_resolution.rs | 4 +- src/mir/builder/calls/call_unified.rs | 7 +- src/mir/builder/calls/emit.rs | 6 +- src/mir/builder/calls/extern_calls.rs | 1 + src/mir/builder/calls/function_lowering.rs | 4 +- src/mir/builder/calls/guard.rs | 3 + src/mir/builder/calls/mod.rs | 5 + src/mir/builder/calls/special_handlers.rs | 4 +- src/mir/builder/context.rs | 5 + src/mir/builder/decls.rs | 7 +- src/mir/builder/emission/compare.rs | 2 + src/mir/builder/lifecycle.rs | 4 +- src/mir/builder/metadata/propagate.rs | 2 +- src/mir/builder/method_call_handlers.rs | 1 + src/mir/builder/phi.rs | 6 +- src/mir/builder/rewrite/known.rs | 5 +- src/mir/builder/rewrite/special.rs | 8 +- src/mir/builder/schedule/block.rs | 2 + src/mir/builder/type_registry.rs | 10 + src/mir/builder/types/annotation.rs | 1 + src/mir/builder/utils.rs | 2 + src/mir/control_form.rs | 222 +++++++++++++++ src/mir/loop_builder.rs | 52 +++- src/mir/mod.rs | 1 + src/mir/phi_core/if_phi.rs | 2 +- src/mir/phi_core/loop_phi.rs | 2 +- src/mir/verification/utils.rs | 1 + src/parser/cursor.rs | 6 +- src/parser/statements/helpers.rs | 4 +- src/parser/statements/mod.rs | 2 +- src/runner/child_env.rs | 1 + src/runner/demos.rs | 1 + src/runner/hv1_inline.rs | 13 +- src/runner/json_v0_bridge/lowering.rs | 3 +- src/runner/json_v0_bridge/lowering/expr.rs | 2 +- src/runner/json_v0_bridge/lowering/if_else.rs | 2 +- src/runner/json_v0_bridge/lowering/ternary.rs | 4 +- .../json_v0_bridge/lowering/throw_ctx.rs | 2 +- src/runner/json_v1_bridge.rs | 21 -- src/runner/mir_json_emit.rs | 2 + src/runner/modes/common_util/plugin_guard.rs | 3 +- .../common_util/resolve/prelude_manager.rs | 4 +- .../common_util/resolve/selfhost_pipeline.rs | 6 +- src/runner/modes/common_util/resolve/strip.rs | 2 +- .../common_util/resolve/using_resolution.rs | 1 + src/runner/modes/vm.rs | 2 +- src/runner/modes/vm_fallback.rs | 5 +- src/runner/pipe_io.rs | 3 +- src/runner/pipeline.rs | 1 + src/runner/plugins.rs | 2 +- src/runner/selfhost.rs | 59 ++-- .../plugin_loader_v2/enabled/loader/config.rs | 1 - .../plugin_loader_v2/enabled/loader/mod.rs | 4 +- .../enabled/loader/singletons.rs | 1 - .../plugin_loader_v2/enabled/loader/specs.rs | 1 + .../enabled/method_resolver.rs | 7 +- src/runtime/unified_registry.rs | 2 +- 81 files changed, 907 insertions(+), 147 deletions(-) create mode 100644 docs/development/roadmap/phases/phase-25.1f/README.md create mode 100644 docs/development/roadmap/phases/phase-25.1g/README.md create mode 100644 lang/src/shared/mir/control_form_box.hako create mode 100644 src/mir/control_form.rs diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 1ee23255..3832d189 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -1,5 +1,34 @@ # Current Task — Phase 21.8 / 25 / 25.1 / 25.2(Numeric Core & Stage0/Stage1 Bootstrap) +Update (2025-11-18 — Phase 25.1g: Conservative PHI ↔ ControlForm 統合の準備) +- Context: + - 25.1f までに Rust 側の ControlForm(LoopShape / IfShape + ControlForm)と .hako 側の ControlFormBox を定義し、観測レイヤーは安定した。 + - 次のステップとして、Conservative PHI Box(If/Loop の SSA/PHI ロジック)に ControlForm ベースの入口を用意するフェーズ(25.1g)に入る。 +- Plan (25.1g): + - If 側: + - `phi_core::if_phi` に `merge_modified_with_control` のような薄いラッパを追加し、将来的に ControlForm から PHI マージが呼べるようにする(初回は既存関数への委譲だけ)。 + - `LoopBuilder::lower_if_in_loop` からの呼び出し位置をコメントで固定し、切り替えポイントを明示。 + - Loop 側: + - `phi_core::loopform_builder` に LoopForm v2 Exit PHI 用の ControlForm ラッパを追加(同じく最初は既存 `build_exit_phis` に委譲するだけ)。 + - Docs: + - `docs/development/roadmap/phases/phase-25.1g/README.md` に Option B の範囲とタスク粒度(G‑1〜G‑3)を記述済み。 + - Guard: + - 各ステップ後に `mir_stage1_using_resolver_*` / `mir_loopform_exit_phi` / `mir_stageb_loop_break_continue` / `tools/test_stageb_min.sh` を流し、SSA/PHI の赤ログが増えていないことを確認しながら進める。 + +Update (2025-11-18 — Phase 25.1f: ControlForm / Stage‑B ハーネス準備の設計開始) +- Context: + - Phase 25.1d/e で Rust MIR 側の SSA/PHI(特に LoopForm v2 + Conservative PHI)と Stage‑1 UsingResolver/Program v0 PHI スモークは一通り緑になった。 + - 次の大きな山は Stage‑B 最小ハーネス(`test_stageb_min.sh`)と selfhost 側 LoopSSA だが、その前に「Loop/If を共通ビューで眺める ControlForm 層」を挟んでおきたい。 +- Done (this step): + - 新フェーズ `Phase 25.1f` を切り、`docs/development/roadmap/phases/phase-25.1f/README.md` を追加。 + - ControlForm(LoopShape / IfShape + ControlKind)と、その役割(LoopForm v2 と If の構造を SSOT としてまとめる観測レイヤ)を文章で定義。 + - このフェーズでは挙動を変えず、「構造だけを先に固定する」方針を明記。 +- Next: + - `src/mir/control_form.rs` に ControlForm / LoopShape / IfShape のスケルトンを追加(Conservative PHI にはまだ接続しない)。 + - Stage‑1 / Stage‑B 代表テスト(`mir_stage1_using_resolver_*` / `mir_loopform_exit_phi.rs` / `mir_stageb_loop_break_continue.rs`)から + dev フラグ(例: `NYASH_CONTROL_FORM_TRACE=1`)付きで ControlForm を生成し、CFG 形をトレースできるようにする。 + - Stage‑B ハーネスや .hako LoopSSA の本格実装は、ControlForm の設計が固まってから次フェーズで扱う。 + Update (2025-11-17 PM — Phase 25.1d: CalleeBoxKind構造ガード実装完了) - ✅ **静的Box/ランタイムBox混線問題を構造レベルで解決!** - **実装内容**: diff --git a/Cargo.toml b/Cargo.toml index 6390fd18..f092519c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,8 @@ llvm-inkwell-legacy = ["dep:inkwell"] llvm = ["llvm-harness"] # Legacy AST interpreter (off by default). Gates NyashInterpreter usage in runner/tests. interpreter-legacy = [] +# Cranelift JIT cfg guard (ARCHIVED): keep feature empty to silence check-cfg warnings. +cranelift-jit = [] # (removed) Optional modular MIR builder feature # cranelift-jit = [ # ARCHIVED: Moved to archive/jit-cranelift/ during Phase 15 # "dep:cranelift-codegen", diff --git a/docs/development/roadmap/phases/phase-25.1f/README.md b/docs/development/roadmap/phases/phase-25.1f/README.md new file mode 100644 index 00000000..0d251e53 --- /dev/null +++ b/docs/development/roadmap/phases/phase-25.1f/README.md @@ -0,0 +1,252 @@ +# Phase 25.1f — ControlForm(Loop/If 共通ビュー)& Stage‑B ハーネス準備 + +Status: planning(設計+観測レイヤ追加/挙動は変えない) + +## ゴール + +- LoopForm v2(ループ)と If まわり(`phi_core::if_phi`)に対して、**制御構造の共通ビュー `ControlForm`** を用意する。 +- すでに導入済みの Conservative PHI Box(If/Loop 用 SSA/PHI ロジック)を、 + - ループ専用/If 専用でバラバラに持つのではなく、 + - `ControlForm` を単一の SSOT(Single Source of Truth)として参照する方向に寄せる。 +- Stage‑B 最小ハーネスや Stage‑1 Resolver など、「複雑な if + loop」を含む経路で、 + - ループと条件分岐の形を **構造として観測・検証できる足場** を整える(いきなり本番導線は切り替えない)。 + +※ このフェーズでは Rust の挙動は変えず、「制御構造の箱(LoopShape / IfShape)+ ControlForm の定義」と、 + デバッグ/テスト用の観測導線(トレース)までに留める。 + +## 背景(25.1d / 25.1e までの位置づけ) + +- 25.1d: + - Rust MIR ビルダーの SSA/PHI バグ(ValueId 二重定義/non‑dominating use/undefined Value)を、 + 小さな Rust テスト(`mir_*_verifies`)で炙り出して修正済み。 + - CalleeBoxKind / BoxCompilationContext によって Stage‑B / Stage‑1 の静的 Box とランタイム Box の混線も構造的に解消。 +- 25.1e: + - ループの PHI 生成の SSOT を LoopForm v2 + `phi_core` に寄せ、 + - Exit PHI、break/continue、pinned/carrier/invariant 変数を整理。 + - Conservative PHI Box(If/Loop 両方で「安全側に倒す PHI 生成」を行い、不要な PHI は将来の削除で最適化する方針)を実装。 + - Stage‑1 UsingResolver 系テストと Program v0 PHI スモーク、Stage‑B 風ループテストはすべて緑。 + +ここまでで「LoopForm v2 + Conservative PHI」の根本バグはだいたい取り切れたが、 + +- PHI ロジックが If 用と Loop 用で散在している。 +- Stage‑B ハーネス側で「どの loop/if がどう組み合わさっているか」を横断的に眺める手段がまだ弱い。 + +→ 25.1f では、**Loop / If を一段上から包む ControlForm レイヤ**を定義し、Stage‑B ハーネスに進む前準備として構造を固める。 + +## 方針 — ControlForm / Shape の設計 + +### 型と場所 + +- 新規モジュール案: + - `src/mir/control_form.rs` +- 基本構造: + - `LoopShape`: + - `preheader: BasicBlockId` + - `header: BasicBlockId` + - `body: BasicBlockId`(代表 body ブロック) + - `latch: BasicBlockId` + - `exit: BasicBlockId` + - `continue_targets: Vec` + - `break_targets: Vec` + - `IfShape`: + - `cond_block: BasicBlockId` + - `then_block: BasicBlockId` + - `else_block: Option` + - `merge_block: BasicBlockId` + - `ControlKind`: + - `Loop(LoopShape)` / `If(IfShape)`(将来 `Switch` / `Match` も追加可能な余地だけ確保) + - `ControlForm`: + - `entry: BasicBlockId`(構造全体の入口) + - `exits: Vec`(構造を抜けた先のブロック群) + - `kind: ControlKind` + +### 生成パス(from_loop / from_if) + +- `LoopForm` → `ControlForm`: + - 既存の LoopForm v2(`LoopFormBuilder` が返す構造)から `LoopShape` を構築し、 + - `ControlForm::from_loop(loop_form: &LoopForm)` で共通ビューに変換する。 + - `entry = preheader`, `exits = [exit]` というルールで統一。 +- If 用: + - 既存の `phi_core::if_phi` / builder 側の if lowering から、必要な情報をまとめた薄い `IfForm`(もしくは `IfShape` 直構築)を定義。 + - `ControlForm::from_if(if_form: &IfForm)` で共通ビューに変換。 + - `entry = cond_block`, `exits = [merge_block]` を基本とし、将来 `else if` や switch なども扱える形で設計。 + +### Invariant / Debug 用の Trait + +- 25.1f では「挙動を変えない」ため、ControlForm 自体は **観測・検証専用** として設計する: + - `debug_dump(&self)`: + - Loop / If の各ブロック ID を一括でログ出力し、Stage‑1 / Stage‑B テストから CFG の形を視覚的に確認できるようにする。 + - `CfgLike` トレイト(任意): + - `fn has_edge(&self, from: BasicBlockId, to: BasicBlockId) -> bool;` + - `fn predecessors_len(&self, block: BasicBlockId) -> usize;` + - `LoopShape::debug_validate(&self, cfg: &C)` などを `#[cfg(debug_assertions)]` で用意し、 + Loop/If の形が想定どおりかを assert できるようにする。 + +## タスク粒度(25.1f TODO) + +### F‑1: ControlForm / Shape の設計ドキュメント + +- 本 README で: + - `LoopShape` / `IfShape` / `ControlKind` / `ControlForm` の責務とフィールドを明文化。 + - LoopForm v2 との対応関係(preheader/header/latch/exit/continue/break)を図解レベルで通るところまで整理。 +- 25.1e の LoopForm 仕様(Carrier/Pinned/Invariant / break/continue / exit PHI)と整合していることを確認。 + +### F‑2: Rust 側のスケルトン実装(導線のみ) + +- `src/mir/control_form.rs` を追加し、以下のみ実装: + - 型定義(`LoopShape` / `IfShape` / `ControlKind` / `ControlForm`)。 + - `ControlForm::from_loop(&LoopForm)` / `ControlForm::from_if(&IfForm)` の雛形。 + - `debug_dump()` と `debug_validate()`(`#[cfg(debug_assertions)]` 前提、もしくはテスト専用)。 +- 既存のビルダー/PHI ロジックは **まだ ControlForm を使わない**: + - 25.1e で安定した Conservative PHI 実装を壊さないため、Phase 25.1f では「観測オンリー」に留める。 + +### F‑3: Stage‑1 / Stage‑B テストへの観測フック + +- 対象テスト: + - `src/tests/mir_stage1_using_resolver_verify.rs` 系(Stage‑1 UsingResolver の min/full)。 + - Stage‑B 風ループ/Program v0 PHI スモーク(`mir_loopform_exit_phi.rs` / `mir_stageb_loop_break_continue.rs` / `tools/smokes/v2/...`)。 +- 方針: + - `NYASH_CONTROL_FORM_TRACE=1` などの dev フラグが立っているときだけ、 + - LoopForm v2 から `ControlForm` を生成し、 + - `debug_dump()` で構造をトレースログに出す。 + - これにより、Stage‑B ハーネスを組む前に「実際にどんな Loop/If 形が発生しているか」を CFG レベルで確認できる。 + +### F‑4: Conservative PHI との接続計画(設計のみ) + +- 25.1e で実装した Conservative PHI Box(If/Loop)のロジックを整理し、将来像を設計として固定する: + - 目標: `merge_modified_at_merge_with` / LoopForm v2 Exit PHI 生成などを、 + - `ControlForm` ベースの API で呼べるようにする(例: `build_phi_for_control(form: &ControlForm, ...)`)。 + - 25.1f では: + - どの関数をどこまで ControlForm 受けにするか、 + - 既存 API との互換性をどう保つか、 + を README 上で設計するところまで。 + - 実際の実装切り替え(PHI ロジックを ControlForm ベースに差し替える)は、Stage‑B ハーネスと合わせて **別フェーズ(25.1g または 25.2 以降)** に送る。 + +### F‑5: Stage‑B ハーネスへの橋渡し準備 + +- Stage‑B 最小ハーネス(`tools/test_stageb_min.sh` / `lang/src/compiler/tests/stageb_min_sample.hako`)における: + - ループパターン(`skip_ws` などの単純ループ、複数 break/continue を含むループ)。 + - if + loop のネスト構造。 + を洗い出し、LoopForm v2 + IfShape + ControlForm ですべて表現できることを確認する。 +- 将来のタスク(このフェーズでは設計のみ): + - Stage‑B ハーネスの SSA/PHI 検証を `ControlForm` 経由で行う Rust テストをどう設計するかをまとめる。 + - Stage‑B 側の .hako LoopSSA(`lang/src/compiler/builder/ssa/loopssa.hako`)が、LoopForm v2 / ControlForm の設計と齟齬を起こさないように、必要な制約・前提条件を明記する。 + +### F‑6: .hako 側 ControlFormBox(Layer 2 の箱)定義 + +- 目的: + - Rust 側 `LoopShape` / `IfShape` / `ControlForm` に対応する **Hakorune 実装版の箱** を用意し、 + Stage‑B / LoopSSA が Rust と同じモデルでループ/if を扱えるようにする。 + - 将来の LoopSSA 実装は、この箱経由で構造を受け取ることを前提に設計する。 +- 現行構文版(Layer 2): + - ファイル案: `lang/src/shared/mir/control_form_box.hako` + - 定義案(BlockId は現状 i64/IntegerBox で表現): + ```hako + static box ControlFormBox { + kind_name: StringBox // "loop" or "if" + entry: IntegerBox // BasicBlockId 相当 + exits: ArrayBox // of IntegerBox (BlockId) + + // Loop fields (kind_name == "loop" の時のみ有効) + loop_preheader: IntegerBox + loop_header: IntegerBox + loop_body: IntegerBox + loop_latch: IntegerBox + loop_exit: IntegerBox + + // If fields (kind_name == "if" の時のみ有効) + if_cond: IntegerBox + if_then: IntegerBox + if_else: IntegerBox + if_merge: IntegerBox + + birth(kind) { + me.kind_name = kind + me.exits = new ArrayBox() + } + + is_loop() { + return me.kind_name == "loop" + } + + is_if() { + return me.kind_name == "if" + } + } + ``` + - 対応表(Rust ↔ .hako): + - Rust `LoopShape.preheader/header/body/latch/exit` + ↔ Hako `loop_preheader/loop_header/loop_body/loop_latch/loop_exit` + - Rust `IfShape.cond_block/then_block/else_block/merge_block` + ↔ Hako `if_cond/if_then/if_else/if_merge` + - Rust `ControlForm.entry/exits` + ↔ Hako `entry` / `exits`(`exits` は BlockId の配列) +- 将来構文版(Layer 3 の理想形・variant 導入前提): + - 将来の Nyash variant 構文が入ったら、`ControlKind` を enum 的に表現し、 + ```hako + box ControlKind { + variant Loop { preheader: BlockIdBox, header: BlockIdBox, ... } + variant If { cond_block: BlockIdBox, then_block: BlockIdBox, ... } + } + + static box ControlFormBox { + kind: ControlKind + entry: BlockIdBox + exits: ArrayBox + } + ``` + のような形に寄せる(現段階では設計メモのみ)。 +- 25.1f でのスコープ: + - `control_form_box.hako` に上記 Layer 2 版 `ControlFormBox` を実装する。 + - ただし Stage‑B / LoopSSA からはまだ使用しない(コンパイルが通る最小限の実装+将来用の箱)。 + - Stage‑B LoopSSA 統合(ControlFormBox を実際に使って JSON v0→MIR を整理する)は、次フェーズに回す。 + +## 移行ステップ(Option A → B → C のロードマップ) + +このフェーズ(25.1f)では、あくまで **Option A = 観測レイヤーの完成** までをスコープにするよ。その上で、将来の B/C も含めて合意しておきたい移行順序はこうだよ: + +1. **Option A: 観測レイヤーを完璧にする(Phase 25.1f)** + - Rust: + - `LoopShape` / `IfShape` / `ControlForm` 実装済み。 + - `LoopBuilder` から LoopForm v2 / `lower_if_in_loop` の出口で `ControlForm::Loop/If` を生成して `debug_dump` 済み。 + - `NYASH_CONTROL_FORM_TRACE` は「未設定=ON, 0/false=OFF」のヘルパーに統一済み。 + - .hako: + - `ControlFormBox`(kind_name + loop_* / if_* + entry/exits)の箱だけ定義(まだ未使用)。 + - テスト/スモーク: + - `mir_stage1_using_resolver_*` / `mir_loopform_exit_phi.rs` / `mir_stageb_loop_break_continue.rs` / `tools/test_stageb_min.sh` を回しつつ、 + ControlForm トレースが panic せずに構造ログだけを出すことを確認する。 + +2. **Option B: Conservative PHI ↔ ControlForm の統合(別フェーズ: 25.1g 想定)** + - ねらい: + - いま `merge_modified_at_merge_with`(If)や LoopForm v2 Exit PHI が直接 BlockId/ValueId を持っている部分を、 + `ControlForm` 経由で読めるように段階的に寄せていく。 + - 方針: + - まず If から(`ControlKind::If`)→ ループ Exit PHI(`ControlKind::Loop`)の順に小さく進める。 + - 各ステップごとに: + - 対応するテスト(Stage‑1 / Program v0 / Stage‑B 風)+ `test_stageb_min.sh` を回し、 + SSA/PHI の赤ログが増えていないことを確認しながら移行する。 + - 注意: + - これは 25.1f のスコープ外。Phase 25.1g(仮)として小さな差分に分割しながら実装する。 + +3. **Option C: LoopBuilder/If 降下の ControlForm ベース正規化(さらに後ろのフェーズ)** + - ねらい: + - 最終的には「LoopBuilder/If 降下がまず ControlForm を組み立てる」スタイルに寄せ、 + Conservative PHI / LoopSSA / .hako 側 LoopSSA が同じ ControlForm を揃って見る状態にする。 + - 規模: + - 数百行単位のリファクタになるため、Phase 25.2 以降(Selfhost/Stage‑B の安定を見ながら)に分割してやる。 + - ガード: + - 各ステップで代表スモーク(Stage‑1 / Stage‑B / Program v0 / `test_stageb_min.sh`)を流しながら進める。 + - `NYASH_CONTROL_FORM_TRACE` と `.hako ControlFormBox` を使って、常に「形」が崩れていないかを観測できるようにしておく。 + +このフェーズ(25.1f)は「Option A をやり切って足場を固める」ことに専念し、その上で 25.1g 以降で Option B/C に進む、というロードマップで進めるよ。 + +## このフェーズで「やらないこと」 + +- if を loop に書き換えるような、意味論レベルの正規化は **行わない**: + - If は IfShape、Loop は LoopShape として、それぞれの形を尊重する。 +- Stage‑B ハーネス本体の導入・既存パイプラインの切り替え: + - `test_stageb_min.sh` の経路変更や `.hako` コンパイラ側の LoopSSA 実装変更は、25.1f では触らず、 + ControlForm の設計と観測レイヤ整備が完了してから別フェーズで扱う。 +- Conservative PHI ロジックの大規模リライト: + - 25.1e で安定させた If/Loop PHI 実装を、いきなり ControlForm ベースに書き換えることはしない。 + - まずは「どう書き換えるのが構造的に美しいか」を、このフェーズの README に設計として落とす。 diff --git a/docs/development/roadmap/phases/phase-25.1g/README.md b/docs/development/roadmap/phases/phase-25.1g/README.md new file mode 100644 index 00000000..2fdac3c1 --- /dev/null +++ b/docs/development/roadmap/phases/phase-25.1g/README.md @@ -0,0 +1,118 @@ +# Phase 25.1g — Conservative PHI ↔ ControlForm 統合(設計+小さな導線) + +Status: planning(設計・導線追加/既存挙動は変えない) + +## ゴール + +- 25.1f で整えた **ControlForm 観測レイヤー**(LoopShape / IfShape + ControlForm)を、 + Conservative PHI Box(If/Loop 用 SSA/PHI ロジック)の入口として使えるようにする。 +- いきなりすべてを書き換えるのではなく、 + 1. If 用 Conservative PHI → ControlForm 対応 + 2. LoopForm v2 Exit PHI → ControlForm 対応 + の順に、小さく段階的に寄せる。 +- 各ステップごとに Rust テストと `tools/test_stageb_min.sh` を流しつつ、 + SSA/PHI の赤ログが増えていないことを確認して進む。 + +## 前提(25.1f までで揃ったもの) + +- Rust: + - `src/mir/control_form.rs`: + - `LoopShape` / `IfShape` / `ControlKind` / `ControlForm` / `CfgLike` / `is_control_form_trace_on()` が定義済み。 + - `src/mir/loop_builder.rs`: + - LoopForm v2 経路(`build_loop_with_loopform`)の出口で `LoopShape` → `ControlForm::Loop` を生成・トレース。 + - `lower_if_in_loop` の merge 部分で `IfShape` → `ControlForm::If` を生成・トレース。 + - `NYASH_CONTROL_FORM_TRACE`(未設定=ON, 0/false=OFF)でトレース ON/OFF 切り替え可能。 + - Conservative PHI: + - If 用: `src/mir/builder/phi.rs` / `src/mir/phi_core/if_phi.rs`(Conservative PHI Box 実装)。 + - Loop 用: `src/mir/phi_core/loopform_builder.rs`(LoopForm v2 の Exit PHI / Carrier/Pinned 対応)。 +- .hako: + - `lang/src/shared/mir/control_form_box.hako`: + - `static box ControlFormBox`(kind_name + loop_* / if_* + entry/exits)だけ実装済み(まだ未使用)。 + +## 方針(Option B の範囲) + +- **このフェーズでは**: + - Conservative PHI の「インターフェースと呼び出し位置」に ControlForm の導線を用意する。 + - ただし既存のロジック(引数で BlockId を受け取る形)は残し、ControlForm 導線は **観測+補助的な入口** として扱う。 + - 影響範囲は If / Loop の PHI 部分に限定し、他の MIR 降下には触れない。 +- 実装方針: + - 新しい API を「足す」→ 既存コードから段階的に使い始める、という形で進める。 + - 例: + - If 用: `merge_modified_at_merge_with_control(form: &ControlForm, ...)` を追加。 + - Loop 用: `build_exit_phis_for_control(form: &ControlForm, ...)` を追加。 + - 最初のステップでは「ControlForm から必要な BlockId を取り出して、既存の関数に委譲するだけ」の薄いラッパにする。 + +## タスク粒度 + +### G‑1: If 用 Conservative PHI への ControlForm 導線 + +- 目的: + - `loop_builder.rs::lower_if_in_loop` から、`ControlForm::If` を PHI ロジックに渡せるようにする。 +- ステップ: + 1. `src/mir/phi_core/if_phi.rs` に薄いラッパ関数を追加: + ```rust + pub fn merge_modified_with_control( + ops: &mut O, + form: &crate::mir::control_form::ControlForm, + pre_if_snapshot: &HashMap, + then_map_end: &HashMap, + else_map_end_opt: &Option>, + skip_var: Option<&str>, + ) -> Result<(), String> { + // ControlForm::If から cond/then/else/merge を取り出し、 + // 既存の merge_modified_at_merge_with に橋渡しするだけ(ロジックは変えない)。 + } + ``` + 2. `lower_if_in_loop` 側で: + - 既存の `merge_modified_at_merge_with` 呼び出しの直前/直後にコメントを付け、 + - 将来的に `merge_modified_with_control` に置き換えられるように位置を明示する(25.1g ではまだ呼び替えない or dev フラグで限定)。 + 3. テスト: + - `cargo test -q mir_stage1_using_resolver_min_fragment_verifies -- --nocapture` + - `cargo test -q mir_stage1_using_resolver_full_collect_entries_verifies -- --nocapture` + - 必要なら `NYASH_CONTROL_FORM_TRACE=1` で IfShape ログを確認し、BlockId 対応が設計どおりかを確認。 + +### G‑2: LoopForm v2 Exit PHI への ControlForm 導線 + +- 目的: + - LoopForm v2 Exit PHI(`loopform_builder.rs::build_exit_phis`)にも ControlForm ベースの入口を用意する。 +- ステップ: + 1. `src/mir/phi_core/loopform_builder.rs` にラッパ関数追加: + ```rust + pub fn build_exit_phis_for_control( + loopform: &LoopFormBuilder, + ops: &mut O, + form: &crate::mir::control_form::ControlForm, + exit_snapshots: &[(BasicBlockId, HashMap)], + ) -> Result<(), String> { + // form.kind が Loop の場合に限り、 + // shape.preheader/header/body/latch/exit から exit_id/branch_source_block を決めて + // 既存の build_exit_phis に委譲するだけ。 + } + ``` + 2. `LoopBuilder::build_loop_with_loopform` からは: + - 現在どおり `loopform.build_exit_phis(self, exit_id, branch_source_block, &exit_snaps)` を呼び続ける。 + - コメントで「ControlForm 経由の入口」があることを明示し、将来の切り替えポイントを固定する。 + 3. テスト: + - `cargo test -q mir_loopform_exit_phi -- --nocapture` + - `cargo test -q mir_stageb_loop_break_continue -- --nocapture` + - `./tools/test_stageb_min.sh` を流して、Exit PHI 誘発系の赤ログが増えていないことを確認。 + +### G‑3: ControlForm ↔ Conservative PHI の設計メモ更新 + +- 目的: + - 25.1d/e/f/g の成果をまとめ、「If/Loop の PHI が最終的にどのレイヤで SSOT を持つか」を文書で固定する。 +- ステップ: + - `phase-25.1d/README.md` と `phase-25.1f/README.md` をリンクしつつ、 + - Conservative PHI Box の責務(If/Loop 両方) + - ControlForm レイヤの責務 + - .hako 側 `ControlFormBox` / `LoopSSA` の予定 + を Phase 25 全体の流れの中に整理して追記する。 + - `CURRENT_TASK.md` に 25.1g の短いサマリを追加して、今どこまで進めたかをいつでも追えるようにする。 + +## このフェーズで「しない」こと + +- 既存の Conservative PHI 実装を一気に ControlForm 専用に書き換えること: + - 25.1g は「導線追加+ラッパ」「設計固め」まで。 + - 実際の置き換え(Option B の本体)は、さらに小さなステップに分けて後続フェーズで行う。 +- LoopBuilder/If 降下の大規模リファクタ(Option C 相当): + - これは Phase 25.2 以降の仕事として残しておく。 diff --git a/lang/src/shared/mir/control_form_box.hako b/lang/src/shared/mir/control_form_box.hako new file mode 100644 index 00000000..291b2814 --- /dev/null +++ b/lang/src/shared/mir/control_form_box.hako @@ -0,0 +1,42 @@ +// selfhost/shared/mir/control_form_box.hako +// ControlFormBox — Loop / If 共通ビューの Hakorune 実装版(Layer 2) +// +// 目的: +// - Rust 側の LoopShape / IfShape / ControlForm に対応する箱を .hako 側に用意して、 +// Stage‑B / LoopSSA からも同じモデルで制御構造を扱えるようにすることだよ。 +// - 現時点では「構造定義のみ」の箱で、コンパイルを通すための最小限の実装になっているよ。 + +static box ControlFormBox { + // 共通フィールド + kind_name: StringBox // "loop" or "if" + entry: IntegerBox // BasicBlockId 相当(整数ID) + exits: ArrayBox // of IntegerBox (BlockId) + + // Loop 用フィールド(kind_name == "loop" の時のみ意味を持つ) + loop_preheader: IntegerBox + loop_header: IntegerBox + loop_body: IntegerBox + loop_latch: IntegerBox + loop_exit: IntegerBox + + // If 用フィールド(kind_name == "if" の時のみ意味を持つ) + if_cond: IntegerBox + if_then: IntegerBox + if_else: IntegerBox + if_merge: IntegerBox + + // コンストラクタ相当: kind_name を設定し、exits 配列を初期化するよ。 + birth(kind) { + me.kind_name = kind + me.exits = new ArrayBox() + } + + is_loop() { + return me.kind_name == "loop" + } + + is_if() { + return me.kind_name == "if" + } +} + diff --git a/src/backend/mir_interpreter/exec.rs b/src/backend/mir_interpreter/exec.rs index 5bf5c02e..f5b7be48 100644 --- a/src/backend/mir_interpreter/exec.rs +++ b/src/backend/mir_interpreter/exec.rs @@ -36,9 +36,6 @@ impl MirInterpreter { let saved_fn = self.cur_fn.clone(); self.cur_fn = Some(func.signature.name.clone()); - // Check if this is a static box method call - let static_box_name = self.is_static_box_method(&func.signature.name); - match arg_vals { Some(args) => { // Regular parameter binding: params and args are 1:1 diff --git a/src/backend/mir_interpreter/handlers/boxes.rs b/src/backend/mir_interpreter/handlers/boxes.rs index f26c4fd3..cb20db73 100644 --- a/src/backend/mir_interpreter/handlers/boxes.rs +++ b/src/backend/mir_interpreter/handlers/boxes.rs @@ -278,6 +278,7 @@ impl MirInterpreter { } // moved: try_handle_map_box → handlers/boxes_map.rs + #[allow(dead_code)] fn try_handle_map_box( &mut self, dst: Option, @@ -289,6 +290,7 @@ impl MirInterpreter { } // moved: try_handle_string_box → handlers/boxes_string.rs + #[allow(dead_code)] fn try_handle_string_box( &mut self, dst: Option, @@ -300,6 +302,7 @@ impl MirInterpreter { } // moved: try_handle_array_box → handlers/boxes_array.rs + #[allow(dead_code)] fn try_handle_array_box( &mut self, dst: Option, diff --git a/src/backend/mir_interpreter/handlers/boxes_instance.rs b/src/backend/mir_interpreter/handlers/boxes_instance.rs index cba77985..54bed76e 100644 --- a/src/backend/mir_interpreter/handlers/boxes_instance.rs +++ b/src/backend/mir_interpreter/handlers/boxes_instance.rs @@ -102,7 +102,7 @@ pub(super) fn try_handle_instance_box( } else { // Conservative fallback: search unique function by name tail ".method/arity" let tail = format!(".{}{}", method, format!("/{}", args.len())); - let mut cands: Vec = this + let cands: Vec = this .functions .keys() .filter(|k| k.ends_with(&tail)) diff --git a/src/backend/mir_interpreter/handlers/boxes_object_fields.rs b/src/backend/mir_interpreter/handlers/boxes_object_fields.rs index f71af6d4..043039f8 100644 --- a/src/backend/mir_interpreter/handlers/boxes_object_fields.rs +++ b/src/backend/mir_interpreter/handlers/boxes_object_fields.rs @@ -1,5 +1,4 @@ use super::*; -use crate::box_trait::NyashBox; pub(super) fn try_handle_object_fields( this: &mut MirInterpreter, diff --git a/src/backend/mir_interpreter/handlers/boxes_string.rs b/src/backend/mir_interpreter/handlers/boxes_string.rs index f1306dbe..f2d7faed 100644 --- a/src/backend/mir_interpreter/handlers/boxes_string.rs +++ b/src/backend/mir_interpreter/handlers/boxes_string.rs @@ -1,5 +1,4 @@ use super::*; -use crate::box_trait::NyashBox; pub(super) fn try_handle_string_box( this: &mut MirInterpreter, diff --git a/src/backend/mir_interpreter/handlers/externals.rs b/src/backend/mir_interpreter/handlers/externals.rs index bcf5dc8a..2f5b3a19 100644 --- a/src/backend/mir_interpreter/handlers/externals.rs +++ b/src/backend/mir_interpreter/handlers/externals.rs @@ -3,6 +3,7 @@ use serde_json::Value as JsonValue; impl MirInterpreter { #[inline] + #[allow(dead_code)] fn ensure_mir_json_version_field(s: &str) -> String { match serde_json::from_str::(s) { Ok(mut v) => { @@ -28,6 +29,12 @@ impl MirInterpreter { let mbase = super::super::utils::normalize_arity_suffix(method); match (iface, mbase) { ("env", "get") => { + // Prefer provider-based resolution when available, fall back to process env. + if let Some(provider_res) = self.extern_provider_dispatch("env.get", args) { + let result = provider_res?; + self.write_result(dst, result); + return Ok(()); + } if let Some(a0) = args.get(0) { let key = self.reg_load(*a0)?.to_string(); let val = std::env::var(&key).ok(); @@ -135,14 +142,6 @@ impl MirInterpreter { } Ok(()) } - ("env", "get") => { - // Delegate to provider - let ret = self - .extern_provider_dispatch("env.get", args) - .unwrap_or(Ok(VMValue::Void))?; - self.write_result(dst, ret); - Ok(()) - } ("env", "set") => { // Delegate to provider let ret = self diff --git a/src/backend/mir_interpreter/mod.rs b/src/backend/mir_interpreter/mod.rs index 32309b21..88c9d741 100644 --- a/src/backend/mir_interpreter/mod.rs +++ b/src/backend/mir_interpreter/mod.rs @@ -110,6 +110,7 @@ impl MirInterpreter { /// Check if a function name represents a static box method /// Format: "BoxName.method/Arity" + #[allow(dead_code)] fn is_static_box_method(&self, func_name: &str) -> Option { if let Some((box_name, _rest)) = func_name.split_once('.') { if self.static_box_decls.contains_key(box_name) { diff --git a/src/backend/mir_interpreter/utils/arg_validation.rs b/src/backend/mir_interpreter/utils/arg_validation.rs index 286eb342..fc88b9e9 100644 --- a/src/backend/mir_interpreter/utils/arg_validation.rs +++ b/src/backend/mir_interpreter/utils/arg_validation.rs @@ -44,6 +44,7 @@ impl MirInterpreter { /// # Returns /// 引数数が範囲内の場合はOk(())、そうでない場合はエラー #[inline] + #[allow(dead_code)] pub(crate) fn validate_args_range( &self, method: &str, @@ -71,6 +72,7 @@ impl MirInterpreter { /// # Returns /// 引数数が最小値以上の場合はOk(())、そうでない場合はエラー #[inline] + #[allow(dead_code)] pub(crate) fn validate_args_min( &self, method: &str, diff --git a/src/backend/mir_interpreter/utils/conversion_helpers.rs b/src/backend/mir_interpreter/utils/conversion_helpers.rs index db6c9012..f4eb9426 100644 --- a/src/backend/mir_interpreter/utils/conversion_helpers.rs +++ b/src/backend/mir_interpreter/utils/conversion_helpers.rs @@ -42,6 +42,7 @@ impl MirInterpreter { /// # Errors /// * 値が整数でない場合はエラー #[inline] + #[allow(dead_code)] pub(crate) fn load_as_int(&mut self, vid: ValueId) -> Result { match self.reg_load(vid)? { VMValue::Integer(i) => Ok(i), @@ -71,6 +72,7 @@ impl MirInterpreter { /// # Errors /// * 値がboolでない場合はエラー #[inline] + #[allow(dead_code)] pub(crate) fn load_as_bool(&mut self, vid: ValueId) -> Result { match self.reg_load(vid)? { VMValue::Bool(b) => Ok(b), @@ -112,6 +114,7 @@ impl MirInterpreter { /// # Returns /// * `Result, VMError>` - 読み込んだVMValueのVec #[inline] + #[allow(dead_code)] pub(crate) fn load_args_as_values( &mut self, vids: &[ValueId], diff --git a/src/backend/mir_interpreter/utils/destination_helpers.rs b/src/backend/mir_interpreter/utils/destination_helpers.rs index 9a53655a..8082c001 100644 --- a/src/backend/mir_interpreter/utils/destination_helpers.rs +++ b/src/backend/mir_interpreter/utils/destination_helpers.rs @@ -13,6 +13,7 @@ impl MirInterpreter { /// * `dst` - 書き込み先のValueId (Noneの場合は何もしない) /// * `result` - 書き込むBox #[inline] + #[allow(dead_code)] pub(crate) fn write_box_result( &mut self, dst: Option, diff --git a/src/backend/mir_interpreter/utils/error_helpers.rs b/src/backend/mir_interpreter/utils/error_helpers.rs index 635a8ae9..a070ad5c 100644 --- a/src/backend/mir_interpreter/utils/error_helpers.rs +++ b/src/backend/mir_interpreter/utils/error_helpers.rs @@ -40,6 +40,7 @@ impl ErrorBuilder { /// // => "get expects Integer type, got String" /// ``` #[inline] + #[allow(dead_code)] pub fn type_mismatch(method: &str, expected: &str, actual: &str) -> VMError { VMError::InvalidInstruction(format!("{} expects {} type, got {}", method, expected, actual)) } @@ -57,6 +58,7 @@ impl ErrorBuilder { /// // => "get index out of bounds: 5 >= 3" /// ``` #[inline] + #[allow(dead_code)] pub fn out_of_bounds(method: &str, index: usize, len: usize) -> VMError { VMError::InvalidInstruction(format!("{} index out of bounds: {} >= {}", method, index, len)) } @@ -93,6 +95,7 @@ impl ErrorBuilder { /// // => "receiver must be ArrayBox" /// ``` #[inline] + #[allow(dead_code)] pub fn receiver_type_error(expected: &str) -> VMError { VMError::InvalidInstruction(format!("receiver must be {}", expected)) } @@ -123,6 +126,7 @@ impl ErrorBuilder { /// // => "link_object expects at least 1 arg, got 0" /// ``` #[inline] + #[allow(dead_code)] pub fn arg_count_min(method: &str, min: usize, actual: usize) -> VMError { VMError::InvalidInstruction(format!( "{} expects at least {} arg{}, got {}", @@ -153,6 +157,7 @@ impl ErrorBuilder { /// // => "link_object: " /// ``` #[inline] + #[allow(dead_code)] pub fn from_error(operation: &str, error: &dyn std::error::Error) -> VMError { VMError::InvalidInstruction(format!("{}: {}", operation, error)) } @@ -178,6 +183,7 @@ impl super::super::MirInterpreter { /// return Err(self.err_type_mismatch("get", "Integer", actual_type)); /// ``` #[inline] + #[allow(dead_code)] pub(crate) fn err_type_mismatch(&self, method: &str, expected: &str, actual: &str) -> VMError { ErrorBuilder::type_mismatch(method, expected, actual) } @@ -189,6 +195,7 @@ impl super::super::MirInterpreter { /// return Err(self.err_out_of_bounds("get", idx, len)); /// ``` #[inline] + #[allow(dead_code)] pub(crate) fn err_out_of_bounds(&self, method: &str, index: usize, len: usize) -> VMError { ErrorBuilder::out_of_bounds(method, index, len) } diff --git a/src/backend/mir_interpreter/utils/receiver_helpers.rs b/src/backend/mir_interpreter/utils/receiver_helpers.rs index 1fc6ddde..42f0981c 100644 --- a/src/backend/mir_interpreter/utils/receiver_helpers.rs +++ b/src/backend/mir_interpreter/utils/receiver_helpers.rs @@ -15,6 +15,7 @@ impl MirInterpreter { /// # Returns /// 変換成功時はBox、失敗時はエラー #[inline] + #[allow(dead_code)] pub(crate) fn convert_to_box( &mut self, receiver: ValueId, diff --git a/src/benchmarks.rs b/src/benchmarks.rs index aed0b0c7..dfa7b5cb 100644 --- a/src/benchmarks.rs +++ b/src/benchmarks.rs @@ -33,7 +33,10 @@ impl BenchmarkSuite { /// Run comprehensive benchmark across all backends pub fn run_all(&self) -> Vec { + #[cfg(feature = "wasm-backend")] let mut results = Vec::new(); + #[cfg(not(feature = "wasm-backend"))] + let results = Vec::new(); let benchmarks = [ ("bench_light", "benchmarks/bench_light.hako"), @@ -45,14 +48,14 @@ impl BenchmarkSuite { println!("🚀 Running benchmark: {}", name); // Test if file exists and is readable - if let Ok(source) = fs::read_to_string(file_path) { + if let Ok(_source) = fs::read_to_string(file_path) { // Run on all backends // Interpreter benchmark removed with legacy interpreter // VM benchmark removed with vm-legacy #[cfg(feature = "wasm-backend")] - if let Ok(wasm_result) = self.run_wasm_benchmark(name, &source) { + if let Ok(wasm_result) = self.run_wasm_benchmark(name, &_source) { results.push(wasm_result); } } else { diff --git a/src/box_operators.rs b/src/box_operators.rs index f1344780..1d835b71 100644 --- a/src/box_operators.rs +++ b/src/box_operators.rs @@ -27,7 +27,6 @@ mod static_ops; pub use helpers::{concat_result, can_repeat}; pub use macros::impl_static_numeric_ops; -use crate::operator_traits::{NyashAdd, NyashMul}; // Phase 2: Static implementations are now in static_ops.rs @@ -514,6 +513,7 @@ impl OperatorResolver { #[cfg(test)] mod tests { use super::*; + use crate::operator_traits::{NyashAdd, NyashMul}; #[test] fn test_integer_addition() { diff --git a/src/box_operators/static_ops.rs b/src/box_operators/static_ops.rs index 101d76b7..00e25d31 100644 --- a/src/box_operators/static_ops.rs +++ b/src/box_operators/static_ops.rs @@ -11,14 +11,14 @@ use crate::impl_static_numeric_ops; // ===== Macro-generated static implementations ===== -/// Static numeric operations for IntegerBox -/// -/// Generates implementations for: Add, Sub, Mul, Div with zero-division error handling +// Static numeric operations for IntegerBox +// +// Generates implementations for: Add, Sub, Mul, Div with zero-division error handling impl_static_numeric_ops!(IntegerBox, 0); -/// Static numeric operations for FloatBox -/// -/// Generates implementations for: Add, Sub, Mul, Div with zero-division error handling +// Static numeric operations for FloatBox +// +// Generates implementations for: Add, Sub, Mul, Div with zero-division error handling impl_static_numeric_ops!(FloatBox, 0.0); // ===== Manual static implementations for special cases ===== @@ -57,4 +57,4 @@ impl NyashAdd for BoolBox { } // Note: Additional static implementations can be added here as needed -// for cross-type operations or special Box types \ No newline at end of file +// for cross-type operations or special Box types diff --git a/src/boxes/arithmetic/modulo_box.rs b/src/boxes/arithmetic/modulo_box.rs index 974e4aa8..70889121 100644 --- a/src/boxes/arithmetic/modulo_box.rs +++ b/src/boxes/arithmetic/modulo_box.rs @@ -3,7 +3,6 @@ //! Implements modulo operations between integer types with error handling. use crate::box_trait::{BoolBox, BoxBase, BoxCore, IntegerBox, NyashBox, StringBox}; -use std::any::Any; use std::fmt::{Debug, Display}; /// Modulo operations between boxes @@ -124,4 +123,4 @@ impl Display for ModuloBox { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.fmt_box(f) } -} \ No newline at end of file +} diff --git a/src/host_providers/mir_builder.rs b/src/host_providers/mir_builder.rs index b59638a6..294f73c1 100644 --- a/src/host_providers/mir_builder.rs +++ b/src/host_providers/mir_builder.rs @@ -2,7 +2,7 @@ use crate::runner; use serde_json::Value as JsonValue; use std::collections::HashMap; use std::fs; -use std::io::Write; +// use std::io::Write; // kept for future pretty-print extensions /// Convert Program(JSON v0) to MIR(JSON v0) and return it as a String. /// Fail-Fast: prints stable tags on stderr and returns Err with the same tag text. @@ -52,7 +52,7 @@ pub fn program_json_to_mir_json_with_imports(program_json: &str, imports: HashMa let _ = fs::remove_file(&tmp_path); // Ensure v1 schema: if output lacks schema_version but has functions, wrap minimally let s = match serde_json::from_str::(&s0) { - Ok(JsonValue::Object(mut m)) => { + Ok(JsonValue::Object(m)) => { if m.get("schema_version").is_none() { if let Some(funcs) = m.get("functions").cloned() { let v1 = serde_json::json!({"schema_version":"1.0","functions": funcs}); diff --git a/src/mir/builder.rs b/src/mir/builder.rs index f4c1fe6a..4459ca12 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -510,11 +510,11 @@ impl MirBuilder { let mut instruction = instruction; // Precompute debug metadata to avoid borrow conflicts later - let dbg_fn_name = self + let _dbg_fn_name = self .current_function .as_ref() .map(|f| f.signature.name.clone()); - let dbg_region_id = self.debug_current_region_id(); + let _dbg_region_id = self.debug_current_region_id(); // P0: PHI の軽量補強と観測は、関数ブロック取得前に実施して借用競合を避ける if let MirInstruction::Phi { dst, inputs } = &instruction { origin::phi::propagate_phi_meta(self, *dst, inputs); diff --git a/src/mir/builder/builder_calls.rs b/src/mir/builder/builder_calls.rs index c8c34c8f..c17dd370 100644 --- a/src/mir/builder/builder_calls.rs +++ b/src/mir/builder/builder_calls.rs @@ -18,7 +18,6 @@ //! 4. ✅ 巨大関数は分割: 100行超える関数を30-50行目標で分割 // Import from new modules (refactored with Box Theory) -use super::calls::*; pub use super::calls::call_target::CallTarget; // ======================================== diff --git a/src/mir/builder/call_resolution.rs b/src/mir/builder/call_resolution.rs index 8d40643c..2451c70a 100644 --- a/src/mir/builder/call_resolution.rs +++ b/src/mir/builder/call_resolution.rs @@ -46,6 +46,7 @@ pub fn suggest_resolution(name: &str) -> String { /// Check if a method name is commonly shadowed by global functions /// Used for generating warnings about potential self-recursion +#[allow(dead_code)] pub fn is_commonly_shadowed_method(method: &str) -> bool { matches!( method, @@ -57,6 +58,7 @@ pub fn is_commonly_shadowed_method(method: &str) -> bool { } /// Generate warning message for potential self-recursion +#[allow(dead_code)] pub fn generate_self_recursion_warning(box_name: &str, method: &str) -> String { format!( "Warning: Potential self-recursion detected in {}.{}(). \ @@ -102,4 +104,4 @@ mod tests { assert!(warning.contains("::print()")); assert!(warning.contains("self-recursion")); } -} \ No newline at end of file +} diff --git a/src/mir/builder/calls/call_unified.rs b/src/mir/builder/calls/call_unified.rs index 8dc365b7..d222d508 100644 --- a/src/mir/builder/calls/call_unified.rs +++ b/src/mir/builder/calls/call_unified.rs @@ -5,11 +5,8 @@ * Replaces 6 different call instructions with a single unified system */ -use crate::mir::{Callee, Effect, EffectMask, ValueId}; -use crate::mir::definitions::call_unified::{CallFlags, MirCall, TypeCertainty}; -use super::call_target::CallTarget; -use super::method_resolution; -use super::extern_calls; +use crate::mir::{Callee, EffectMask, ValueId}; +use crate::mir::definitions::call_unified::{CallFlags, MirCall}; /// Check if unified call system is enabled pub fn is_unified_call_enabled() -> bool { diff --git a/src/mir/builder/calls/emit.rs b/src/mir/builder/calls/emit.rs index 85a585f5..a5e962c6 100644 --- a/src/mir/builder/calls/emit.rs +++ b/src/mir/builder/calls/emit.rs @@ -5,9 +5,9 @@ //! - emit_legacy_call: レガシーCall発行(既存互換) //! - emit_global_call/emit_method_call/emit_constructor_call: 便利ラッパー -use super::super::{Effect, EffectMask, MirBuilder, MirInstruction, ValueId}; +use super::super::{EffectMask, MirBuilder, MirInstruction, ValueId}; use crate::mir::definitions::call_unified::Callee; -use super::{CallTarget, call_unified}; +use super::CallTarget; impl MirBuilder { /// Unified call emission - delegates to UnifiedCallEmitterBox @@ -139,6 +139,7 @@ impl MirBuilder { // ======================================== /// Try fallback handlers for global functions (delegates to CallMaterializerBox) + #[allow(dead_code)] pub(super) fn try_global_fallback_handlers( &mut self, dst: Option, @@ -149,6 +150,7 @@ impl MirBuilder { } /// Ensure receiver is materialized in Callee::Method (delegates to CallMaterializerBox) + #[allow(dead_code)] pub(super) fn materialize_receiver_in_callee( &mut self, callee: Callee, diff --git a/src/mir/builder/calls/extern_calls.rs b/src/mir/builder/calls/extern_calls.rs index 90300e1a..6a56f32b 100644 --- a/src/mir/builder/calls/extern_calls.rs +++ b/src/mir/builder/calls/extern_calls.rs @@ -155,6 +155,7 @@ pub fn parse_extern_name(name: &str) -> (String, String) { } /// Check if a name refers to an environment interface +#[allow(dead_code)] pub fn is_env_interface(name: &str) -> bool { matches!(name, "env" | "env.console" | "env.fs" | "env.net" | diff --git a/src/mir/builder/calls/function_lowering.rs b/src/mir/builder/calls/function_lowering.rs index 739fdfad..8bbc9d81 100644 --- a/src/mir/builder/calls/function_lowering.rs +++ b/src/mir/builder/calls/function_lowering.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + /*! * Function Lowering Utilities * @@ -147,4 +149,4 @@ pub fn method_likely_returns_value(method_name: &str) -> bool { "add" | "sub" | "mul" | "div" | "min" | "max" | "abs" ) -} \ No newline at end of file +} diff --git a/src/mir/builder/calls/guard.rs b/src/mir/builder/calls/guard.rs index 956e684f..91f25084 100644 --- a/src/mir/builder/calls/guard.rs +++ b/src/mir/builder/calls/guard.rs @@ -96,6 +96,7 @@ impl<'a> CalleeGuardBox<'a> { /// receiver型の検証(ヘルパー) /// /// 指定されたreceiverがBox型を持っているか確認 + #[allow(dead_code)] pub fn has_box_type(&self, receiver: ValueId) -> bool { matches!(self.value_types.get(&receiver), Some(MirType::Box(_))) } @@ -103,6 +104,7 @@ impl<'a> CalleeGuardBox<'a> { /// receiver型の取得(ヘルパー) /// /// 指定されたreceiverのBox型名を返す(存在しない場合はNone) + #[allow(dead_code)] pub fn get_box_type(&self, receiver: ValueId) -> Option<&String> { match self.value_types.get(&receiver) { Some(MirType::Box(box_name)) => Some(box_name), @@ -114,6 +116,7 @@ impl<'a> CalleeGuardBox<'a> { /// /// box_name と receiver型が一致するか判定 /// (静的メソッド呼び出しの検出用) + #[allow(dead_code)] pub fn is_me_call(&self, box_name: &str, receiver: ValueId) -> bool { match self.get_box_type(receiver) { Some(recv_box) => recv_box == box_name, diff --git a/src/mir/builder/calls/mod.rs b/src/mir/builder/calls/mod.rs index a5281c45..77c8d5f8 100644 --- a/src/mir/builder/calls/mod.rs +++ b/src/mir/builder/calls/mod.rs @@ -28,8 +28,13 @@ pub mod effects_analyzer; // Phase 3-B: Effects analyzer (エフェクト解析 pub mod materializer; // Phase 3-C: Call materializer (Call前処理・準備専用箱) // Re-export public interfaces +#[allow(unused_imports)] pub use call_target::CallTarget; +#[allow(unused_imports)] pub use lowering::*; +#[allow(unused_imports)] pub use utils::*; +#[allow(unused_imports)] pub use emit::*; +#[allow(unused_imports)] pub use build::*; diff --git a/src/mir/builder/calls/special_handlers.rs b/src/mir/builder/calls/special_handlers.rs index b72ea470..8ea9e836 100644 --- a/src/mir/builder/calls/special_handlers.rs +++ b/src/mir/builder/calls/special_handlers.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + /*! * Special Call Handlers * @@ -137,4 +139,4 @@ pub fn suggest_alternative_for_reserved(name: &str) -> String { "from" => "Use 'from Parent.method()' syntax for delegation".to_string(), _ => format!("'{}' is a reserved keyword", name), } -} \ No newline at end of file +} diff --git a/src/mir/builder/context.rs b/src/mir/builder/context.rs index 513e5a03..22bc8d10 100644 --- a/src/mir/builder/context.rs +++ b/src/mir/builder/context.rs @@ -23,16 +23,19 @@ use std::collections::HashMap; pub struct BoxCompilationContext { /// 変数名 → ValueId マッピング /// 例: "args" → ValueId(0), "result" → ValueId(42) + #[allow(dead_code)] pub variable_map: HashMap, /// ValueId → 起源Box名 マッピング /// NewBox命令で生成されたValueIdがどのBox型から来たかを追跡 /// 例: ValueId(10) → "ParserBox" + #[allow(dead_code)] pub value_origin_newbox: HashMap, /// ValueId → MIR型 マッピング /// 各ValueIdの型情報を保持 /// 例: ValueId(5) → MirType::Integer + #[allow(dead_code)] pub value_types: HashMap, } @@ -43,6 +46,7 @@ impl BoxCompilationContext { } /// コンテキストが空(未使用)かどうかを判定 + #[allow(dead_code)] pub fn is_empty(&self) -> bool { self.variable_map.is_empty() && self.value_origin_newbox.is_empty() @@ -50,6 +54,7 @@ impl BoxCompilationContext { } /// デバッグ用:コンテキストのサイズ情報を取得 + #[allow(dead_code)] pub fn size_info(&self) -> (usize, usize, usize) { ( self.variable_map.len(), diff --git a/src/mir/builder/decls.rs b/src/mir/builder/decls.rs index 73f3d9a0..b7f49069 100644 --- a/src/mir/builder/decls.rs +++ b/src/mir/builder/decls.rs @@ -38,11 +38,6 @@ impl super::MirBuilder { let _ = self.lower_static_method_as_function(func_name, params.clone(), body.clone()); eprintln!("[DEBUG] build_static_main_box: After lower_static_method_as_function"); eprintln!("[DEBUG] variable_map = {:?}", self.variable_map); - // Convert the method body to a Program AST node and lower it - let program_ast = ASTNode::Program { - statements: body.clone(), - span: crate::ast::Span::unknown(), - }; // Initialize local variables for Main.main() parameters // Note: These are local variables in the wrapper main() function, NOT parameters let saved_var_map = std::mem::take(&mut self.variable_map); @@ -117,7 +112,7 @@ impl super::MirBuilder { weak_fields: Vec, ) -> Result<(), String> { // Create a type registration constant (marker) - let type_id = crate::mir::builder::emission::constant::emit_string(self, format!("__box_type_{}", name)); + crate::mir::builder::emission::constant::emit_string(self, format!("__box_type_{}", name)); // Emit field metadata markers for field in fields { diff --git a/src/mir/builder/emission/compare.rs b/src/mir/builder/emission/compare.rs index b2d0c889..0ef363ce 100644 --- a/src/mir/builder/emission/compare.rs +++ b/src/mir/builder/emission/compare.rs @@ -17,11 +17,13 @@ pub fn emit_to(b: &mut MirBuilder, dst: ValueId, op: CompareOp, lhs: ValueId, rh // Convenience wrappers (明示関数名が読みやすい箇所用) #[inline] +#[allow(dead_code)] pub fn emit_eq_to(b: &mut MirBuilder, dst: ValueId, lhs: ValueId, rhs: ValueId) -> Result<(), String> { emit_to(b, dst, CompareOp::Eq, lhs, rhs) } #[inline] +#[allow(dead_code)] pub fn emit_ne_to(b: &mut MirBuilder, dst: ValueId, lhs: ValueId, rhs: ValueId) -> Result<(), String> { emit_to(b, dst, CompareOp::Ne, lhs, rhs) } diff --git a/src/mir/builder/lifecycle.rs b/src/mir/builder/lifecycle.rs index 2d59d23d..d2f3cacd 100644 --- a/src/mir/builder/lifecycle.rs +++ b/src/mir/builder/lifecycle.rs @@ -288,7 +288,7 @@ impl super::MirBuilder { MirInstruction::Const { value, .. } => { if let super::ConstValue::String(s) = value { last_const_name = Some(s.clone()); } } - MirInstruction::Call { func, .. } => { + MirInstruction::Call { func: _, .. } => { // If immediately preceded by matching Const String, accept if let Some(prev) = last_const_name.as_ref() { if prev == &expect_tail { ok = true; break; } @@ -318,7 +318,7 @@ impl super::MirBuilder { // Dev stub: provide condition_fn when missing to satisfy predicate calls in JSON lexers // Returns integer 1 (truthy) and accepts one argument (unused). if module.functions.get("condition_fn").is_none() { - let mut sig = FunctionSignature { + let sig = FunctionSignature { name: "condition_fn".to_string(), params: vec![MirType::Integer], // accept one i64-like arg return_type: MirType::Integer, diff --git a/src/mir/builder/metadata/propagate.rs b/src/mir/builder/metadata/propagate.rs index 973548d7..be136824 100644 --- a/src/mir/builder/metadata/propagate.rs +++ b/src/mir/builder/metadata/propagate.rs @@ -32,6 +32,7 @@ pub fn propagate(builder: &mut MirBuilder, src: ValueId, dst: ValueId) { /// dst に型注釈を明示的に設定し、必要ならば起源情報を消去/維持する。 /// 🎯 TypeRegistry 経由モード対応(NYASH_USE_TYPE_REGISTRY=1) #[inline] +#[allow(dead_code)] pub fn propagate_with_override(builder: &mut MirBuilder, dst: ValueId, ty: MirType) { let use_registry = std::env::var("NYASH_USE_TYPE_REGISTRY") .ok() @@ -45,4 +46,3 @@ pub fn propagate_with_override(builder: &mut MirBuilder, dst: ValueId, ty: MirTy builder.value_types.insert(dst, ty); } } - diff --git a/src/mir/builder/method_call_handlers.rs b/src/mir/builder/method_call_handlers.rs index c90ec598..94981e58 100644 --- a/src/mir/builder/method_call_handlers.rs +++ b/src/mir/builder/method_call_handlers.rs @@ -62,6 +62,7 @@ impl MirBuilder { } /// Check if this is a TypeOp method call + #[allow(dead_code)] pub(super) fn is_typeop_method(method: &str, arguments: &[ASTNode]) -> Option { if (method == "is" || method == "as") && arguments.len() == 1 { Self::extract_string_literal(&arguments[0]) diff --git a/src/mir/builder/phi.rs b/src/mir/builder/phi.rs index 70c297bb..174b1e1e 100644 --- a/src/mir/builder/phi.rs +++ b/src/mir/builder/phi.rs @@ -12,7 +12,7 @@ impl MirBuilder { pub(super) fn merge_modified_vars( &mut self, _then_block: super::BasicBlockId, - else_block: super::BasicBlockId, + _else_block: super::BasicBlockId, then_exit_block_opt: Option, else_exit_block_opt: Option, pre_if_snapshot: &std::collections::HashMap, @@ -179,8 +179,8 @@ impl MirBuilder { /// This handles variable reassignment patterns and ensures a single exit value. pub(super) fn normalize_if_else_phi( &mut self, - then_block: BasicBlockId, - else_block: BasicBlockId, + _then_block: BasicBlockId, + _else_block: BasicBlockId, then_exit_block_opt: Option, else_exit_block_opt: Option, then_value_raw: ValueId, diff --git a/src/mir/builder/rewrite/known.rs b/src/mir/builder/rewrite/known.rs index 28526ec5..cb67ae30 100644 --- a/src/mir/builder/rewrite/known.rs +++ b/src/mir/builder/rewrite/known.rs @@ -19,6 +19,7 @@ fn rewrite_enabled() -> bool { /// Try Known‑route instance→function rewrite. /// 既存の安全ガード(user_defined/存在確認/ENV)を尊重して関数化する。 +#[allow(dead_code)] pub(crate) fn try_known_rewrite( builder: &mut MirBuilder, object_value: ValueId, @@ -119,6 +120,7 @@ pub(crate) fn try_known_rewrite_to_dst( /// Fallback: when exactly one user-defined method matches by name/arity across the module, /// resolve to that even if class inference failed. Deterministic via uniqueness and user-box prefix. +#[allow(dead_code)] pub(crate) fn try_unique_suffix_rewrite( builder: &mut MirBuilder, object_value: ValueId, @@ -183,7 +185,7 @@ pub(crate) fn try_unique_suffix_rewrite_to_dst( if cands.len() != 1 { return None; } let fname = cands.remove(0); if let Some((bx, _)) = fname.split_once('.') { if !builder.user_defined_boxes.contains(bx) { return None; } } else { return None; } - let name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) { + let _name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -212,6 +214,7 @@ pub(crate) fn try_unique_suffix_rewrite_to_dst( } /// Unified entry: try Known rewrite first, then unique-suffix fallback. +#[allow(dead_code)] pub(crate) fn try_known_or_unique( builder: &mut MirBuilder, object_value: ValueId, diff --git a/src/mir/builder/rewrite/special.rs b/src/mir/builder/rewrite/special.rs index bce6ba50..435d0dea 100644 --- a/src/mir/builder/rewrite/special.rs +++ b/src/mir/builder/rewrite/special.rs @@ -2,6 +2,7 @@ use super::super::MirBuilder; /// Early special-case: toString/stringify → str(互換)を処理。 /// 戻り値: Some(result_id) なら処理済み。None なら通常経路へ委譲。 +#[allow(dead_code)] pub(crate) fn try_early_str_like( builder: &mut MirBuilder, object_value: super::super::ValueId, @@ -104,6 +105,7 @@ pub(crate) fn try_early_str_like( /// Special-case for equals/1: prefer Known rewrite; otherwise allow unique-suffix fallback /// when it is deterministic (single candidate). This centralizes equals handling. +#[allow(dead_code)] pub(crate) fn try_special_equals( builder: &mut MirBuilder, object_value: super::super::ValueId, @@ -151,7 +153,7 @@ pub(crate) fn try_early_str_like_to_dst( "certainty": "Known", }); super::super::observe::resolve::emit_choose(builder, meta); - let name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &chosen) { + let _name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &chosen) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -182,7 +184,7 @@ pub(crate) fn try_early_str_like_to_dst( "certainty": "Heuristic", }); super::super::observe::resolve::emit_choose(builder, meta); - let name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) { + let _name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) { Ok(v) => v, Err(e) => return Some(Err(e)), }; @@ -209,7 +211,7 @@ pub(crate) fn try_early_str_like_to_dst( "certainty": "Heuristic", }); super::super::observe::resolve::emit_choose(builder, meta); - let name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) { + let _name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) { Ok(v) => v, Err(e) => return Some(Err(e)), }; diff --git a/src/mir/builder/schedule/block.rs b/src/mir/builder/schedule/block.rs index c838a765..7c77e9bc 100644 --- a/src/mir/builder/schedule/block.rs +++ b/src/mir/builder/schedule/block.rs @@ -7,6 +7,7 @@ pub struct BlockScheduleBox; impl BlockScheduleBox { /// Insert a Copy immediately after PHI nodes. Returns the local value id. + #[allow(dead_code)] pub fn ensure_after_phis_copy(builder: &mut MirBuilder, src: ValueId) -> Result { if let Some(bb) = builder.current_block { if let Some(&cached) = builder.schedule_mat_map.get(&(bb, src)) { @@ -29,6 +30,7 @@ impl BlockScheduleBox { /// Emit a Copy right before the next emitted instruction (best-effort): /// place it at the tail of the current block. Returns the local value id. + #[allow(dead_code)] pub fn emit_before_call_copy(builder: &mut MirBuilder, src: ValueId) -> Result { // Prefer to reuse the after-phis materialized id for this src in this block let base = Self::ensure_after_phis_copy(builder, src)?; diff --git a/src/mir/builder/type_registry.rs b/src/mir/builder/type_registry.rs index 8473cf9e..44e8a30e 100644 --- a/src/mir/builder/type_registry.rs +++ b/src/mir/builder/type_registry.rs @@ -13,6 +13,7 @@ use std::collections::HashMap; pub struct TraceEntry { pub vid: ValueId, pub source: String, // "newbox:MapBox", "param:args", "propagate:from_%123" + #[allow(dead_code)] pub timestamp: usize, } @@ -52,6 +53,7 @@ impl TypeRegistry { // ============================================================ /// NewBox起源を記録 + #[allow(dead_code)] pub fn record_newbox(&mut self, vid: ValueId, class: String) { self.origins.insert(vid, class.clone()); @@ -67,6 +69,7 @@ impl TypeRegistry { } /// パラメータ型を記録 + #[allow(dead_code)] pub fn record_param(&mut self, vid: ValueId, param_name: &str, param_type: Option) { if let Some(ty) = param_type.clone() { self.types.insert(vid, ty.clone()); @@ -107,6 +110,7 @@ impl TypeRegistry { } /// 起源を明示的に設定(推論結果など) + #[allow(dead_code)] pub fn record_origin(&mut self, vid: ValueId, origin: String, reason: &str) { self.origins.insert(vid, origin.clone()); @@ -164,11 +168,13 @@ impl TypeRegistry { // ============================================================ /// 起源クラス名を取得 + #[allow(dead_code)] pub fn get_origin(&self, vid: ValueId) -> Option<&String> { self.origins.get(&vid) } /// 型情報を取得 + #[allow(dead_code)] pub fn get_type(&self, vid: ValueId) -> Option<&MirType> { self.types.get(&vid) } @@ -214,6 +220,7 @@ impl TypeRegistry { } /// 全トレースログを表示 + #[allow(dead_code)] pub fn dump_trace(&self) { eprintln!("[type-registry] === Trace Log ({} entries) ===", self.trace_log.len()); for entry in &self.trace_log { @@ -222,6 +229,7 @@ impl TypeRegistry { } /// 統計情報を表示 + #[allow(dead_code)] pub fn dump_stats(&self) { eprintln!("[type-registry] === Statistics ==="); eprintln!("[type-registry] Origins: {} entries", self.origins.len()); @@ -234,6 +242,7 @@ impl TypeRegistry { // ============================================================ /// 起源情報のみクリア(型情報は保持) + #[allow(dead_code)] pub fn clear_origins(&mut self) { self.origins.clear(); if self.trace_enabled { @@ -242,6 +251,7 @@ impl TypeRegistry { } /// 全情報クリア + #[allow(dead_code)] pub fn clear_all(&mut self) { self.origins.clear(); self.types.clear(); diff --git a/src/mir/builder/types/annotation.rs b/src/mir/builder/types/annotation.rs index d94fa07a..937b3d4f 100644 --- a/src/mir/builder/types/annotation.rs +++ b/src/mir/builder/types/annotation.rs @@ -5,6 +5,7 @@ use crate::mir::builder::MirBuilder; /// 直接的に MirType を設定する(仕様不変)。 #[inline] +#[allow(dead_code)] pub fn set_type(builder: &mut MirBuilder, dst: ValueId, ty: MirType) { builder.value_types.insert(dst, ty); } diff --git a/src/mir/builder/utils.rs b/src/mir/builder/utils.rs index 99abb223..7973b10d 100644 --- a/src/mir/builder/utils.rs +++ b/src/mir/builder/utils.rs @@ -334,6 +334,7 @@ impl super::MirBuilder { } /// Ensure a value has a local definition in the current block by inserting a Copy. + #[allow(dead_code)] pub(crate) fn materialize_local(&mut self, v: super::ValueId) -> Result { // Phase 25.1b: Use function-local ID allocator to avoid SSA verification failures let dst = if let Some(ref mut f) = self.current_function { @@ -348,6 +349,7 @@ impl super::MirBuilder { } /// Insert a Copy immediately after PHI nodes in the current block (position-stable). + #[allow(dead_code)] pub(crate) fn insert_copy_after_phis(&mut self, dst: super::ValueId, src: super::ValueId) -> Result<(), String> { if let (Some(ref mut function), Some(bb)) = (&mut self.current_function, self.current_block) { if std::env::var("NYASH_SCHEDULE_TRACE").ok().as_deref() == Some("1") { diff --git a/src/mir/control_form.rs b/src/mir/control_form.rs new file mode 100644 index 00000000..60afe827 --- /dev/null +++ b/src/mir/control_form.rs @@ -0,0 +1,222 @@ +/*! + * ControlForm – 共通制御構造ビュー(Loop / If の箱化レイヤ) + * + * 目的: + * - LoopForm v2(ループ)と If 降下を、1段上の「制御構造の形」として統一的に眺めるための薄いレイヤだよ。 + * - Conservative PHI Box や将来の可視化/検証ロジックが、Loop 専用 / If 専用に分かれず、 + * ControlForm という SSOT から情報を取れるようにするのがねらいだよ。 + * + * このモジュール自体は構造定義とデバッグ用のユーティリティのみを提供し、 + * 既存の LoopBuilder / If 降下の挙動は変えないよ(Phase 25.1f では観測レイヤ専用)。 + */ + +use crate::mir::{BasicBlock, BasicBlockId, MirFunction}; + +/// ループ構造の形だけを表す箱だよ。 +/// +/// - `preheader` : ループ直前のブロック(キャリア/ピン変数のコピー元) +/// - `header` : ループヘッダ(条件判定と header PHI が置かれる) +/// - `body` : 代表的なループ本体ブロック(最初の body など) +/// - `latch` : ヘッダへ戻るバックエッジを張るブロック +/// - `exit` : ループを抜けた先のブロック +/// - `continue_targets` : continue がジャンプするブロック群(通常は latch か header) +/// - `break_targets` : break がジャンプするブロック群(通常は exit) +#[derive(Debug, Clone)] +pub struct LoopShape { + pub preheader: BasicBlockId, + pub header: BasicBlockId, + pub body: BasicBlockId, + pub latch: BasicBlockId, + pub exit: BasicBlockId, + pub continue_targets: Vec, + pub break_targets: Vec, +} + +/// if/else 構造の形だけを表す箱だよ。 +/// +/// - `cond_block` : 条件式を評価するブロック +/// - `then_block` : then ブランチの先頭ブロック +/// - `else_block` : else ブランチの先頭ブロック(無ければ None) +/// - `merge_block`: then/else の合流ブロック +#[derive(Debug, Clone)] +pub struct IfShape { + pub cond_block: BasicBlockId, + pub then_block: BasicBlockId, + pub else_block: Option, + pub merge_block: BasicBlockId, +} + +/// 制御構造の種別だよ。 +#[derive(Debug, Clone)] +pub enum ControlKind { + Loop(LoopShape), + If(IfShape), +} + +/// ループ / if / 将来の switch などを、共通のビューとして扱う箱だよ。 +/// +/// - `entry` : 構造に入る入口ブロック +/// - `exits` : 構造を抜けたあとのブロック群 +/// - `kind` : Loop / If などの種別ごとの Shape +#[derive(Debug, Clone)] +pub struct ControlForm { + pub entry: BasicBlockId, + pub exits: Vec, + pub kind: ControlKind, +} + +impl ControlForm { + /// ループ用 Shape から ControlForm を生成するよ。 + /// + /// ループの entry は preheader、exit は exit ブロック 1 つとみなす。 + pub fn from_loop(shape: LoopShape) -> Self { + ControlForm { + entry: shape.preheader, + exits: vec![shape.exit], + kind: ControlKind::Loop(shape), + } + } + + /// If 用 Shape から ControlForm を生成するよ。 + /// + /// If の entry は cond_block、exit は merge_block 1 つとみなす。 + pub fn from_if(shape: IfShape) -> Self { + ControlForm { + entry: shape.cond_block, + exits: vec![shape.merge_block], + kind: ControlKind::If(shape), + } + } + + /// これはループかな?という軽い判定だよ。 + pub fn is_loop(&self) -> bool { + matches!(self.kind, ControlKind::Loop(_)) + } + + /// これは if 構造かな?という軽い判定だよ。 + pub fn is_if(&self) -> bool { + matches!(self.kind, ControlKind::If(_)) + } + + /// デバッグ用に構造をダンプするよ。 + /// + /// 呼び出し側で `NYASH_CONTROL_FORM_TRACE=1` を見る想定なので、 + /// ここでは単純に eprintln! するだけにしておく。 + pub fn debug_dump(&self) { + match &self.kind { + ControlKind::Loop(shape) => { + eprintln!( + "[ControlForm::Loop] entry={:?} preheader={:?} header={:?} body={:?} latch={:?} exit={:?} continue={:?} break={:?}", + self.entry, + shape.preheader, + shape.header, + shape.body, + shape.latch, + shape.exit, + shape.continue_targets, + shape.break_targets, + ); + } + ControlKind::If(shape) => { + eprintln!( + "[ControlForm::If] entry={:?} cond={:?} then={:?} else={:?} merge={:?} exits={:?}", + self.entry, + shape.cond_block, + shape.then_block, + shape.else_block, + shape.merge_block, + self.exits, + ); + } + } + } +} + +/// ControlForm の invariant を軽く検査するための CFG 抽象だよ。 +/// +/// 実装は MirFunction などに持たせて、`debug_validate` から使う想定。 +pub trait CfgLike { + fn has_edge(&self, from: BasicBlockId, to: BasicBlockId) -> bool; + fn predecessors_len(&self, block: BasicBlockId) -> usize; +} + +impl CfgLike for MirFunction { + fn has_edge(&self, from: BasicBlockId, to: BasicBlockId) -> bool { + self.blocks + .get(&from) + .map(|bb: &BasicBlock| bb.successors.contains(&to)) + .unwrap_or(false) + } + + fn predecessors_len(&self, block: BasicBlockId) -> usize { + self.blocks + .get(&block) + .map(|bb: &BasicBlock| bb.predecessors.len()) + .unwrap_or(0) + } +} + +/// ControlForm トレース用の環境フラグを判定するヘルパーだよ。 +/// +/// - 未設定 → 既定で ON +/// - "0" / "false" → OFF +/// - それ以外 → ON +pub fn is_control_form_trace_on() -> bool { + std::env::var("NYASH_CONTROL_FORM_TRACE") + .map(|v| v != "0" && v.to_lowercase() != "false") + .unwrap_or(true) +} + +impl LoopShape { + /// Debug ビルドでだけ呼ぶ用の簡易 invariant チェックだよ。 + /// + /// - preheader → header にエッジがあること + /// - latch → header にバックエッジがあること + #[cfg(debug_assertions)] + pub fn debug_validate(&self, cfg: &C) { + debug_assert!( + cfg.has_edge(self.preheader, self.header), + "LoopShape invalid: preheader -> header edge missing: {:?} -> {:?}", + self.preheader, + self.header + ); + debug_assert!( + cfg.has_edge(self.latch, self.header), + "LoopShape invalid: latch -> header backedge missing: {:?} -> {:?}", + self.latch, + self.header + ); + } +} + +impl IfShape { + /// Debug ビルドでだけ呼ぶ用の簡易 invariant チェックだよ。 + /// + /// - cond → then / else にエッジがあること + /// - merge については、predecessor 情報がまだ配線途中のケースもあるので + /// ここでは「0 ならログだけ出す(panic しない)」ことにするよ。 + #[cfg(debug_assertions)] + pub fn debug_validate(&self, cfg: &C) { + debug_assert!( + cfg.has_edge(self.cond_block, self.then_block), + "IfShape invalid: cond -> then edge missing: {:?} -> {:?}", + self.cond_block, + self.then_block + ); + if let Some(else_blk) = self.else_block { + debug_assert!( + cfg.has_edge(self.cond_block, else_blk), + "IfShape invalid: cond -> else edge missing: {:?} -> {:?}", + self.cond_block, + else_blk + ); + } + let preds = cfg.predecessors_len(self.merge_block); + if preds == 0 && std::env::var("NYASH_CONTROL_FORM_TRACE").ok().as_deref() == Some("1") { + eprintln!( + "[ControlForm::IfShape] WARN: merge block {:?} has no predecessors yet", + self.merge_block + ); + } + } +} diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index d8632523..baa7efe0 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -6,6 +6,7 @@ */ use super::{BasicBlockId, ConstValue, MirInstruction, ValueId}; +use crate::mir::control_form::{ControlForm, IfShape, LoopShape, is_control_form_trace_on}; use crate::mir::phi_core::loop_phi::IncompletePhi; use crate::mir::phi_core::loopform_builder::{LoopFormBuilder, LoopFormOps}; use crate::ast::ASTNode; @@ -342,7 +343,6 @@ impl<'a> LoopBuilder<'a> { // Jump to latch if not already terminated let actual_latch_id = if !is_current_block_terminated(self.parent_builder)? { - let cur_body_end = self.current_block()?; self.emit_jump(latch_id)?; latch_id } else { @@ -375,6 +375,38 @@ impl<'a> LoopBuilder<'a> { // Pop loop context crate::mir::builder::loops::pop_loop_context(self.parent_builder); + // ControlForm 観測: 環境フラグ(未設定時は既定ON)のとき LoopShape をダンプ + if is_control_form_trace_on() { + // continue / break のターゲットブロックをユニーク化して収集 + use std::collections::HashSet; + let mut cont_set: HashSet = HashSet::new(); + let mut break_set: HashSet = HashSet::new(); + for (bb, _) in &self.continue_snapshots { + cont_set.insert(*bb); + } + for (bb, _) in &self.exit_snapshots { + break_set.insert(*bb); + } + let continue_targets: Vec = cont_set.into_iter().collect(); + let break_targets: Vec = break_set.into_iter().collect(); + + let loop_shape = LoopShape { + preheader: preheader_id, + header: header_id, + body: body_id, + latch: latch_id, + exit: exit_id, + continue_targets, + break_targets, + }; + let form = ControlForm::from_loop(loop_shape.clone()); + form.debug_dump(); + #[cfg(debug_assertions)] + if let Some(ref func) = self.parent_builder.current_function { + loop_shape.debug_validate(func); + } + } + // Return void value let void_dst = self.new_value(); self.emit_const(void_dst, ConstValue::Void)?; @@ -486,7 +518,7 @@ impl<'a> LoopBuilder<'a> { } // Add PHI nodes for new pinned variables in header block - for (name, value, preheader_value) in new_pinned_vars { + for (name, _value, preheader_value) in new_pinned_vars { let phi_id = self.new_value(); self.emit_phi_at_block_start(header_id, phi_id, vec![(preheader_id, preheader_value)])?; // Update variable map to use PHI value @@ -1156,6 +1188,22 @@ impl<'a> LoopBuilder<'a> { &else_var_map_end_opt, None, )?; + + // ControlForm 観測: 環境フラグ(未設定時は既定ON)のとき IfShape をダンプ + if is_control_form_trace_on() { + let if_shape = IfShape { + cond_block: pre_branch_bb, + then_block: then_bb, + else_block: Some(else_bb), + merge_block: merge_bb, + }; + let form = ControlForm::from_if(if_shape.clone()); + form.debug_dump(); + #[cfg(debug_assertions)] + if let Some(ref func) = self.parent_builder.current_function { + if_shape.debug_validate(func); + } + } let void_id = self.new_value(); self.emit_const(void_id, ConstValue::Void)?; // Pop merge debug region diff --git a/src/mir/mod.rs b/src/mir/mod.rs index 7044ec19..5c46c1e7 100644 --- a/src/mir/mod.rs +++ b/src/mir/mod.rs @@ -34,6 +34,7 @@ pub mod slot_registry; // Phase 9.79b.1: method slot resolution (IDs) pub mod value_id; pub mod verification; pub mod verification_types; // extracted error types // Optimization subpasses (e.g., type_hints) +pub mod control_form; // Phase 25.1f: Loop/If 共通ビュー(ControlForm) // Re-export main types for easy access pub use basic_block::{BasicBlock, BasicBlockId, BasicBlockIdGenerator}; diff --git a/src/mir/phi_core/if_phi.rs b/src/mir/phi_core/if_phi.rs index f515d3a5..b4c035d7 100644 --- a/src/mir/phi_core/if_phi.rs +++ b/src/mir/phi_core/if_phi.rs @@ -145,7 +145,7 @@ pub fn merge_modified_at_merge_with( ops: &mut O, merge_bb: crate::mir::BasicBlockId, _then_block: crate::mir::BasicBlockId, - else_block: crate::mir::BasicBlockId, + _else_block: crate::mir::BasicBlockId, then_pred_opt: Option, else_pred_opt: Option, pre_if_snapshot: &HashMap, diff --git a/src/mir/phi_core/loop_phi.rs b/src/mir/phi_core/loop_phi.rs index 22c0b153..afe32113 100644 --- a/src/mir/phi_core/loop_phi.rs +++ b/src/mir/phi_core/loop_phi.rs @@ -193,7 +193,7 @@ pub fn prepare_loop_variables_with( ops.emit_copy_at_preheader(preheader_id, pre_copy, value_before)?; let phi_id = ops.new_value(); - let mut inc = IncompletePhi { + let inc = IncompletePhi { phi_id, var_name: var_name.clone(), known_inputs: vec![(preheader_id, pre_copy)], // ensure def at preheader diff --git a/src/mir/verification/utils.rs b/src/mir/verification/utils.rs index 34be64c3..3e12929e 100644 --- a/src/mir/verification/utils.rs +++ b/src/mir/verification/utils.rs @@ -67,6 +67,7 @@ pub fn compute_dominators(function: &MirFunction) -> HashMap HashSet { let mut reachable = HashSet::new(); let mut worklist = vec![function.entry_block]; diff --git a/src/parser/cursor.rs b/src/parser/cursor.rs index 80dad2f5..a239e765 100644 --- a/src/parser/cursor.rs +++ b/src/parser/cursor.rs @@ -43,6 +43,7 @@ impl<'a> TokenCursor<'a> { } /// 次のトークンをピーク + #[allow(dead_code)] pub fn peek(&self) -> &Token { self.tokens.get(self.idx + 1).unwrap_or(&Token { token_type: TokenType::EOF, @@ -52,6 +53,7 @@ impl<'a> TokenCursor<'a> { } /// N番目のトークンをピーク + #[allow(dead_code)] pub fn peek_nth(&self, n: usize) -> &Token { self.tokens.get(self.idx + n).unwrap_or(&Token { token_type: TokenType::EOF, @@ -220,11 +222,13 @@ impl<'a> TokenCursor<'a> { } /// モードを取得 + #[allow(dead_code)] pub fn get_mode(&self) -> NewlineMode { self.mode } /// モードを設定 + #[allow(dead_code)] pub fn set_mode(&mut self, mode: NewlineMode) { self.mode = mode; } @@ -294,4 +298,4 @@ mod tests { assert!(c.match_token(&TokenType::PLUS)); }); } -} \ No newline at end of file +} diff --git a/src/parser/statements/helpers.rs b/src/parser/statements/helpers.rs index ec0a6146..78b01acc 100644 --- a/src/parser/statements/helpers.rs +++ b/src/parser/statements/helpers.rs @@ -59,6 +59,7 @@ impl NyashParser { } /// Small helper: build UnexpectedToken with current token and line + #[allow(dead_code)] pub(super) fn err_unexpected>(&self, expected: S) -> ParseError { ParseError::UnexpectedToken { found: self.current_token().token_type.clone(), @@ -68,6 +69,7 @@ impl NyashParser { } /// Expect an identifier and advance. Returns its string or an UnexpectedToken error + #[allow(dead_code)] pub(super) fn expect_identifier(&mut self, what: &str) -> Result { if let TokenType::IDENTIFIER(name) = &self.current_token().token_type { let out = name.clone(); @@ -77,4 +79,4 @@ impl NyashParser { Err(self.err_unexpected(what)) } } -} \ No newline at end of file +} diff --git a/src/parser/statements/mod.rs b/src/parser/statements/mod.rs index 94b1f398..708b527b 100644 --- a/src/parser/statements/mod.rs +++ b/src/parser/statements/mod.rs @@ -131,7 +131,7 @@ impl NyashParser { let mut statements = Vec::new(); // Helper: lookahead for `ident '(' ... ')' [NEWLINE*] '{'` - let mut looks_like_method_head = |this: &Self| -> bool { + let looks_like_method_head = |this: &Self| -> bool { // Only meaningful when starting at a new statement head match &this.current_token().token_type { TokenType::IDENTIFIER(_) => { diff --git a/src/runner/child_env.rs b/src/runner/child_env.rs index b0cc2185..f9f1202c 100644 --- a/src/runner/child_env.rs +++ b/src/runner/child_env.rs @@ -8,6 +8,7 @@ pub fn pre_run_reset_oob_if_strict() { } } +#[allow(dead_code)] pub fn post_run_exit_if_oob_strict_triggered() -> ! { if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() { eprintln!("[gate-c][oob-strict] Out-of-bounds observed → exit(1)"); diff --git a/src/runner/demos.rs b/src/runner/demos.rs index 8aefff19..1a783113 100644 --- a/src/runner/demos.rs +++ b/src/runner/demos.rs @@ -90,6 +90,7 @@ pub(super) fn demo_parser_system() { } } +#[allow(dead_code)] pub(super) fn demo_interpreter_system() { println!("\n🎭 7. Interpreter System:"); println!(" ⚠️ Legacy interpreter removed - use VM or LLVM backends instead"); diff --git a/src/runner/hv1_inline.rs b/src/runner/hv1_inline.rs index 78f13c4e..5bbc0a85 100644 --- a/src/runner/hv1_inline.rs +++ b/src/runner/hv1_inline.rs @@ -129,18 +129,17 @@ pub fn run_json_v1_inline(json: &str) -> i32 { let sval = regs.get(&src).cloned(); let is_integer = sval.is_some(); // hv1 inline stores i64 only → integer - let mut out = 0i64; if operation == "check" || operation == "is" { - if target == "i64" || target == "int" || target == "integer" { - out = if is_integer { 1 } else { 0 }; + let out: i64 = if target == "i64" || target == "int" || target == "integer" { + if is_integer { 1 } else { 0 } } else if target == "bool" { // Inline model uses integer registers; treat 0/1 as bool when present - out = if let Some(v) = sval { if v == 0 || v == 1 { 1 } else { 0 } } else { 0 }; + if let Some(v) = sval { if v == 0 || v == 1 { 1 } else { 0 } } else { 0 } } else if target == "string" { - out = 0; // no string registers in inline model + 0 // no string registers in inline model } else { - out = 0; - } + 0 + }; regs.insert(dst, out); } else { // cast/as: pass-through (MVP) diff --git a/src/runner/json_v0_bridge/lowering.rs b/src/runner/json_v0_bridge/lowering.rs index 886b311c..009779da 100644 --- a/src/runner/json_v0_bridge/lowering.rs +++ b/src/runner/json_v0_bridge/lowering.rs @@ -2,7 +2,7 @@ use super::ast::{ProgramV0, StmtV0, ExprV0}; use crate::mir::Callee; use crate::mir::{ BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction, MirInstruction, MirModule, - MirPrinter, MirType, ValueId, BinaryOp, + MirPrinter, MirType, ValueId, }; use std::collections::HashMap; use std::cell::RefCell; @@ -103,6 +103,7 @@ pub(super) struct BridgeEnv { } impl BridgeEnv { + #[allow(dead_code)] pub(super) fn load() -> Self { Self::with_imports(HashMap::new()) } diff --git a/src/runner/json_v0_bridge/lowering/expr.rs b/src/runner/json_v0_bridge/lowering/expr.rs index b0065b60..dc22ad64 100644 --- a/src/runner/json_v0_bridge/lowering/expr.rs +++ b/src/runner/json_v0_bridge/lowering/expr.rs @@ -3,7 +3,7 @@ use super::BridgeEnv; use super::ternary; use super::match_expr; use crate::mir::{ - BasicBlockId, BinaryOp, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId, + BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId, }; use std::collections::HashMap; diff --git a/src/runner/json_v0_bridge/lowering/if_else.rs b/src/runner/json_v0_bridge/lowering/if_else.rs index f0d356a6..1a121cd3 100644 --- a/src/runner/json_v0_bridge/lowering/if_else.rs +++ b/src/runner/json_v0_bridge/lowering/if_else.rs @@ -1,5 +1,5 @@ use super::{lower_stmt_list_with_vars, merge_var_maps, new_block, BridgeEnv, LoopContext}; -use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; +use crate::mir::{BasicBlockId, MirFunction, ValueId}; use std::collections::HashMap; use super::super::ast::StmtV0; use super::super::ast::ExprV0; diff --git a/src/runner/json_v0_bridge/lowering/ternary.rs b/src/runner/json_v0_bridge/lowering/ternary.rs index c5a8212f..7cabe222 100644 --- a/src/runner/json_v0_bridge/lowering/ternary.rs +++ b/src/runner/json_v0_bridge/lowering/ternary.rs @@ -5,7 +5,7 @@ use super::merge::new_block; use super::BridgeEnv; -use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; +use crate::mir::{BasicBlockId, MirFunction, ValueId}; use super::super::ast::ExprV0; use super::expr::{lower_expr_with_scope, VarScope}; @@ -35,7 +35,7 @@ pub(super) fn lower_ternary_expr_with_scope( } let out = f.next_value_id(); // フェーズM.2: PHI統一処理(no_phi分岐削除) - let mut inputs = vec![(tend, tval), (eend, eval)]; + let inputs = vec![(tend, tval), (eend, eval)]; crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs); Ok((out, merge_bb)) } diff --git a/src/runner/json_v0_bridge/lowering/throw_ctx.rs b/src/runner/json_v0_bridge/lowering/throw_ctx.rs index 667544d6..d00f4653 100644 --- a/src/runner/json_v0_bridge/lowering/throw_ctx.rs +++ b/src/runner/json_v0_bridge/lowering/throw_ctx.rs @@ -1,4 +1,4 @@ -use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId}; +use crate::mir::{BasicBlockId, MirFunction, ValueId}; use std::cell::RefCell; thread_local! { diff --git a/src/runner/json_v1_bridge.rs b/src/runner/json_v1_bridge.rs index 5751cbfd..8c72dd4f 100644 --- a/src/runner/json_v1_bridge.rs +++ b/src/runner/json_v1_bridge.rs @@ -511,27 +511,6 @@ pub fn try_parse_v1_to_module(json: &str) -> Result, String> { if let Some(d) = dst_opt { max_value_id = max_value_id.max(d.as_u32() + 1); } } } - "Constructor" => { - // box_type: string, dst: required - let dst = dst_opt.ok_or_else(|| format!( - "mir_call Constructor requires dst in function '{}'", - func_name - ))?; - let bt = callee_obj - .get("box_type") - .and_then(Value::as_str) - .ok_or_else(|| format!( - "mir_call Constructor missing box_type in function '{}'", - func_name - ))? - .to_string(); - block_ref.add_instruction(MirInstruction::NewBox { - dst, - box_type: bt, - args: argv.clone(), - }); - max_value_id = max_value_id.max(dst.as_u32() + 1); - } "Extern" => { let name = callee_obj .get("name") diff --git a/src/runner/mir_json_emit.rs b/src/runner/mir_json_emit.rs index 3a4c47ce..b428bde6 100644 --- a/src/runner/mir_json_emit.rs +++ b/src/runner/mir_json_emit.rs @@ -31,6 +31,7 @@ fn create_json_v1_root(functions: serde_json::Value) -> serde_json::Value { /// Helper: detect residual numeric-core boxcalls that should have been lowered by AotPrepNumericCoreBox. /// Currently we only check for `boxcall` with `method:"mul_naive"` which should become /// `call("NyNumericMatI64.mul_naive", ...)` when NYASH_AOT_NUMERIC_CORE=1 is effective. +#[allow(dead_code)] fn has_numeric_core_boxcall(root: &serde_json::Value) -> bool { let funs = match root.get("functions") { Some(v) => v.as_array().cloned().unwrap_or_default(), @@ -61,6 +62,7 @@ fn has_numeric_core_boxcall(root: &serde_json::Value) -> bool { /// Helper: enforce numeric_core invariants when NYASH_AOT_NUMERIC_CORE=1 is set. /// - Default: emit a warning if mul_naive boxcalls are still present. /// - Strict: if NYASH_AOT_NUMERIC_CORE_STRICT=1, return Err to fail fast. +#[allow(dead_code)] fn check_numeric_core_invariants(root: &serde_json::Value) -> Result<(), String> { let numeric_on = matches!(std::env::var("NYASH_AOT_NUMERIC_CORE").ok().as_deref(), Some("1")); if !numeric_on { diff --git a/src/runner/modes/common_util/plugin_guard.rs b/src/runner/modes/common_util/plugin_guard.rs index f9007188..21b66454 100644 --- a/src/runner/modes/common_util/plugin_guard.rs +++ b/src/runner/modes/common_util/plugin_guard.rs @@ -22,7 +22,7 @@ pub fn gather_required_providers() -> Vec { return v; } // Default conservative set - let mut v = vec![ + let v = vec![ "FileBox".to_string(), "ConsoleBox".to_string(), "ArrayBox".to_string(), @@ -86,4 +86,3 @@ pub fn check_and_report(strict: bool, quiet_pipe: bool, label: &str) { } } } - diff --git a/src/runner/modes/common_util/resolve/prelude_manager.rs b/src/runner/modes/common_util/resolve/prelude_manager.rs index 068c234e..bed6f3fa 100644 --- a/src/runner/modes/common_util/resolve/prelude_manager.rs +++ b/src/runner/modes/common_util/resolve/prelude_manager.rs @@ -111,7 +111,7 @@ impl<'a> PreludeManagerBox<'a> { fn build_text_merged( &self, source: &str, - filename: &str, + _filename: &str, prelude_paths: &[String], trace: bool, ) -> Result { @@ -123,7 +123,7 @@ impl<'a> PreludeManagerBox<'a> { .map_err(|e| format!("using: failed to read '{}': {}", path, e))?; // using行を除去して正規化 - let using_resolver = UsingResolutionBox::new(&self.runner, path)?; + let _using_resolver = UsingResolutionBox::new(&self.runner, path)?; let (cleaned_raw, _nested) = self.collect_using_and_strip_internal(&content, path)?; let cleaned = self.normalize_text_for_inline(&cleaned_raw); diff --git a/src/runner/modes/common_util/resolve/selfhost_pipeline.rs b/src/runner/modes/common_util/resolve/selfhost_pipeline.rs index 04406383..9f1e2477 100644 --- a/src/runner/modes/common_util/resolve/selfhost_pipeline.rs +++ b/src/runner/modes/common_util/resolve/selfhost_pipeline.rs @@ -129,7 +129,7 @@ impl<'a> SelfhostPipelineBox<'a> { &self, error: &str, original_code: &str, - filename: &str, + _filename: &str, ) -> CompilationResult { eprintln!("[selfhost-pipeline] ⚠️ Error: {}", error); eprintln!("[selfhost-pipeline] 🔄 Falling back to original code"); @@ -179,8 +179,8 @@ impl<'a> SelfhostPipelineBox<'a> { /// 📊 パフォーマンスプロファイリングするにゃ! pub fn profile_pipeline( &mut self, - code: &str, - filename: &str, + _code: &str, + _filename: &str, ) -> Result { // プロファイル機能を実装(別途) // TODO: プロファイル機能を追加 diff --git a/src/runner/modes/common_util/resolve/strip.rs b/src/runner/modes/common_util/resolve/strip.rs index 99ce04bd..70e5730e 100644 --- a/src/runner/modes/common_util/resolve/strip.rs +++ b/src/runner/modes/common_util/resolve/strip.rs @@ -448,7 +448,7 @@ pub fn resolve_prelude_paths_profiled( // must be discovered so that their definitions are present at runtime // (e.g., runner_min -> lower_* boxes). Previously this only ran when // NYASH_USING_AST=1, which caused unresolved calls in inline flows. - let ast_on = crate::config::env::env_bool("NYASH_USING_AST"); + let _ast_on = crate::config::env::env_bool("NYASH_USING_AST"); let mut out: Vec = Vec::new(); let mut seen: std::collections::HashSet = std::collections::HashSet::new(); fn normalize_path(path: &str) -> (String, String) { diff --git a/src/runner/modes/common_util/resolve/using_resolution.rs b/src/runner/modes/common_util/resolve/using_resolution.rs index 2c48355f..d1aa9674 100644 --- a/src/runner/modes/common_util/resolve/using_resolution.rs +++ b/src/runner/modes/common_util/resolve/using_resolution.rs @@ -14,6 +14,7 @@ pub struct UsingResolutionBox<'a> { runner: &'a NyashRunner, config: UsingConfig, ctx_dir: Option, + #[allow(dead_code)] filename_canon: Option, inside_pkg: bool, seen_paths: HashMap, // canon_path -> (alias/label, first_line) diff --git a/src/runner/modes/vm.rs b/src/runner/modes/vm.rs index 061c8bca..88866fb0 100644 --- a/src/runner/modes/vm.rs +++ b/src/runner/modes/vm.rs @@ -476,7 +476,7 @@ impl NyashRunner { match vm.execute_module(&module_vm) { Ok(ret) => { - use crate::box_trait::{NyashBox, IntegerBox, BoolBox}; + use crate::box_trait::{IntegerBox, BoolBox}; // Extract exit code from return value let exit_code = if let Some(ib) = ret.as_any().downcast_ref::() { diff --git a/src/runner/modes/vm_fallback.rs b/src/runner/modes/vm_fallback.rs index 50c4b983..65f90553 100644 --- a/src/runner/modes/vm_fallback.rs +++ b/src/runner/modes/vm_fallback.rs @@ -321,7 +321,7 @@ impl NyashRunner { } match vm.execute_module(&module_vm) { Ok(ret) => { - use crate::box_trait::{NyashBox, IntegerBox, BoolBox}; + use crate::box_trait::{IntegerBox, BoolBox}; // Extract exit code from return value let exit_code = if let Some(ib) = ret.as_any().downcast_ref::() { @@ -346,7 +346,8 @@ impl NyashRunner { impl NyashRunner { /// Small helper to continue fallback execution once AST is prepared - fn execute_vm_fallback_from_ast(&self, filename: &str, ast: nyash_rust::ast::ASTNode) { + #[allow(dead_code)] + fn execute_vm_fallback_from_ast(&self, _filename: &str, ast: nyash_rust::ast::ASTNode) { use crate::{ backend::MirInterpreter, box_factory::{BoxFactory, RuntimeError}, diff --git a/src/runner/pipe_io.rs b/src/runner/pipe_io.rs index 68618c4f..57ca5a63 100644 --- a/src/runner/pipe_io.rs +++ b/src/runner/pipe_io.rs @@ -10,7 +10,6 @@ */ use super::*; -use crate::runner::child_env; impl NyashRunner { /// Try to handle `--ny-parser-pipe` / `--json-file` flow. @@ -20,7 +19,7 @@ impl NyashRunner { if !(groups.parser.ny_parser_pipe || groups.parser.json_file.is_some()) { return false; } - let mut json = if let Some(path) = &groups.parser.json_file { + let json = if let Some(path) = &groups.parser.json_file { match std::fs::read_to_string(path) { Ok(s) => s, Err(e) => { diff --git a/src/runner/pipeline.rs b/src/runner/pipeline.rs index afa42420..abba1630 100644 --- a/src/runner/pipeline.rs +++ b/src/runner/pipeline.rs @@ -84,6 +84,7 @@ impl NyashRunner { } /// Suggest candidate files by leaf name within limited bases (apps/lib/.) +#[allow(dead_code)] pub(super) fn suggest_in_base(base: &str, leaf: &str, out: &mut Vec) { use std::fs; fn walk(dir: &std::path::Path, leaf: &str, out: &mut Vec, depth: usize) { diff --git a/src/runner/plugins.rs b/src/runner/plugins.rs index 56bfd5e3..c71c47b3 100644 --- a/src/runner/plugins.rs +++ b/src/runner/plugins.rs @@ -58,7 +58,7 @@ impl NyashRunner { for p in list { if list_only { println!(" • {}", p); continue; } match std::fs::read_to_string(&p) { - Ok(code) => { + Ok(_code) => { // Legacy interpreter removed - ny_plugins execution disabled println!("[ny_plugins] {}: SKIP (legacy interpreter removed)", p); } diff --git a/src/runner/selfhost.rs b/src/runner/selfhost.rs index 088b0dd6..93d8fcdf 100644 --- a/src/runner/selfhost.rs +++ b/src/runner/selfhost.rs @@ -403,21 +403,22 @@ impl NyashRunner { // パイプライン(tools/ny_selfhost_inline.sh など)を使う想定とし、ここでは常に Rust 既定 // パスへフォールバックする。 crate::cli_v!("[ny-compiler] inline selfhost pipeline disabled (Phase 25.1b); falling back to default path"); - return false; - match super::json_v0_bridge::parse_json_v0_to_module("") { - Ok(module) => { - if crate::config::env::cli_verbose() { + // Dev-only escape hatch: allow forcing the old inline path when explicitly requested. + if std::env::var("NYASH_SELFHOST_INLINE_FORCE").ok().as_deref() == Some("1") { + match super::json_v0_bridge::parse_json_v0_to_module("") { + Ok(module) => { if crate::config::env::cli_verbose() { - super::json_v0_bridge::maybe_dump_mir(&module); + if crate::config::env::cli_verbose() { + super::json_v0_bridge::maybe_dump_mir(&module); + } + } + let emit_only = std::env::var("NYASH_NY_COMPILER_EMIT_ONLY") + .unwrap_or_else(|_| "1".to_string()) + == "1"; + if emit_only { + return false; } - } - let emit_only = std::env::var("NYASH_NY_COMPILER_EMIT_ONLY") - .unwrap_or_else(|_| "1".to_string()) - == "1"; - if emit_only { - return false; - } // Phase-15 policy: when NYASH_VM_USE_PY=1, prefer PyVM as reference executor // regardless of BoxCall presence to ensure semantics parity (e.g., PHI merges). let prefer_pyvm = std::env::var("NYASH_VM_USE_PY").ok().as_deref() == Some("1"); @@ -430,25 +431,29 @@ impl NyashRunner { }) }) }); - if prefer_pyvm || needs_pyvm { - let label = if prefer_pyvm { "selfhost" } else { "selfhost-fallback" }; - if let Some(code) = crate::runner::modes::common_util::selfhost::json::run_pyvm_module(&module, label) { - println!("Result: {}", code); - std::process::exit(code); + if prefer_pyvm || needs_pyvm { + let label = if prefer_pyvm { "selfhost" } else { "selfhost-fallback" }; + if let Some(code) = crate::runner::modes::common_util::selfhost::json::run_pyvm_module(&module, label) { + println!("Result: {}", code); + std::process::exit(code); + } } + crate::runner::child_env::pre_run_reset_oob_if_strict(); + self.execute_mir_module(&module); + if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() { + eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)"); + std::process::exit(1); + } + return true; } - crate::runner::child_env::pre_run_reset_oob_if_strict(); - self.execute_mir_module(&module); - if crate::config::env::oob_strict_fail() && crate::runtime::observe::oob_seen() { - eprintln!("[selfhost][oob-strict] Out-of-bounds observed → exit(1)"); - std::process::exit(1); + Err(e) => { + eprintln!("❌ JSON v0 bridge error: {}", e); + return false; } - true - } - Err(e) => { - eprintln!("❌ JSON v0 bridge error: {}", e); - false } } + + // Default path: always fall back to existing Rust runner. + return false; } } diff --git a/src/runtime/plugin_loader_v2/enabled/loader/config.rs b/src/runtime/plugin_loader_v2/enabled/loader/config.rs index e5628ef2..92c2897b 100644 --- a/src/runtime/plugin_loader_v2/enabled/loader/config.rs +++ b/src/runtime/plugin_loader_v2/enabled/loader/config.rs @@ -1,4 +1,3 @@ -use super::library; use super::PluginLoaderV2; use crate::bid::{BidError, BidResult}; diff --git a/src/runtime/plugin_loader_v2/enabled/loader/mod.rs b/src/runtime/plugin_loader_v2/enabled/loader/mod.rs index f5933989..4ebe1c4b 100644 --- a/src/runtime/plugin_loader_v2/enabled/loader/mod.rs +++ b/src/runtime/plugin_loader_v2/enabled/loader/mod.rs @@ -6,8 +6,8 @@ mod specs; mod util; use super::host_bridge::BoxInvokeFn; -use super::types::{LoadedPluginV2, PluginBoxMetadata, PluginBoxV2, PluginHandleInner}; -use crate::bid::{BidError, BidResult}; +use super::types::{LoadedPluginV2, PluginBoxMetadata, PluginHandleInner}; +use crate::bid::BidResult; use crate::box_trait::NyashBox; use crate::config::nyash_toml_v2::{LibraryDefinition, NyashConfigV2}; use specs::LoadedBoxSpec; diff --git a/src/runtime/plugin_loader_v2/enabled/loader/singletons.rs b/src/runtime/plugin_loader_v2/enabled/loader/singletons.rs index 8055cde3..47e21414 100644 --- a/src/runtime/plugin_loader_v2/enabled/loader/singletons.rs +++ b/src/runtime/plugin_loader_v2/enabled/loader/singletons.rs @@ -1,4 +1,3 @@ -use super::specs; use super::PluginLoaderV2; use crate::bid::{BidError, BidResult}; use crate::runtime::plugin_loader_v2::enabled::{errors, host_bridge, types}; diff --git a/src/runtime/plugin_loader_v2/enabled/loader/specs.rs b/src/runtime/plugin_loader_v2/enabled/loader/specs.rs index 8026ce9c..eba0389c 100644 --- a/src/runtime/plugin_loader_v2/enabled/loader/specs.rs +++ b/src/runtime/plugin_loader_v2/enabled/loader/specs.rs @@ -18,6 +18,7 @@ pub(crate) struct LoadedBoxSpec { #[derive(Debug, Clone, Copy)] pub(crate) struct MethodSpec { pub(crate) method_id: u32, + #[allow(dead_code)] pub(crate) returns_result: bool, } diff --git a/src/runtime/plugin_loader_v2/enabled/method_resolver.rs b/src/runtime/plugin_loader_v2/enabled/method_resolver.rs index 69b7a79e..19cc06b5 100644 --- a/src/runtime/plugin_loader_v2/enabled/method_resolver.rs +++ b/src/runtime/plugin_loader_v2/enabled/method_resolver.rs @@ -5,7 +5,6 @@ use crate::bid::{BidError, BidResult}; use crate::runtime::plugin_loader_v2::enabled::PluginLoaderV2; -use std::collections::HashMap; impl PluginLoaderV2 { /// Resolve a method ID for a given box type and method name @@ -37,7 +36,7 @@ impl PluginLoaderV2 { // Fallback to TypeBox FFI spec if let Ok(map) = self.box_specs.read() { // Try direct lookup first - for ((lib, bt), spec) in map.iter() { + for ((_lib, bt), spec) in map.iter() { if bt == box_type { // Check methods map if let Some(ms) = spec.methods.get(method_name) { @@ -47,7 +46,7 @@ impl PluginLoaderV2 { // Try resolve function if let Some(res_fn) = spec.resolve_fn { if let Ok(cstr) = std::ffi::CString::new(method_name) { - let mid = unsafe { res_fn(cstr.as_ptr()) }; + let mid = res_fn(cstr.as_ptr()); if mid != 0 { return Ok(mid); } @@ -130,11 +129,13 @@ impl PluginLoaderV2 { } /// Helper functions for method resolution +#[allow(dead_code)] pub(super) fn is_special_method(method_name: &str) -> bool { matches!(method_name, "birth" | "fini" | "toString") } /// Get default method IDs for special methods +#[allow(dead_code)] pub(super) fn get_special_method_id(method_name: &str) -> Option { match method_name { "birth" => Some(1), diff --git a/src/runtime/unified_registry.rs b/src/runtime/unified_registry.rs index b6600ddb..2b9c5053 100644 --- a/src/runtime/unified_registry.rs +++ b/src/runtime/unified_registry.rs @@ -8,7 +8,7 @@ use crate::box_factory::builtin::BuiltinBoxFactory; #[cfg(feature = "plugins")] use crate::box_factory::plugin::PluginBoxFactory; -use crate::box_factory::{UnifiedBoxRegistry, FactoryPolicy}; +use crate::box_factory::UnifiedBoxRegistry; use std::sync::{Arc, Mutex, OnceLock}; /// Global registry instance