diff --git a/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md b/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md index 53452f46..6850caf1 100644 --- a/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md +++ b/docs/development/current/main/01-JoinIR-Selfhost-INDEX.md @@ -55,6 +55,8 @@ JoinIR の箱構造と責務、ループ/if の lowering パターンを把握 - `docs/development/current/main/phases/phase-97/README.md` 11. Phase 98: Plugin loader fail-fast + LLVM parity持続化 - `docs/development/current/main/phases/phase-98/README.md` +12. Phase 100: Pinned Read‑Only Captures(設計メモ) + - `docs/development/current/main/phases/phase-100/README.md` 6. MIR Builder(Context 分割の入口) - `src/mir/builder/README.md` 7. Scope/BindingId(shadowing・束縛同一性の段階移行) diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 90a13e7d..ec167480 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -7,6 +7,9 @@ - escape 末尾バックスラッシュを best-effort として固定(`hello\` そのまま出力) - VM+LLVM EXE parity 完全対応、integration smoke で検証済み +Next(設計メモ): +- Phase 100: Pinned Read‑Only Captures(ループ外 local を loop 内 receiver として解決): `docs/development/current/main/phases/phase-100/README.md` + ## 2025‑12‑15:Phase 132 完了 ✅ **Phase 132: LLVM Exit PHI=0 根治修正 完了!** diff --git a/docs/development/current/main/design/joinir-design-map.md b/docs/development/current/main/design/joinir-design-map.md index baaff08d..a8dc6fcb 100644 --- a/docs/development/current/main/design/joinir-design-map.md +++ b/docs/development/current/main/design/joinir-design-map.md @@ -184,3 +184,23 @@ Box を新規実装・変更した際は以下を必ず確認: - `docs/development/current/main/loop_pattern_space.md`(パターン空間に追記が必要なら) - `docs/development/current/main/joinir-architecture-overview.md`(箱/契約が増えたなら) - 本ファイル(入口・責務マップの更新) + +--- + +## スコープ解決の SSOT(Pinned Read‑Only Captures) + +JoinIR lowering では「ループ内で参照される値」を次の層で解決する(探索順 SSOT): + +1. `ConditionEnv`(条件式に必要な値) +2. `LoopBodyLocalEnv`(ループ body 内で初期化される一時変数) +3. `CapturedEnv`(ループ外から入ってくる read‑only 入力) + +`CapturedEnv` は “読み取り専用入力” の SSOT として扱い、内部で区別する: +- `Explicit`(従来の capture) +- `Pinned`(ループ外 local を loop 内 receiver として参照するための read‑only capture) + +Fail‑Fast(Pinned): +- loop body 内で再代入される変数は pinned 禁止 +- loop entry 時点で host 側 ValueId が無い場合は拒否(黙って skip しない) + +設計メモ: `docs/development/current/main/phases/phase-100/README.md` diff --git a/docs/development/current/main/phases/phase-100/README.md b/docs/development/current/main/phases/phase-100/README.md new file mode 100644 index 00000000..8dbb6695 --- /dev/null +++ b/docs/development/current/main/phases/phase-100/README.md @@ -0,0 +1,35 @@ +# Phase 100: Pinned Read‑Only Captures(設計メモ) + +## 目的 + +JoinIR lowering のスコープ解決(`ConditionEnv → LoopBodyLocalEnv → CapturedEnv`)の前提を崩さずに、 +「ループ外で定義した local(動的式でも可)」をループ内で receiver として参照できるようにする。 + +例(問題の形): + +```nyash +local s = "a" + "b" // 条件式とは無関係 +loop(i < n) { + local ch = s.substring(i, i + 1) // receiver 解決が必要 +} +``` + +## 方針(SSOT) + +- “Pinned local” は **新しい Pattern ではなく**、ループに入ってくる **read‑only 入力**として扱う。 +- SSOT は増やさず `CapturedEnv` に統合し、`CapturedKind` で区別する: + - `Explicit`: 従来の capture + - `Pinned`: ループ内参照のために必要な read‑only local + +## Fail‑Fast 契約 + +- `Pinned` は loop body 内で **再代入されない**(assignment target に現れたら拒否)。 +- loop entry 時点で host 側 ValueId が存在する(`variable_map` に無い場合は拒否)。 +- 初期化が loop より後にある等、支配関係が曖昧な場合は拒否(理由付き)。 +- init 式の副作用有無は問わない(評価はホスト側で1回、Pinned は値を渡すだけ)。 + +## Loop Canonicalizer との関係(混ぜない) + +- Phase 100 は「ループ外の値が loop 内で見えない」問題(capture/wiring)を解く。 +- Loop Canonicalizer は「ループ内の不変式を外に出す」AST 変換であり、別ユースケース。 +