Files
hakorune/docs/development/current/main/phases/phase-287/P4-INSTRUCTIONS.md
tomoaki c117a04035 fix(rewrite): toString normalization to BoxCall(slot #0) - Phase 287 P4
Root cause: toString/stringify/str were being rewritten to Global/Method calls
with class inference, causing Main.toString/0 to be called for primitives.

Fix (Box-First + Legacy Deletion):
1.  MIR Builder - toString normalization (special.rs)
   - ALWAYS emit BoxCall with method_id=0 for toString/stringify/str
   - Do NOT rewrite to Global(Class.str/0) or Method calls
   - DELETED 70+ lines of complex class inference logic
   - Primitive guard with method name filter (known.rs)

2.  JSON Serializer - method_id output (mir_json_emit.rs)
   - Include method_id field in BoxCall JSON for LLVM

3.  LLVM Backend - universal slot #0 support
   - Extract method_id from JSON (instruction_lower.py)
   - Box primitives via nyash.box.from_i64 (boxcall.py)
   - Invoke toString via plugin system with method_id=0
   - ⚠️ TODO: Add nyash.integer.tostring_h to kernel

Test Results:
 VM: local x = 1; print(x.toString()) → "1" (PASS)
 VM: array_length test (boxed Integer) → PASS
⚠️ LLVM: Compiles successfully, needs kernel function

SSOT: slot_registry - toString is ALWAYS universal slot #0

Legacy Deleted:
- special.rs: Complex class inference rewrite (~70 lines)
- special.rs: Unique suffix fallback for toString
- special.rs: Main box special handling

Files changed:
- src/mir/builder/rewrite/special.rs (try_early_str_like_to_dst)
- src/mir/builder/rewrite/known.rs (primitive guards x4)
- src/runner/mir_json_emit.rs (method_id serialization x2)
- src/llvm_py/builders/instruction_lower.py (method_id extraction)
- src/llvm_py/instructions/boxcall.py (slot #0 handler)
- docs/reference/language/quick-reference.md (toString SSOT)

🎊 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 11:38:05 +09:00

3.6 KiB
Raw Blame History

Phase 287 P4: Quick 残failの根治core回帰の修正 + テストの仕様合わせ)

目的

  • tools/smokes/v2/run.sh --profile quickfail=0 で安定させる。
  • P3で「責務外」を integration に寄せたあとに残った core回帰(意味論バグ)を直す。
  • REPL はまず hakorune --repl明示起動から開始する(仕様は docs/reference/language/repl.md をSSOT

優先度1: String mixed + の SSOT へ戻す(暗黙 stringify を入れない)

症状

"" + a.length()unsupported binop Add on String("") and Integer(0) で落ちる。

この挙動自体は SSOTPhase 275 C2 / types.md)では正しい。問題は「テスト/ドキュメントが旧挙動を期待している」こと。

仕様SSOT

  • docs/reference/language/types.md+C2: String+String onlyに従う。
  • docs/reference/language/quick-reference.md も SSOT に合わせて修正するString mixed は TypeError)。

実装方針(構造的)

  • 実装VM/LLVMに自動文字列化の分岐を追加しないPhase 287 で仕様拡張をしない)。
  • 連結したいテストは明示的に x.toString() を使う(例: "len=" + a.length().toString())。

受け入れsmokeで固定

この整理により、少なくとも以下の失敗群がまとめて解消する可能性が高い(要再計測):

  • array_length_vm
  • array_oob_get_tag_vm
  • index_substring_vm
  • map_len_set_get_vm
  • map_values_sum_vm
  • string_size_alias

優先度2: JoinIR ループ非対応パターンの扱いquick から外す)

症状

[joinir/freeze] Loop lowering failed: JoinIR does not support this pattern

方針

  • これは「言語機能の最低ゲート」ではなく「JoinIRループ網羅/拡張」の範囲なので、Phase 287 では quick に残さない。
  • 対象テストは integration へ移動し、必要なら [SKIP:joinir](理由固定)にする。

優先度3: Top-level localfile mode禁止 / REPL許可へテストを合わせる

仕様(決定)

  • file mode は top-level 実行文禁止宣言のみ。top-level local も禁止。
  • REPL は hakorune --repl で明示起動し、暗黙localを許可するdocs/reference/language/repl.md)。

具体対応

  • run_nyash_vm -c 'local ...; ...' のように top-level 実行文を前提にしたテストは、quick からは外すか、次のいずれかに書き換える:
    • function main(){ ... } に包むentryは NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 でOK
    • static box Main { main(){ ... } } に包む
  • 「top-level local が壊れている」方向へ直すのは、REPL/file mode の仕様を汚しやすいので今はやらないWIPブランチへ隔離済み

優先度4: 残りの個別(環境依存 / 揺れ)を quick のSSOTへ寄せる

  • filebox_basic.sh のように host依存が避けられないものは [SKIP:env] で理由固定。
  • async_await.sh / gc_mode_off.sh は “環境依存” と断定しない。まずログを見て:
    • core回帰なら修正quickに残す
    • 統合寄り/重いなら integration へ移す

作業手順(推奨)

  1. --format json で fail をSSOT化pathとdurationでソート
  2. まず優先度1String+Integerを修正 → quick を再実行
  3. JoinIR freeze のテストは integration へ移動必要ならSKIP理由固定
  4. top-level 実行文前提のテストは「mainに包む」か integration へ
  5. 残った fail を A/B/Cenv/統合/コアで片付け、quick fail=0 で締める