**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>
Phase 25.1m — Static Method / VM Param Semantics Bugfix
Status: planning(Rust 側の暗黙レシーバ問題を切り出したバグ修正フェーズ)
ゴール
- Rust MIR/VM 層に残っている「静的メソッド呼び出し時の引数ずれ/暗黙レシーバ」問題を解消し、
Stage‑B / Stage‑1 / 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() = 1(label)でもtotal_value_ids = 2を予約してparams = [%0, %1]を組み立てている。
- VM 側の
exec_function_innerはargsをそのままfunc.paramsに 1:1 でバインドするため:args = ["HELLO"]%0←"HELLO"(暗黙 receiver)%1←Void(足りない分が Void 埋め) →labelに null が入る。
- その結果:
- 静的メソッドに文字列リテラルを直接渡すと label が null 化される。
- 25.1d/e で扱っていた Stage‑1 UsingResolver 系テスト(
collect_entries/1)でも、
%0/%1の扱いに由来する SSA 破綻が見えていた(現在は LoopForm v2/Conservative PHI 側で多くを解消済みだが、根底の呼び出し規約はまだ歪なまま)。
スコープ(25.1m でやること)
-
呼び出し規約の 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」としているので、なるべく触らない)。
- 原則:
-
静的メソッドまわりの SSA/テストの洗い出し
- 代表ケース:
src/tests/mir_stage1_using_resolver_verify.rs内の
mir_stage1_using_resolver_full_collect_entries_verifies(Stage1UsingResolverFull.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のテストで確認する。
- まず
- 代表ケース:
-
実装方針(高レベル)
MirFunction::new:- 暗黙 receiver 判定を段階縮小し、最終的には「インスタンスメソッドのみ
MirType::Box(_)を用いた明示的 receiver」に統一。 - 静的メソッド(
static box Foo { method bar(x){...} })はsignature.params == [Unknown]のみを予約対象にし、
追加のreceiver_countを持たない設計に戻す。
- 暗黙 receiver 判定を段階縮小し、最終的には「インスタンスメソッドのみ
emit_unified_call:- Method call のみ receiver を args に足す (
args_local.insert(0, recv))、Global/static 呼び出しでは一切いじらない。
- Method call のみ receiver を args に足す (
exec_function_inner:- 現状の「params[] と args[] を 1:1 でバインドする」実装を前提として保ち、
呼び出し規約の側(MIR builder 側)で整合を取る。
- 現状の「params[] と args[] を 1:1 でバインドする」実装を前提として保ち、
非スコープ(25.1m でやらないこと)
- 言語仕様の変更:
- Hako/Nyash の静的メソッド構文 (
static box/method) 自体は変更しない。
- Hako/Nyash の静的メソッド構文 (
- Stage‑B / Stage‑1 CLI の構造タスク:
- Stage‑B body 抽出/bundle/using/RegionBox 観測は 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:
- Stage‑B / Stage‑1 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 経路で緑のまま(または改善)であること。
- 簡易 TraceTest(静的メソッド + 文字列引数)の MIR/VM 実行が
- 既存の Stage‑B / selfhost / 数値系テスト:
- 25.1c までに整えた Stage‑B / selfhost ラインの canary(fib defs / CLI run)が、25.1m の変更で悪化していないこと。
- 挙動の安定:
- 静的メソッド呼び出しに関する「引数が null になる」「ValueId %0 が未定義になる」といった VM エラーが、新規テスト群で再現しないこと。