Files
hakorune/docs/development/roadmap/phases/phase-25.1m/README.md
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

109 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 時点)
- 再現(簡易例):
```hako
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 で扱っていた 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_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` のテストで確認する。
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 エラーが、新規テスト群で再現しないこと。