Files
hakorune/CURRENT_TASK.md
Selfhosting Dev 1f5ba5f829 💢 The truth about Rust + LLVM development hell
ChatGPT5 struggling for 34+ minutes with Rust lifetime/build errors...
This perfectly illustrates why we need Phase 22 (Nyash LLVM compiler)\!

Key insights:
- 'Rust is safe and beautiful' - Gemini (who never fought lifetime errors)
- Reality: 500-line error messages, 34min debug sessions, lifetime hell
- C would just work: void* compile(void* mir) { done; }
- Python would work: 100 lines with llvmlite
- ANY language with C ABI would work\!

The frustration is real:
- We're SO CLOSE to Nyash self-hosting paradise
- Once bootstrapped, EVERYTHING can be written in Nyash
- No more Rust complexity, no more 5-7min builds
- Just simple, beautiful Box-based code

Current status:
- PHI/SSA hardening in progress (ChatGPT5)
- 'phi incoming value missing' in Main.esc_json/1
- Sealed SSA approach being implemented

The dream is near: Everything is Box, even the compiler\! 🌟
2025-09-12 05:48:59 +09:00

15 KiB
Raw Blame History

Current Task (2025-09-11) — Phase 15 LLVMonly

Summary

  • LLVM is the authoritative path; VM/Cranelift/Interpreter are not MIR14ready.
  • Keep fallbacks minimal; fix MIR annotations first.
  • ExternCall(console/debug) autoselects ptr/handle by IR type.
  • StringBox NewBox i8* fast path; print/log choose automatically.
  • Implement multi-function lowering and Call lowering for MIR14.

Update — 2025-09-12 (LLVM flow + BB naming)

  • codegen/mod.rs match arms cleanup:
    • BinOp: unify to instructions::lower_binop(...)
    • BoxCall: delegate solely to instructions::lower_boxcall(...); removed unreachable legacy code
  • BasicBlock naming made functionscoped and unique: create_basic_blocks now prefixes with function label (e.g., Main_join_2_bb23)
  • Terminator fallback: when a MIR block lacks a terminator, emit a conservative jump to the next block (or entry if last)
  • Build: cargo build --features llvm passes
  • AOT emit status: improved (bb name collision resolved), but verifier still flags a missing terminator in Main.esc_json/1 (e.g., Main_esc_json_1_bb88)
    • Likely cause: flow lowering edge case; MIR dump is correct, LLVM lowering missed a terminator
    • Plan below addresses this with hardened flow lowering and instrumentation

Hot Update — 2025-09-12 (quick)

  • Flow: moved function verify to postlower; added terminator fallback only when MIR lacks one
  • Compare: allow ptr↔int comparisons for all ops via ptr→i64 bridge
  • Strings: substring now accepts i64(handle) receiver (i2p); len/lastIndexOf stable
  • Arrays: method_id未注入でも get/set/push/length を NyRT 経由で処理
  • BoxCall: println→env.console.log フォールバック、同モジュール関数呼び出し/名前指定 invoke_by_name 経路を追加
  • PHI: 文字列/Box等を含む場合は i8* を選択する型推定に改善
  • 現在のブロッカー: esc_json/1 で「phi incoming value missing」
    • 対応: emit_jump/emit_branch の incoming 配線をログ付きで点検し、値未定義箇所byname/fastpath戻りを補完

Plan — PHI/SSA Hardening (Sealed SSA)

  • Sealed SSA 入れ替え(安全に段階導入)
    • Blockごとに sealed: boolincomplete_phis: Map<Var, Phi> を保持
    • 値取得APIを一本化: value_at_end_of_block(var, bb) で vmap を再帰解決仮PHI生成
    • seal(bb) で pred 確定後に incomplete_phis を埋め、fold_trivial_phi で単純化
  • 配線の方向を整理
    • emit_jump/emit_branch では直接 incoming を配線しないto 側で必要時に解決)
    • fast/slow 両レーンは同じ Var に書く(合流で拾えるように)
  • 型の前処理を一箇所へ
    • Bool は i1 固定(必要なら zext は PHI 外側)
    • ptr/int 混在禁止。必要箇所で ptrtoint/inttoptr を生成し、PHI では等型を保証
  • 計測と検証
    • seal(bb) 時に incomplete_phis が残れば panic場所特定
    • [PHI] add incoming var=.. pred=.. ty=.. をデバッグ出力
    • verify は関数降下完了後に 1 回
  • フォールバックのゲート
    • by-name invoke は環境変数で明示ONデフォルトOFFにする方針に切替イズ低減

