109 lines
6.5 KiB
Markdown
109 lines
6.5 KiB
Markdown
|
|
# 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 時点)
|
|||
|
|
|
|||
|
|
- 再現(簡易例):
|
|||
|
|
```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 で扱っていた Stage‑1 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`) 自体は変更しない。
|
|||
|
|
- 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 経路で緑のまま(または改善)であること。
|
|||
|
|
- 既存の Stage‑B / selfhost / 数値系テスト:
|
|||
|
|
- 25.1c までに整えた Stage‑B / selfhost ラインの canary(fib defs / CLI run)が、25.1m の変更で悪化していないこと。
|
|||
|
|
- 挙動の安定:
|
|||
|
|
- 静的メソッド呼び出しに関する「引数が null になる」「ValueId %0 が未定義になる」といった VM エラーが、新規テスト群で再現しないこと。
|
|||
|
|
|