# 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 変換であり、別ユースケース。