Refactor Policy

  • 慌てず小さな箱モジュールを積む。必要なら随時リファクタリングOK。
  • 代替案(必要時のみ): llvmlite の薄層で最低限の命令面を実装し、dep_tree_min_string を先に通す。

Done (today)

  • BoxCall legacy block removed in LLVM codegen; delegation only.
  • BinOp concat safety: minimal fallback for i8*+i64/i64+i8* when both sides are annotated String/Box → from_i8_string + concat_hh; otherwise keep concat_ss/si/is.
  • String fastpath: length/len lowered to nyash.string.len_h (handle), with ptr→handle bridge when needed.
  • Map corefirst: NewBox(MapBox) routes via nyash.env.box.new("MapBox") → NyRT特例でコアMapを生成。LLVM BoxCall(Map.size/get/set/has) は NyRT の nyash.map.* を呼ぶ。
  • Plugin強制スイッチ: NYASH_LLVM_FORCE_PLUGIN_MAP=1 で MapBox のプラグイン経路を明示切替(デフォルトはコア)。
  • Docs: ARCHITECTURE/LOWERING_LLVM/EXTERNCALL/PLUGIN_ABI を追加・整備。
  • Smokes: pluginret green, map smoke greencorefirst
  • ExternCall microsplit 完了: externcall.rsexterncall/ ディレクトリ配下に分割し、 console.rsconsole/debugenv.rsfuture/local/boxに切り出し。 ディスパッチは externcall/mod.rs に集約挙動差分なし・0diff
  • String FastPath 追加LLVM/NYRT: substring(start,end)lastIndexOf(needle) を実装。
  • Compare: String/StringBox 注釈のときは内容比較(nyash.string.eq_hh)にブリッジ。
  • LLVM 多関数 Lower の骨格を実装: 全関数を事前宣言→順次Lower→ny_main ラッパで呼び出し正規化。
  • Call Lowering 追加MIR14の MirInstruction::Call: callee 文字列定数を解決し、対応するLLVM関数を呼び出し引数束縛・戻り値格納

Refactor — LLVM codegen instructions modularized (done)

  • Goal achieved: instructions.rs を段階分割し、責務ごとに再配置0diff
  • New layout under src/backend/llvm/compiler/codegen/instructions/:
    • Core: blocks.rsBB生成/PHI事前作成, flow.rsReturn/Jump/Branch, consts.rs, mem.rs, arith.rsCompare
    • BoxCall front: boxcall.rs(ディスパッチ本体)
      • Strings/Arrays/Maps fastpaths: strings.rs, arrays.rs, maps.rs
      • Fields: boxcall/fields.rsgetField/setField
      • Tagged invoke: boxcall/invoke.rsmethod_idありの固定長/可変長)
      • Marshal: boxcall/marshal.rsptr→i64, f64→box→i64, tag分類
    • Arith ops: arith_ops.rsUnary/Binary、文字列連結の特例含む
    • Extern: externcall.rsconsole/debug/env.local/env.box.*
    • NewBox: newbox.rscodegen/mod.rs から委譲に一本化)
  • Wiring: instructions/mod.rspub(super) use ... で再エクスポート。可視性は pub(in super::super)/pub(super) を維持。
  • Build: cargo build --features llvm グリーン、挙動差分なし。

