docs(joinir): Step 1 - SSOT updates (Phase 72/73 foundation)

Add terminology clarification and architecture notes:

- joinir-architecture-overview.md:
  - Add section 0.1 (routing/fallback/fail-fast terminology)
  - Clarify JoinValueSpace vs MIR ValueId distinction
  - Add Phase 72 observations (PHI reserved is not architectural)
  - Update invariant 12: lexical scope support prerequisite

- phase67-mir-var-identity-survey.md:
  - Update with Phase 68/69 status (lexical scope complete)
  - Link to ownership analyzer refinements

These are prerequisites for Phase 74 (BindingId infrastructure).

Tests: lib 950/950, normalized_dev 54/54 PASS

🤖 Generated with Claude Code

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-13 03:47:54 +09:00
parent 851bf4f8a5
commit 7c988ae3ec
2 changed files with 85 additions and 25 deletions

View File

@ -12,6 +12,8 @@
このファイルは情報量が多いので、「何を知りたいか」で読む場所を分けると楽だよ:
- 注意: 本文のセクション番号は歴史的経緯で重複することがあるため、参照は「見出し名」を基本にする。
- **不変条件だけ押さえたいとき**
- セクション `1. 不変条件Invariants` を読む。
- JoinIR 全体で絶対に守るルールValueId 領域 / PHI 契約 / FailFastがここにまとまっている。
@ -21,13 +23,12 @@
- LoopPattern / Pattern lowerer / ConditionEnv / ExitLine / Boundary など、構造箱・判定箱・生成箱の入口がここ。
- **Normalized JoinIRJoinIR→JoinIR 正規化)を知りたいとき**
- セクション `3. JoinIR 第1章基盤完成サマリ`
小節 `3.13.3`Structured vs Normalized の関係)を読む。
- 見出し `JoinIR 第1章基盤完成サマリ`
小節 `Structured vs Normalized`Structured/Normalized の関係)を読む。
- 詳細な完成サマリは `PHASE_43_245B_NORMALIZED_COMPLETION.md` にまとまっているので、そちらも合わせて参照してね。
- **JsonParser/selfhost のループ状況を見たいとき**
- セクション `7. JoinIR 第1章基盤完成サマリ` 内の JsonParser/selfhost 表と、
`phase181-jsonparser-loop-roadmap.md` を見る。
- 見出し `JoinIR 第1章基盤完成サマリ` 内の JsonParser/selfhost 表と、`phase181-jsonparser-loop-roadmap.md` を見る。
- **各 Phase ごとの細かい経緯・ログが欲しいとき**
- `docs/development/current/main/phase*-*.md` 系の Phase ドキュメントを読む。
@ -35,13 +36,24 @@
---
## 0.1 用語routing / fallback / fail-fast
本文では「fallback」という単語が文脈でぶれやすいので、先に用語を固定する
- **routing**: JoinIR Core 内での正規な経路選択Pattern ルータ、if-sum mode ↔ legacy P3 など)。理由が分かる形でログ/タグを付ける。
- **soft fallback**: 任意箱pre-validation / optional optimizerが失敗したときに、同等意味論の別 JoinIR 経路へ退避することJoinIR Core 外へは出ない)。
- **prohibited fallback**: 非 JoinIR への退避(例: LoopBuilder・サイレント退避・契約違反の握りつぶし。
## 1. 不変条件Invariants
JoinIR ラインで守るべきルールを先に書いておくよ:
1. **JoinIR 内部は JoinIR ValueId だけ**
- JoinIR lowering が発行する `JoinInst``ValueId`、すべて `alloc_value()` で割り当てるローカル ID
- Rust/MIR 側の ValueId`builder.variable_map` に入っている IDは、JoinIR には直接持ち込まない
- JoinIR lowering が発行する `JoinInst``ValueId` JoinValueSpace の領域Param/Localのみを使う
- `alloc_param()`Param 100999/ `alloc_local()`Local 1000+)が SSOT
- 多くの lowerer が使う `alloc_value()` は「実装上の別名Local を増やす)」として扱う(概念上は `alloc_local()`)。
- Rust/MIR 側の ValueId例: `builder.variable_map`は、JoinInst の operand としては持ち込まない。
- 例外(ただし JoinInst には出現しない): LoopHeader PHI dst は merge(MIR) 段階で確保される MIR ValueId で、JoinValueSpace は `reserve_phi()` で衝突防止のマークだけを行う。
2. **host ↔ join の橋渡しは JoinInlineBoundary 系だけ**
- host から JoinIR への入力(ループ変数 / 条件専用変数)は
@ -94,14 +106,14 @@ JoinIR ラインで守るべきルールを先に書いておくよ:
- `ExprResult`: ループ戻り値 → exit_phi_builder で処理
10. **JoinIR Core は常時 ON**
- LoopBuilder は物理削除済み。JoinIR を OFF にする経路やフォールバックは存在しない。
- LoopBuilder は物理削除済み。JoinIR を OFF にする経路や prohibited fallback非 JoinIR への退避)は存在しない。
- `NYASH_JOINIR_CORE` は deprecated0 を指定しても警告して無視。JoinIR の OFF トグルは提供しない。
11. **Phase 220: P3 if-sum の ConditionEnv 統合完了**
- **LoopBuilder へのフォールバック経路は Phase 187 で完全削除済み**。
- **P3 if-sum には ConditionPatternBox + ConditionEnv が必須**:
- 単純条件(`var CmpOp literal`)のみ if-sum mode へルーティングPhase 219-fix
- 複雑条件(`i % 2 == 1` 等)は legacy P3 経路へフォールバック
- 複雑条件(`i % 2 == 1` 等)は legacy P3 経路へ routingJoinIR Core 内)
- **Phase 220-D で loop 条件の変数サポート完了**:
- `loop(i < len)` のような変数条件を ConditionEnv で解決。
- `extract_loop_condition()` を ValueOrLiteral 対応に拡張。
@ -109,6 +121,27 @@ JoinIR ラインで守るべきルールを先に書いておくよ:
- ExprResultResolver Box で expr_result routing を統一化Phase 221-R
- phase212_if_sum_min.hako → RC=2 達成。
12. **Lexical scopePhase 68を host 側で実在化する**
- JoinIR の正当性は「上流の束縛モデル」が壊れていないことを前提にする。
- MIR builder は `{...}`Program/ `ScopeBox` を lexical scope として扱い、`local` shadowing を正しく復元する。
- “未宣言名への代入はエラー” を SSOTquick-reference/LANGUAGE_REFERENCEに揃えて Fail-Fast 化する。
- 参照:
- `docs/development/current/main/phase67-mir-var-identity-survey.md`
- `docs/reference/language/variables-and-scope.md`
- 次の焦点Phase 73+:
- JoinIR lowering の `ScopeManager` を「名前ベース」から「BindingId ベース」に段階移行し、shadowing/束縛同一性を JoinIR 側でも安全に扱えるようにする。
- 参照: `docs/development/current/main/phase73-scope-manager-design.md`
13. **Ownership/RelayPhase 5671: carrier/capture/relay を契約化するdev-only**
- `OwnershipPlan` は carriers/captures/relay_writes の SSOT として使い、混線を Fail-Fast で検出する。
- multihop relay は plan 層では受理できるが、runtime 側で未対応の間は標準タグで Fail-Fast に落とすPhase 70-A
- 標準タグ: `[ownership/relay:runtime_unsupported]`
- `OwnershipPlanValidator` を箱として隔離し、Pattern lowerer 側から再利用できる形にするPhase 71-Pre
- 参照:
- `docs/development/current/main/phase56-ownership-relay-design.md`
- `docs/development/current/main/phase65-ownership-relay-multihop-design.md`
- `docs/development/current/main/phase70-relay-runtime-guard.md`
---
## 1.9 ValueId Space Management (Phase 201)
@ -120,21 +153,22 @@ JoinIR の ValueId 割り当ては **JoinValueSpace** で一元管理され、3
```
JoinValueSpace Memory Layout:
0 100 1000 u32::MAX
0 100 1000 LOCAL_MAX
├──────────┼──────────┼──────────────────────────┤
│ PHI │ Param │ Local │
│ Reserved│ Region │ Region │
└──────────┴──────────┴──────────────────────────┘
PHI Reserved (0-99):
- LoopHeader PHI dst 用の予約領域
- reserve_phi(id) で特定 ID をマーク
- LoopHeader PHI dst 用の予約マーカー領域」JoinValueSpace 側の契約)
- `reserve_phi(dst)` で「この MIR ValueId を PHI dst として予約した」というマークだけを行うJoinValueSpace は PHI dst を割り当てない)
- 注: 実際の PHI dst は host MirBuilder が割り当てるため、0-99 に入ることは “保証” ではないPhase 72 観測: `docs/development/current/main/phase72-phi-reserved-observation.md`
Param Region (100-999):
- alloc_param() で割り当て
- 使用箇所: ConditionEnv, CarrierInfo.join_id, CapturedEnv
Local Region (1000+):
Local Region (1000..=LOCAL_MAX):
- alloc_local() で割り当て
- 使用箇所: Pattern lowerers (Const, BinOp, etc.)
```
@ -145,6 +179,7 @@ Local Region (1000+):
- **領域分離**: Param ID、Local ID、PHI dst が決して重複しない
- **契約検証**: デバッグモードで違反を早期検出
- **後方互換性**: 既存 API は継続動作
- 注意: `LOCAL_MAX` はデバッグ/検証用の上限。概念上は Local 領域は拡張可能で、必要なら上限を増やす。
### 1.9.3 各コンポーネントと ValueId 領域の対応表
@ -167,8 +202,9 @@ Local Region (1000+):
- アロケータ間の調整不要
2. **reserve_phi() vs alloc_phi()**
- PHI dst ID は MirBuilderhost 側から来るため、JoinValueSpace は割り当てない
- `reserve_phi()` はマーカーのみ(「この ID を上書きするな」という契約)
- LoopHeader PHI dst は merge(MIR) 段階で確保される **MIR 側 ValueId**JoinInst の ValueId とは世界が違う)。
- JoinValueSpace は PHI dst を「割り当てる」箱ではなく、`reserve_phi(dst)` で予約マークし、JoinIR Param/Local の割当と衝突しないようにする。
- `reserve_phi()` はマーカーのみ(「この ID を JoinIR 側で上書き/再利用するな」という契約)。
3. **value_id_ranges.rs との関係**
- `value_id_ranges.rs`: **モジュールレベルの分離**min_loop, skip_ws 等の各モジュールに大きな固定範囲を割り当て)
@ -195,7 +231,9 @@ Local Region (1000+):
- 検証項目:
- 全ての `boundary.join_inputs` が Param 領域100-999にいる
- 全ての `condition_bindings[].join_value` が Param 領域にいる
- 全ての `carrier_phis[].phi_dst`有効範囲(<= LOCAL_MAX
- 全ての `carrier_phis[].phi_dst`「JoinIR 側の Param/Local と衝突しない」こと
- 現状は “偶発的な非衝突MirBuilder が低番、JoinValueSpace が 100+)” で安定しているPhase 72 観測: `docs/development/current/main/phase72-phi-reserved-observation.md`)。
- 検証強化の是非は Phase 72 を SSOT にして別フェーズで決める(ここで前提を固定しない)。
4. **明示的な領域定数**
```rust
@ -321,7 +359,7 @@ Local Region (1000+):
- 複雑条件(`i % 2 == 1`、MethodCall 等)は false を返し、legacy P3 経路へルーティング。
- 使用箇所:
- PatternPipelineContext.is_if_sum_pattern() で条件複雑度をチェック。
- P3 if-sum mode は単純比較のみ受理、複雑条件は PoC lowerer へフォールバック
- P3 if-sum mode は単純比較のみ受理、複雑条件は legacy P3 route へ routingJoinIR Core 内)
- **MethodCallLowererPhase 224-B / 224-C / 225 実装完了)**
- ファイル: `src/mir/join_ir/lowering/method_call_lowerer.rs`
@ -357,7 +395,7 @@ Local Region (1000+):
- 責務:
- ループ条件header/break/continueに出てくる LoopBodyLocal を carrier に昇格する統一 API。
- Pattern 2/Pattern 4 両対応の薄いコーディネーター箱detection は専門 Promoter に委譲)。
- **Phase 224: Two-tier strategy** - A-3 Trim → A-4 DigitPos フォールバック型オーケストレーション
- **Phase 224: Two-tier strategy** - A-3 Trim → A-4 DigitPos の二段階 routing昇格箱の順序を固定
- Phase 223-3 実装内容:
- `extract_continue_condition()`: body 内の if 文から continue 条件を抽出。
- `try_promote_for_condition()`: LoopBodyCarrierPromoter を使った昇格処理。
@ -374,12 +412,12 @@ Local Region (1000+):
- **Pattern2ScopeManager**: Pattern2 専用の薄いラッパーpromoted_loopbodylocals 対応含む)。
- **ExprLowerer**: 式 lowering を1箇所に集約Phase 231: Condition context のみ、General context は将来実装)。
- Phase 231 実装内容:
- Pattern2 break 条件の **pre-validation** として ExprLowerer を試行fallback 完備)。
- 簡単な条件式(`i >= 5` など)を正常に検証、複雑なパターンは UnsupportedNode エラーで legacy path へ fallback
- Pattern2 break 条件の **pre-validation** として ExprLowerer を試行(soft fallback を前提にした検証ルート)。
- 簡単な条件式(`i >= 5` など)を正常に検証し、未対応は UnsupportedNode エラーとして上位 router が legacy route を選ぶ
- 箱化・モジュール化の原則に準拠ScopeManager は trait、ExprLowerer は再利用可能)。
- 設計原則:
- **Box-First**: ScopeManager は trait-based "box" で変数解決を抽象化。
- **Fail-Safe**: 未対応 AST ノードは明示的エラーで fallback 可能(実行時エラーにしない)
- **Fail-Safe**: 未対応 AST ノードは明示的エラーとして扱い、JoinIR Core 内の routing で安全に退避する
- **Incremental Adoption**: Phase 231 は検証専用、Phase 232+ で実際の lowering 置き換え予定。
- 使用箇所:
- `pattern2_with_break.rs` の break 条件 lowering 前に pre-validation として実行。
@ -416,7 +454,7 @@ Local Region (1000+):
- Phase 224 実装内容:
- `try_promote()`: A-4 パターン検出 & bool carrier 昇格(`digit_pos` → `is_digit_pos`)。
- **Unit tests**: 6/6 PASSbasic pattern, non-indexOf rejection, no dependency rejection, comparison operators, equality rejection
- **Integration**: LoopBodyCondPromoter から A-3 Trim フォールバック後に呼ばれる。
- **Integration**: LoopBodyCondPromoter から A-3 Trim 失敗後の二段階 routing で呼ばれる。
- 設計原則:
- **One Box, One Question**: A-4 DigitPos パターン専用A-3 Trim は LoopBodyCarrierPromoter に残す)。
- **Separation of Concerns**: Trimequality-basedと DigitPoscomparison-basedを分離。
@ -1315,7 +1353,7 @@ Normalized JoinIR を 1 段挟むと、開発の手触りがどう変わるか
### 3.18 Phase 41-NORM-CANON-P2-CORE Pattern2 コアケースの canonical Normalized 化
- Pattern2 のコアセットP2 ミニ + JsonParser skip_ws/atoi ミニ/realについて、JoinIR→MIR Bridge の既定を Normalized→MIR に寄せ、Structured→MIR は比較テスト用/フォールバック用の位置づけにするFailFast ポリシーは維持)。
- Pattern2 のコアセットP2 ミニ + JsonParser skip_ws/atoi ミニ/realについて、JoinIR→MIR Bridge の既定を Normalized→MIR に寄せ、Structured→MIR は比較テスト用/soft fallbackJoinIR 内)の位置づけにするFailFast ポリシーは維持)。
- `shape_guard` で「Normalized 対応と宣言した P2 コアループ」は常に Normalized 経路を通すようにし、Normalized 側の invariant 破損は dev では panic、本番では明示エラーで早期検出する設計に寄せる。
### 3.19 Phase 42-NORM-P2-INVENTORY P2 コア/ミドル/ヘビーの棚卸し
@ -1331,7 +1369,7 @@ Normalized JoinIR を 1 段挟むと、開発の手触りがどう変わるか
- **P2-Heavy**(複数 MethodCall / 複雑キャリアを持つもの)
- JsonParser: `_parse_string`, `_parse_array`, `_parse_object`, `_unescape_string`
- P2/P3/P4 が混在し、複雑なキャリアや MethodCall 多数のため、Phase 43 以降の後続フェーズで設計する。
- P2-Core については Phase 41 で canonical Normalized 化が完了しており、Structured→MIR は比較テスト用 / フォールバック用の経路として扱う。
- P2-Core については Phase 41 で canonical Normalized 化が完了しており、Structured→MIR は比較テスト用 / soft fallbackJoinIR 内)の経路として扱う。
- P2-Mid のうち、Phase 43 ではまず `_parse_number` を第 1 候補、`_atoi` 本体を第 2 候補として扱い、Normalized→MIR(direct) に必要な追加インフラEnvLayout 拡張 / JpInst パターン拡張)を段階的に入れていく前提を整理した。
### 3.20 Phase 43-NORM-CANON-P2-MID JsonParser 本命 P2_parse_number/_atoiへの適用 ✅ COMPLETE

View File

@ -58,9 +58,9 @@ shadowing の有無は言語中枢なので放置できない)。
追加したスモーク:
- `tools/smokes/v2/profiles/quick/core/phase215/scope_shadow_vm.sh`
- 観測: `local x=1 { local x=2 } return x``rc=2`inner `local x` が outer を上書きして leak
- 観測Phase 67 当時): `local x=1 { local x=2 } return x``rc=2`inner `local x` が outer を上書きして leak
- `tools/smokes/v2/profiles/quick/core/phase215/scope_assign_creates_local_vm.sh`
- 観測: `{ y = 42 } return y``rc=42`(束縛が block 外へ leak
- 観測Phase 67 当時): `{ y = 42 } return y``rc=42`(束縛が block 外へ leak
再現コマンド:
@ -85,3 +85,25 @@ shadowing の有無は言語中枢なので放置できない)。
Phase 67 の観測de facto 実装から、Phase 68 はまず AMIR スコープフレーム)に進むのが安全。
その上で、Ownership/Relay が shadowing を正確に扱う必要が出た箇所だけを Phase 69+ で BindingId 化するのが最小差分になる。
---
## Status updatePhase 68/69 反映)
この設計分岐は実際に Phase 68/69 で完了した。
- Phase 68: MIR 側で lexical scope を実装
- `{...}`Program/ `ScopeBox` を lexical scope として扱い、`local` shadowing を正しく復元。
- “未宣言名への代入はエラー” を SSOTquick-reference/LANGUAGE_REFERENCEに揃えて Fail-Fast 化。
- プローブは仕様固定へ更新:
- `scope_shadow_vm` の期待は `rc=1`outer が保持される)
- `scope_assign_creates_local_vm` は “未宣言代入はエラー” を検証
- `scope_loop_body_local_vm` を追加loop body local が外へ leak しない)
- Phase 69: Ownership/Relay 側で shadowing-aware 化
- `AstOwnershipAnalyzer` を内部 `BindingId` で分離し、ネスト block local が loop carriers/relay に混線しないように修正。
次の焦点は、Phase 65 で定義した merge relay / 本番 multihop の実行導線Phase 70+)に戻る。
関連:
- Phase 68lexical scope 実装): `src/mir/builder/vars/lexical_scope.rs`commit `1fae4f16`
- Phase 69shadowing-aware ownership: `src/mir/join_ir/ownership/ast_analyzer.rs`commit `795d68ec`