Files
hakorune/docs/development/roadmap/phases/phase-25.1m
nyash-codex a95fedf26a fix(mir): Phase 25.1m - Continue PHI修正 & Bug A main(args)ループ修正
**Phase 25.1m: Continue PHI修正**
- seal_phis に continue_snapshots 入力を追加 (loopform_builder.rs)
- LoopShape::debug_validate に continue/break エッジ検証追加 (control_form.rs)
- test_seal_phis_includes_continue_snapshots テスト追加
- 実証テスト成功: balanced scan loop で 228回イテレーション確認

**Bug A修正: main(args) でループ未実行問題**
- LoopBuilder::build_loop で entry → preheader への jump 追加
- decls.rs でデュアル関数作成時のブロック接続修正
- mir_static_main_args_loop.rs テスト追加

**パーサー改善**:
- parser_box.hako に HAKO_PARSER_PROG_MAX ガード追加(無限ループ対策)

🎉 成果:
- Continue 文の PHI predecessor mismatch エラー完全解消
- main(args) パラメータ有りループが正常動作
- Stage-B balanced scan で continue 正常動作確認 (228回イテレーション)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 08:04:43 +09:00
..

Phase 25.1m — Static Method / VM Param Semantics Bugfix

Status: planningRust 側の暗黙レシーバ問題を切り出したバグ修正フェーズ)

ゴール

  • Rust MIR/VM 層に残っている「静的メソッド呼び出し時の引数ずれ/暗黙レシーバ」問題を解消し、
    StageB / Stage1 / selfhost / Dev トレースTraceBox 系)がすべて 同じ呼び出し規約で動くようにする。
  • 具体的には:
    • static box Foo { method bar(x){...} } に対して
      • 呼び出し: Foo.bar("HELLO")
      • VM 内部: params.len() == 1、args 1 本 → bar の唯一の引数に "HELLO" が入る
    • 「暗黙の receiver仮想 me」を静的メソッドにだけ特別扱いしない設計に戻す。

現状の症状2025-11-18 時点)

  • 再現(簡易例):
    static box TraceTest {
      method log(label){
        if label == null { print("label=NULL") }
        else { print("label=\"\" + label") }
      }
    }
    
    static box Main {
      method main(args){
        TraceTest.log("HELLO")
        return 0
      }
    }
    
    • 期待: label=HELLO
    • 実際: label=NULL
  • 原因の一次切り分け:
    • MirFunction::new が「名前に '.' を含み、かつ第 1 パラメータ型が Box でない関数」を「静的メソッド with 暗黙 receiver」とみなし、
      • signature.params.len() = 1label)でも total_value_ids = 2 を予約して params = [%0, %1] を組み立てている。
    • VM 側の exec_function_innerargs をそのまま func.params に 1:1 でバインドするため:
      • args = ["HELLO"]
      • %0"HELLO"(暗黙 receiver
      • %1Void(足りない分が Void 埋め) → label に null が入る。
    • その結果:
      • 静的メソッドに文字列リテラルを直接渡すと label が null 化される。
      • 25.1d/e で扱っていた Stage1 UsingResolver 系テスト(collect_entries/1)でも、
        %0 / %1 の扱いに由来する SSA 破綻が見えていた(現在は LoopForm v2/Conservative PHI 側で多くを解消済みだが、根底の呼び出し規約はまだ歪なまま)。

スコープ25.1m でやること)

  1. 呼び出し規約の SSOT を決める

    • 原則:
      • インスタンスメソッド: prepare_method_signature 側で me を明示的に第 1 パラメータに含める。
      • 静的メソッド / Global 関数: signature.params は「実引数と 1:1」のみ。暗黙レシーバを追加しない。
    • 影響範囲の調査:
      • MirFunction::new の param reservation ロジック(暗黙 receiver 判定と total_value_ids 計算)。
      • emit_unified_call / CalleeResolverBox の Method/Global 判定と receiver 差し込み。
      • VM 側 exec_function_inner の args バインドここは既に「params と args を 1:1」としているので、なるべく触らない
  2. 静的メソッドまわりの SSA/テストの洗い出し

    • 代表ケース:
      • src/tests/mir_stage1_using_resolver_verify.rs 内の
        mir_stage1_using_resolver_full_collect_entries_verifiesStage1UsingResolverFull.collect_entries/1 を静的メソッドとして使うテスト)。
      • Dev 用トレース箱(今回の StageBTraceBox / 既存の TraceTest 相当)。
    • 25.1m では:
      • まず trace_param_bug.hako 相当のミニテスト(静的メソッド + 1 引数)を Rust 側にユニットテストとして追加し、
        Bugfix 前後で「label に null が入らない」ことを固定する。
      • 次に Stage1UsingResolverFull.collect_entries/1 を LoopForm v2 経路込みで通し、
        %0 / %1 の ValueId 割り当てと PHI が健全であることを MirVerifier のテストで確認する。
  3. 実装方針(高レベル)

    • MirFunction::new:
      • 暗黙 receiver 判定を段階縮小し、最終的には「インスタンスメソッドのみ MirType::Box(_) を用いた明示的 receiver」に統一。
      • 静的メソッド(static box Foo { method bar(x){...} })は signature.params == [Unknown] のみを予約対象にし、
        追加の receiver_count を持たない設計に戻す。
    • emit_unified_call:
      • Method call のみ receiver を args に足す (args_local.insert(0, recv))、Global/static 呼び出しでは一切いじらない。
    • exec_function_inner:
      • 現状の「params[] と args[] を 1:1 でバインドする」実装を前提として保ち、
        呼び出し規約の側MIR builder 側)で整合を取る。

非スコープ25.1m でやらないこと)

  • 言語仕様の変更:
    • Hako/Nyash の静的メソッド構文 (static box / method) 自体は変更しない。
  • StageB / Stage1 CLI の構造タスク:
    • StageB body 抽出bundle/usingRegionBox 観測は 25.1c のスコープに残す。
  • VM 命令や Box 実装の追加:
    • 25 フェーズのポリシーに従い、新しい命令・Box 機能は追加しない(既存の呼び出し規約を整えるだけ)。

関連フェーズとの関係

  • Phase 25.1d/e/g/k/l:
    • Rust MIR 側の SSA/PHI特に LoopForm v2 + Conservative PHIと Region 観測レイヤは、静的メソッドを含む多くのケースで安定している。
    • 25.1m はその上に残った「呼び出し規約レベルの歪み」を片付けるフェーズ。
  • Phase 25.1c:
    • StageB / Stage1 CLI 側の構造デバッグRegionBox 的な観測、StageBArgs/BodyExtractor/Driver 分解)に専念。
    • StageBTraceBox は既にインスタンス box 化しており、静的メソッドのバグを踏まないようにしてある。
    • 25.1m で静的メソッド呼び出し規約が直れば、将来的に Trace 系 Box を static 化することも再検討できる。

受け入れ条件25.1m

  • 新規ユニットテスト:
    • 簡易 TraceTest静的メソッド + 文字列引数)の MIR/VM 実行が label=HELLO となること。
    • mir_stage1_using_resolver_full_collect_entries_verifies が LoopForm v2 経路で緑のまま(または改善)であること。
  • 既存の StageB / selfhost / 数値系テスト:
    • 25.1c までに整えた StageB / selfhost ラインの canaryfib defs / CLI runが、25.1m の変更で悪化していないこと。
  • 挙動の安定:
    • 静的メソッド呼び出しに関する「引数が null になる」「ValueId %0 が未定義になる」といった VM エラーが、新規テスト群で再現しないこと。