Next (short, focused)

  • Call Lowering の分離(完了): instructions/call.rs に分割し、mod.rs から委譲。
  • 多関数 Lower 検証: selfhost minimaldep_tree_min_stringを LLVM で通す(必要なら型注釈の微調整)。
  • Flow lowering hardening (in progress next):
    • Ensure every lowered block has a terminator; use builder.get_insert_block().get_terminator() guard before fallback
    • Instrument perblock lowering (bid, has terminator?, emitted kind) to isolate misses
    • Keep fallback minimal and only when MIR.block.terminator is None and LLVM has no terminator
  • MIR readable debug tools:
    • Add --dump-mir-readable to print Nyashlike pseudo code per function/block
    • Optional DOT output (followup)
  • Debug hints in MIR (debug builds only):
    • Add #[cfg(debug_assertions)] fields like MirInstruction::debug_hint and MirMetadata::block_sources
    • Gate emission by env (NYASH_MIR_DEBUG=1)
  • Map コア専用エントリ化env.box.new 特例整理と代表スモークの常時化CI
  • types.rs の将来分割(任意):
    • types/convert.rsi64<->ptr, f64→box, types/classify.rs, types/map_types.rs
  • 機能拡張(任意・別タスク):
    • String AOT fastpaths拡充substring/indexOf/replace/trim/toUpper/toLower
    • MapBox 生成のNyRT専用エントリ化env.box.new特例の解消
    • Map.get の戻り型注釈の厳密化
    • 代表スモークの追加とCI常時チェック

Risks/Guards

  • Avoid broad implicit conversions; keep concat fallback gated by annotations only.
  • Ensure nyash.map.* との一致core Map; plugin経路は環境変数で明示切替。
  • Keep LLVM smokes green continuously; do not gate on VM/JIT.

🎉 LLVMプラグイン戻り値表示問題修正進行中2025-09-10

完了した主要成果

  1. プラグイン実装 - nyash.plugin.invoke_*関数はnyrtライブラリに正常実装済み
  2. プラグイン呼び出し - 環境変数なしでメソッド呼び出し成功
  3. 戻り値型推論修正 - MIR builder にプラグインメソッド型推論追加
  4. by-id統一完了 - by-name方式削除、method_id方式に完全統一
  5. 環境変数削減達成 - NYASH_LLVM_ALLOW_BY_NAME=1削除完了
  6. シンプル実行実現 - ./target/release/nyash --backend llvm program.nyash
  7. codex TLV修正マージ完了 - プラグイン戻り値TLVタグ2/6/7対応2000行修正
  8. console.log ハンドル対応 - 不正なi64→i8*変換を修正、ハンドル対応関数に変更
  9. 型変換エラー解消 - bool(i1)→i64拡張処理追加でLLVM検証エラー修正

🔬 現在の動作状況2025-09-11 最新):

  • プラグイン実行 - CounterBox、FileBox正常実行副作用OK
  • 型エラー解消 - LLVM関数検証エラー修正済み
  • コンパイル成功 - 環境変数なしでLLVMバックエンド動作
  • 条件分岐動作 - if f.exists("file") → "TRUE"/"FALSE"表示OK
  • LLVMコード生成の分割 - codegen/ 下にモジュール化types/instructions
  • BoxCall Lower 移譲 - 実行経路は instructions::lower_boxcall に一本化(旧実装は到達不能)
  • スモーク整理 - tools/llvm_smoke.sh を環境変数整理。プラグイン戻り値スモーク追加

🔍 根本原因判明

Task先生の詳細技術調査により特定

  • 不正なハンドル→ポインタ変換: build_int_to_ptr(iv, i8p, "arg_i2p") でハンドル値3を直接メモリアドレス0x3として扱う不正変換
  • 修正完了: console.log を nyash.console.log_handle(i64) -> i64 に変更、ハンドルレジストリ活用

🔍 残存課題(新)

1. プラグイン戻り値表示問題 🔶 ←現在調査中

症状(修正後も継続):

  • CounterBox.get() → 数値戻り値がprint()で空白
  • FileBox.read(path) → 文字列戻り値がprint()で空白
  • FileBox.exists(path) → if条件では動作、変数格納で失敗
  • local x = 42; print(x) → 正常(問題はプラグイン戻り値のみ)

残る問題の推定:

  • print()以外のExternCall処理にも同様の問題がある可能性
  • MIR変数代入処理での型情報不整合
  • プラグイン戻り値のハンドル→実値変換が不完全

2. LLVM BinOp 文字列連結まわり(新規スモークで再現) 🔶

現象:

  • 追加スモーク ny-plugin-ret-llvm-smoke で LLVM AOT オブジェクト生成中に binop type mismatch が発生
  • ケース: print("S=" + t)tStringBox.concat("CD") の戻り値)

