Files
hakorune/docs/private/roadmap/phases/phase-20.18

Phase 20.18 — Resultケースバイケース+ 軽量糖衣 + Null/Void 固定

目的(要約)

  • 「全部 Result は重い」を回避しつつ、一貫した失敗取り扱いを提供する。
  • Null/Void の言語レベル固定(予約語)と VM 値表現Null タグ)を導入し、欠落/手続きの意味を明確化。
  • ケース別の最小主義:検索=sentinel、境界=FailFasttry_系、変換/I/O=Result 既定。
  • 糖衣は左辺だけ(let a?=/a!=)に限定し、ゼロアロケーションで Lowering。

適用範囲MVP

  • Null/Void の固定(言語+VM
    • 言語: null, void を予約語にする(リテラル)。
    • MIR JSON v0: Const{"type":"Null"|"Void"} を追加。
    • VM/Interpreter: VMValue::Null を追加0 アロケーション、比較高速)。
  • 既定挙動SSOT
    • String.indexOf/1 → not found は -1sentinelのまま
    • Array.get/1 → 範囲外は nullFail しない)。
    • Array.pop/0 → 空配列は nullFail しない)。
    • Array.set/2 → i<0 または i>len は E_OOB、i==len は append、0<=i<len は置換。戻りは void
    • Map.get/1 → 欠落は nullFail しない)。
    • Map.set/2 → 不正キー= E_INVALID_KEY、不正値= E_INVALID_VALUE、戻りは void
    • Map.delete/1 → 削除値 or nullMap.clear/0void
  • 追加API5つ
    • Array.try_get/1, Array.try_pop/0
    • Map.try_get/1
    • String.to_i64/0, String.to_f64/0

糖衣(任意・軽実装)

  • let r = arr.try_get(0) … Resultのまま
  • let x? = arr.try_get(0)ok→値 / err→VoidBox
  • let x! = arr.try_get(0)ok→値 / err→即Fail
  • if let ok(v) = arr.try_get(0) { … } else { … }

実装方針(段階導入)

  • Phase A本フェーズ
    • Null/Void: 予約語・MIR・VM の三層で固定VMValue::Null、singleton 変換)。
    • Core/GateC: Array/Map の SSOT へ挙動を収束(上記 既定挙動)。
    • Parser: 左辺の ?/!if let ok(..) を受理。
    • Lowering: ?/!/if-let を branch/select に展開(ゼロアロケーション)。
    • Verifier: 例外タグ E_OOB/E_EMPTY/E_NOT_FOUND/E_PARSE を安定化。
    • Gate: HAKO_TRY_API=1既定OFFでスモーク有効化。
  • Phase B20.19+ 任意)
    • MIR/LLVM を“値版Result” {i1 ok, T payload} に寄せるSROA/mem2reg 合流)
    • Box化は保存/境界FFI/ABIのみで行いゼロコスト化を徹底

受入れ基準MVP

  • quickoptinで try_* + 糖衣(?/!/if-let okスモークが緑。
  • FailFastタグが安定E_OOB/E_EMPTY/E_NOT_FOUND/E_PARSE
  • Array/Map の SSOTNull/void 既定)が GateC/Core/VM で一致。

完了サマリ20251029 現在)

  • BridgeBNy/Core直行: include ベースで安定。GateC(Core) の file/pipe は緑。
  • Core canary直行: array_get/push/set_get は緑。string indexOf bang は TTL 互換で緑(タグ優先、未到達時は -1/rc=0 を暫定許容)。
  • Runner: Core ラッパー出力はタグ行を優先採用。GateC(Core) はタグ→stderr+rc=1、数値→rc=(num&0xFF)。
  • Docs: VM README/Smokes README/CURRENT_TASK を更新BridgeB方針、カナリア導線、TTL注記

残タスク(短期)

  • Core からの FailFast を state 経由の戻り値へ統一して、タグを必ず last line にするprint 依存解消)。
  • 上記完了後、string indexOf bang の TTL 互換(-1容認を撤去し、タグ必須に戻す。

ノート

  • 20.17 は selfhosting 完了を優先。実装は本フェーズでまとめて入れる。
  • 糖衣は左辺のみ公開名の二重化を避ける。Result は段階で“値版”へ移行予定。

Plugins への影響(互換ポリシー)

ABI 変更は不要Box 戻りのまま)。ただし意味論は SSOT に合わせる:

  • ArrayBoxプラグイン実装がある場合
    • get: 範囲外→NullBox、pop: 空→NullBox、push/set/clear: 戻りは VoidBox。
    • set: i<0 or i>len は E_OOB。i==len は append、0<=i<len は置換。
  • MapBoxプラグイン実装がある場合
    • get: 欠落→NullBox、delete: 削除値 or NullBox、clear: VoidBox、set: VoidBox。
    • set: Null key/不正型→ E_INVALID_KEY、不正値→ E_INVALID_VALUE。暗黙変換は禁止。

Core/GateC が先行で SSOT を満たすため、プラグインが未更新でも GateC(Core) 直行経路は安定。VM 経路でプラグイン実装が呼ばれる場合は、上記の意味論に合わせて段階更新する。