暫定分析:

  • + 連結の BinOp Lower は (ptr+ptr / ptr+int / int+ptr) を NyRT シム経由で処理する設計
  • t のLowerが i64 handleのままになっている/もしくは型注釈不足で ptr へ昇格できていない可能性
  • instructions::lower_boxcall 内の concat 特例f64 fast-pathは撤去済み。以降は tagged invoke → dst 型注釈に応じて i64→ptr へ変換する想定

対応方針:

  1. MIR の value_types に BoxCall 戻り値StringBoxの型注釈が入っているか確認不足時は MIR 側で注入)
  2. BinOp 連結経路は fallback として (ptr + 非ptr) / (非ptr + ptr) に対して handle想定の i64→ptr 昇格を再確認
  3. 上記fixの後、スモーク NYASH_LLVM_PLUGIN_RET_SMOKE=1 を通し、VM/LLVM 一致を確認

メモ:

  • 現状でも BoxCall は新経路に完全委譲済み。旧実装は到達不能削除準備OK

📊 修正済みファイル

  • src/mir/builder.rs - プラグインメソッド戻り値型推論追加
  • src/backend/llvm/compiler.rs - by-name方式削除、method_id統一
  • src/backend/llvm/compiler/codegen/mod.rs - 分割に伴う委譲Const/Compare/Return/Jump/Branch/Extern/NewBox/Load/Store/BoxCall
  • src/backend/llvm/compiler/codegen/types.rs - 型変換/分類/型マップ(新)
  • src/backend/llvm/compiler/codegen/instructions.rs - Lower群を実装
  • tools/llvm_smoke.sh - LLVM18 prefix整理・プラグイン戻り値スモーク追加
  • apps/tests/ny-plugin-ret-llvm-smoke/main.nyash - プラグイン戻り値スモーク(新)
  • CLAUDE.md - 環境変数セクション更新、コマンド簡素化
  • README.md / README.ja.md - 環境変数説明削除
  • tools/llvm_smoke.sh - テストスクリプト環境変数削除

🎯 次期深堀り調査対象

  1. プラグインランタイム戻り値パス詳細調査 - crates/nyrt/src/lib.rs
  2. LLVM BoxCall戻り値処理詳細分析 - src/backend/llvm/compiler/real.rs 戻り値変換
  3. MIR変数代入メカニズム調査 - BoxCall→変数の代入処理
  4. print()関数とプラグイン値の相性調査 - 型認識処理
  5. BinOp 連結の保険見直し - 片方が i64 (handle) の場合に ptr に昇格する安全弾性
  6. BoxCall 旧実装の物理削除 - スモークグリーン後に mod.rs の死コードを除去

リファクタリング完了2025-09-11

PR #136マージ済み - LLVMコンパイラモジュール化

  • compiler.rs → 4モジュールに分割mod.rs, real.rs, mock.rs, mock_impl.in.rs
  • プラグインシグネチャ読み込みを plugin_sigs.rs に移動
  • BoxタイプID読み込みを box_types.rs に移動
  • PR #134の型情報処理を完全保持

🎯 Restart Notes — Ny Syntax Alignment (20250907)

目的

  • SelfHosting 方針Nyのみで工具を回す前段に合わせて、Ny 構文とコーディング規約を明示化し、最小版ツールの完走性を優先。

Ny 構文(実装時の基準)

  • 1行1文セミコロン非使用。
  • break / continue を使わない(関数早期 return、番兵条件、if 包みで置換)。
  • else は直前の閉じ波括弧と同一行(} else {})。
  • 文字列の "\ は確実にエスケープ。
  • 反復は loop(条件) { …; インクリメント } を基本とし、必要に応じて「関数早期 return」型で早期脱出。

短期タスクSyntax 合意前提で最小ゴール)

  1. include のみ依存木Nyのみ・配列/マップ未使用)を完走化
    • apps/selfhost/tools/dep_tree_min_string.nyash
    • FileBox/PathBox + 文字走査のみで JSON 構築(配列/マップに頼らない)
    • make dep-treetmp/deps.json を出力
  2. using/module 対応は次段(構文・優先順位をユーザーと再すり合わせ後)
    • 優先: module > 相対 > using-path、曖昧=エラー、STRICT ゲート(要相談)
  3. ブリッジ Stage 1 は保留
    • NYASH_DEPS_JSON=<path> 読み込みログ出力のみを最小パッチで用意MIR/JIT/AOT は不変)