Files
hakorune/docs/development/current/main/joinir-architecture-overview.md
nyash-codex a722e51a56 docs: Phase 192-impl completion + Phase 193 MethodCall in Init design
Phase 192-impl documentation updates:
- joinir-architecture-overview.md: Section 2.2/7.2 updated with Phase 192 completion
  - ComplexAddendNormalizer AST preprocessing完了
  - Phase 193/194 roadmap追加

Phase 193 instruction document:
- phase193-init-methodcall-design.md: 5-task breakdown for MethodCall in init support
  - Task 193-1: Init expression inventory (indexOf, get patterns)
  - Task 193-2: LoopBodyLocalInitLowerer extension design
  - Task 193-3: Implementation - emit_method_call_init function
  - Task 193-4: E2E verification (phase193_init_method_call.hako)
  - Task 193-5: Documentation updates
  - Method whitelist approach (Fail-Fast for unsupported methods)
  - ConditionEnv-only receiver resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-09 04:28:10 +09:00

32 KiB
Raw Blame History

JoinIR Architecture Overview (20251208)

このドキュメントは、JoinIR ライン全体Loop/If lowering, ExitLine, Boundary, 条件式 loweringの 「箱」と「契約」を横串でまとめた設計図だよ。selfhost / JsonParser / hako_check など、 どの呼び出し元から見てもここを見れば「JoinIR 層の責務と流れ」が分かるようにしておく。

変更があったら、Phase ドキュメントではなく このファイルを随時更新する 方針。


1. 不変条件Invariants

JoinIR ラインで守るべきルールを先に書いておくよ:

  1. JoinIR 内部は JoinIR ValueId だけ

    • JoinIR lowering が発行する JoinInstValueId は、すべて alloc_value() で割り当てるローカル ID。
    • Rust/MIR 側の ValueIdbuilder.variable_map に入っている IDは、JoinIR には直接持ち込まない。
  2. host ↔ join の橋渡しは JoinInlineBoundary 系だけ

    • host から JoinIR への入力(ループ変数 / 条件専用変数)は
      • JoinInlineBoundary.join_inputs + host_inputs
      • JoinInlineBoundary.condition_bindingsConditionBinding だけで接続する。
    • 出力(キャリアの出口)は JoinInlineBoundary.exit_bindings に一本化する。
  3. LoopHeader PHI を SSA の単一源泉にする

    • ループ変数とキャリアは LoopHeaderPhiBuilder/LoopHeaderPhiInfo でヘッダ PHI を作り、これを「現在値」の SSOT にする。
    • exit 用の PHI も組むが、変数再接続や expr_result 収集はヘッダ PHI を経由して行うSSAundef 防止)。
  4. 式としての戻り値とキャリア更新を分離する

    • 「ループが式として値を返す」ケース(例: let r = loop_min_while(...))の出口は exit_phi_builder が扱う。
    • 「ループが状態更新だけする」ケース(例: trimstart/end)の出口は ExitLineExitMeta / ExitBinding / ExitLineReconnector だけが扱う。
  5. ループ制御 vs 条件式の分離

    • ループの「形」Pattern14, LoopFeaturesは control-flow 専用の箱が担当。
    • 条件式(i < len && (ch == " " || ch == "\t") 等)は BoolExprLowerer / condition_to_joinir が担当し、 ループパターンは boolean ValueId だけを受け取る。
  6. FailFast

    • JoinIR が対応していないループパターン / if パターンは、必ず [joinir/freeze] 等で明示的にエラーにする。
    • LoopBuilder 等へのサイレントフォールバックは禁止。
  7. Param の役割ParamRoleを分ける

    • JoinIR 側で扱うパラメータは概念的に 3 種類に分かれる:
      • 条件専用Condition param: 継続条件や break 条件だけに使う値
      • キャリアCarrier param: ループ状態pos/result など)として更新される値
      • 式結果Expr param: ループが式として返す値
    • ExitLine / Header PHI / InstructionRewriter は Carrier param だけ を対象にし、Condition/Expr param は上書きしない。
    • 現状は ConditionBinding/ExitMeta/JoinFragmentMeta で役割を区別しており、将来 ParamRole enum として明示する予定。
  8. LoopHeader PHI dst は予約領域(上書き禁止)

    • LoopHeaderPhiBuilder が生成したヘッダ PHI の dst ValueId は「現在のループ値」の SSOT として扱い、
      BoundaryInjector や InstructionRewriter が Copy などで二度書きすることを禁止する。
    • merge ラインでは「ヘッダ PHI dst に対する新しい定義が出てきたら debug モードで panic する」ことで契約違反を早期検出する。

2. 主な箱と責務

2.1 Loop 構造・検出ライン

  • LoopFeatures / LoopPatternKind / router

    • ファイル:
      • src/mir/loop_pattern_detection.rs
      • src/mir/builder/control_flow/joinir/patterns/router.rs
      • src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs
    • 責務:
      • AST から break/continue/ifelse PHI などの特徴を抽出ast_feature_extractor
      • classify(&LoopFeatures) で Pattern14 に分類し、テーブル駆動の LOOP_PATTERNS でルーティング。
      • ルータ順序は P4(continue) → P3(ifphi) → P1(simple) → P2(break) で固定(優先度フィールドはデバッグ用)。
  • Pattern Lowerers (Pattern14)

    • ファイル例:
      • pattern1_minimal.rsSimple while
      • pattern2_with_break.rsbreak 付き / Trim 昇格パスを含む)
      • pattern3_with_if_phi.rsifphi キャリア)
      • pattern4_with_continue.rscontinue を Select で表現)
    • 責務:
      • LoopScopeShape / AST / LoopFeatures を入力として JoinIR の JoinModule を構築。
      • JoinFragmentMeta{ expr_result, exit_meta } を返し、出口情報を ExitLine に渡す。
      • host/MIR の ValueId は一切扱わないJoinIR ローカルの ValueId のみ)。
  • Scope / Env Builders

    • loop_scope_shape_builder.rs: ループ本体ローカルの収集、LoopScopeShape 統一生成。
    • condition_env_builder.rs: 条件専用変数の環境と ConditionBinding を一括構築。
  • CommonPatternInitializer (Phase 33-22)

    • ファイル: src/mir/builder/control_flow/joinir/patterns/common_init.rs
    • 責務:
      • 全 Pattern 共通の初期化ロジック統一化(ループ変数抽出 + CarrierInfo 構築)。
      • 全パターンで boundary.loop_var_name を確実に設定し、SSAundef を防ぐ。
  • PatternPipelineContext (Phase 179-B)

    • ファイル: src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs
    • 責務:
      • 全 Pattern の前処理結果を格納する「解析済みコンテキスト箱」。
      • CommonPatternInitializer + LoopScopeShapeBuilder の結果を統一的に保持。
      • Pattern 1-4 の共通データloop_var_name, loop_var_id, carrier_info, loop_scopeを提供。
      • Pattern 2/4 専用データcondition_env, carrier_updates, trim_helperは Option で保持。
      • Analyzer-only dependencies: 解析ロジックのみ依存、JoinIR emission ロジックは含まない。
  • TrimLoopLowerer (P5 Dedicated Module) (Phase 180)

    • ファイル: src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs
    • 責務:
      • Trim/CharComparison (Pattern 5) 専用の lowering ロジックを一箇所に集約。
      • Pattern2/4 から呼ばれ、LoopBodyLocal 変数を carrier に昇格し、Trim パターンの break 条件を置き換える。
      • TrimPatternValidator/TrimPatternLowerer を内部で利用し、carrier 初期化コード生成・条件式置換を実行。
    • 入力:
      • MirBuilder, LoopScopeShape, loop_cond, break_cond, body, loop_var_name, carrier_info, alloc_join_value
    • 出力:
      • Some(TrimLoweringResult): Trim パターン検出・lowering 成功時(置換後条件、更新 carrier_info、condition_bindings
      • None: Trim パターンでない場合(通常ループ処理に戻る)
      • Err: Trim パターン検出したが lowering 失敗時
    • 使用元:
      • Pattern2 (pattern2_with_break.rs): Trim/P5 ロジックを完全委譲(~160 行削減)
      • Pattern4 (pattern4_with_continue.rs): 将来の Phase 172+ で Trim lowering 実装時に利用予定
    • デザイン原則:
      • Pure analysis container前処理結果のみ保持、emission なし)
      • Pattern-specific variantsOption でパターン固有データ管理)
      • Single source of truth全パターンが同じ前処理経路を使用
  • JoinIRConversionPipeline (Phase 33-22)

    • ファイル: src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs
    • 責務:
      • JoinIR → MIR 変換フロー統一化JoinModule → MirModule → merge_joinir_mir_blocks
      • JoinIR/MIR の関数数・ブロック数をログ出力し、全パターンが同じ入口でマージする。

2.2 条件式ライン(式の箱)

  • BoolExprLowerer / condition_to_joinir

    • ファイル:
      • src/mir/join_ir/lowering/bool_expr_lowerer.rs
      • src/mir/join_ir/lowering/condition_to_joinir.rs
    • 責務:
      • 通常の if/while 条件を MIR Compare/BinOp/UnaryOp へ lowering。
      • ループ lowerer 用の「AST 条件 → JoinIR Compute 命令列」を ConditionEnv とセットで構築。
  • ConditionEnv/ConditionBinding + ConditionEnvBuilder

    • ファイル:
      • src/mir/join_ir/lowering/condition_env.rs
      • src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs
    • 責務:
      • 変数名→JoinIR ValueId の環境を組み立て、host↔join の橋渡しを ConditionBinding に明示する。
      • Pattern 2 では break 条件の全変数をスキャンし、JoinInlineBoundary.condition_bindings に渡す。
  • LoopConditionScopeBoxPhase 170-D 実装済み)

    • ファイル: src/mir/loop_pattern_detection/loop_condition_scope.rs
    • 責務:
      • 条件式の各変数を LoopParam / OuterLocal / LoopBodyLocal に分類。
      • 関数パラメータ誤分類バグは condition_var_analyzer.rs の修正で解消済みOuterLocal として扱う)。
  • LoopBodyCarrierPromoterPhase 171-C-2 実装済み)

    • ファイル: src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs
    • 責務:
      • LoopBodyLocal を Trim パターンとして bool キャリアへ昇格substring + equality 連鎖を検出)。
      • 昇格成功 → CarrierInfo に統合し Pattern 2/4 へ橋渡し。昇格失敗は FailFast。
      • Pattern 2 は安全な Trim なら実際に前処理substring 生成 + 空白比較の初期化)を emit してから JoinIR lowering。
      • Pattern 4 は Trim 昇格が起きた場合はガード付きでエラーにし、未実装を明示FailFast
    • 汎用性:
      • Phase 173 で _skip_whitespaceJsonParserが Trim パターンで動作確認済み。
      • Phase 174 で _parse_string 最小化版(終端クォート検出)でも動作確認済み。
      • → 空白文字以外の文字比較ループにも対応可能TrimLoopHelper の汎用性実証)。
  • ContinueBranchNormalizer / LoopUpdateAnalyzer

    • ファイル:
      • src/mir/join_ir/lowering/continue_branch_normalizer.rs
      • src/mir/join_ir/lowering/loop_update_analyzer.rs
    • 責務:
      • else-continue を then-continue へ正規化し、Select ベースの continue を簡潔にする。
      • ループ本体で実際に更新されるキャリアだけを抽出Pattern 4 で不要キャリアを排除)。
  • LoopBodyLocalEnv / UpdateEnv / CarrierUpdateEmitterPhase 184, 191統合完了

    • ファイル:
      • src/mir/join_ir/lowering/loop_body_local_env.rs
      • src/mir/join_ir/lowering/update_env.rs
      • src/mir/join_ir/lowering/carrier_update_emitter.rs
      • src/mir/join_ir/lowering/loop_with_break_minimal.rsPhase 191統合
    • 責務:
      • LoopBodyLocalEnv: ループ本体で宣言された body-local 変数の名前→ValueId マッピングを管理(箱化設計)。
      • UpdateEnv: 条件変数ConditionEnvと body-local 変数LoopBodyLocalEnvを統合した変数解決層。
        • Priority order: 1. Condition variables高優先度 → 2. Body-local variablesフォールバック
      • CarrierUpdateEmitter: UpdateExpr を JoinIR 命令に変換する際、UpdateEnv を使用して body-local 変数をサポート。
        • emit_carrier_update_with_env(): UpdateEnv 版Phase 184 新規)
        • emit_carrier_update(): ConditionEnv 版(後方互換)
      • LoopBodyLocalInitLowerer: Phase 191 で Pattern2 に統合完了。
        • 対応済み init 式: 整数リテラル、変数参照、二項演算(local digit = i + 1
        • UpdateEnv の優先順位により ConditionEnv → LoopBodyLocalEnv の順で変数解決
    • 設計原則:
      • 箱理論: 各 Box が単一責任を持ち、境界明確。
      • 決定性: BTreeMap 使用で一貫した順序保証PHI 生成の決定性)。
    • Phase 192完了: Complex addendv = v*10 + f(x))は ComplexAddendNormalizer で temp に分解してから NumberAccumulation に載せる。
      • complex_addend_normalizer.rs: Pure AST transformer前処理箱
      • Pattern2 統合完了、emission ライン再利用(変更なし)
      • 制約: MethodCall を含む init 式は Phase 193 で対応予定

2.3 キャリア / Exit / Boundary ライン

  • CarrierInfo / LoopUpdateAnalyzer / CarrierUpdateEmitter

    • ファイル:
      • src/mir/join_ir/lowering/carrier_info.rs
      • src/mir/join_ir/lowering/loop_update_analyzer.rs
      • src/mir/join_ir/lowering/carrier_update_emitter.rs
    • 責務:
      • ループで更新される変数carrierを検出し、UpdateExpr を保持。
      • Pattern 4 では実際に更新されるキャリアだけを残す。
      • Phase 188 完了 : String 更新StringAppendChar/StringAppendLiteralを UpdateRhs ベースのホワイトリストで受理し、JoinIR BinOp を emit。
        • 許可: UpdateRhs::Const, UpdateRhs::Variable, UpdateRhs::StringLiteral
        • 拒否: UpdateRhs::Othermethod call / nested BinOp 等の複雑パターンのみ)
        • Pattern2/4 の can_lower() で選別、carrier_update_emitter.rs で JoinIR 生成
  • ExitMeta / JoinFragmentMeta

    • ファイル: carrier_info.rs
    • 責務:
      • JoinIR lowerer が出口の JoinIR ValueId を記録expr_result とキャリアを明確に分離)。
  • LoopHeader PHI Builder

    • ファイル:
      • src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs
      • loop_header_phi_builder.rs
    • 責務:
      • ループ変数とキャリアの PHI をヘッダブロックに生成し、entry/latch の 2 入力で SSA を確立。
      • instruction_rewriter が latch 側を埋めた後に finalize して挿入する。
  • JoinInlineBoundary

    • ファイル: src/mir/join_ir/lowering/inline_boundary.rs
    • 主フィールド:
      • join_inputs / host_inputs:ループパラメータの橋渡し
      • condition_bindings条件専用変数の橋渡しJoinIR ValueId を明示)
      • exit_bindingsキャリア出口の橋渡しcarrier 名を明示)
      • expr_result / loop_var_nameexpr result / ヘッダ PHI 生成用のメタ情報
    • 責務:
      • 「host ↔ JoinIR」の境界情報の SSOT。各パターン lowerer がここに全て詰めてから merge する。
  • BoundaryInjector

    • ファイル: src/mir/builder/joinir_inline_boundary_injector.rs
    • 責務:
      • join_inputscondition_bindings を entry block に Copy で注入し、JoinIR ローカル ID と host ID を接続。
  • ExitLine (ExitMetaCollector / ExitLineReconnector / ExitLineOrchestrator)

    • ファイル:
      • src/mir/builder/control_flow/joinir/merge/exit_line/mod.rs
      • exit_line/meta_collector.rs
      • exit_line/reconnector.rs
    • 責務:
      • ExitMeta から exit_bindings を構築Collector
      • 変数再接続はヘッダ PHI の dst を使って builder.variable_map を更新Reconnector
      • expr 用の PHI には一切触れないcarrier 専用ライン)。
  • JoinInlineBoundaryBuilderPhase 200-2 / Phase 201 完了)

    • ファイル: src/mir/join_ir/lowering/inline_boundary_builder.rs
    • 責務:
      • JoinInlineBoundary の構築を Builder パターンで統一化。
      • フィールド直書きの散乱を防ぎ、inputs/outputs/condition_bindings/exit_bindings/loop_var_name/expr_result の設定を fluent API で実施。
      • Phase 201 で Pattern1/2/3/4 全てに適用完了(境界情報組み立てを 1 箇所に集約)。
  • JoinIRVerifierPhase 200-3 追加)

    • ファイル: src/mir/builder/control_flow/joinir/merge/mod.rsdebug_assertions 専用関数)
    • 責務:
      • LoopHeader PHI / ExitLine 契約をデバッグビルドで検証する門番。
      • verify_loop_header_phis(): loop_var_name がある場合にヘッダ PHI が存在するか確認。
      • verify_exit_line(): exit_bindings が exit block に対応しているか確認。
      • verify_joinir_contracts(): merge_joinir_mir_blocks() の最後で全契約を一括チェック。
      • release ビルドでは完全に除去される(#[cfg(debug_assertions)])。

2.4 expr result ライン(式としての戻り値)

  • exit_phi_builder

    • ファイル: src/mir/builder/control_flow/joinir/merge/exit_phi_builder.rs
    • 責務:
      • JoinIR fragment が expr_result を持つときに exit ブロックへ PHI を生成。
      • carrier_inputs も受け取り exit ブロックに PHI を作るが、再接続の SSOT は LoopHeader PHIExitLine はヘッダ PHI を使用)。
  • InstructionRewriter

    • ファイル: instruction_rewriter.rs
    • 責務:
      • continuation 関数k_exitをスキップし、Return → exit ブロック Jump に変換。
      • JoinFragmentMeta.expr_result と exit_bindings をヘッダ PHI 経由で収集し、exit_phi_inputs / carrier_inputs を復活させたSSAundef 修正済み)。
      • tail call を Branch/Jump に書き換えつつ、LoopHeaderPhiInfo に latch 入力を記録する。

3. JoinIR → MIR 統合の全体フロー

  1. Pattern router が AST/LoopFeatures から Pattern14 を選択し、各 lowerer が (JoinModule, JoinFragmentMeta) を生成。
  2. JoinInlineBoundary が:
    • ループ入力join_inputs/host_inputs
    • 条件変数condition_bindings
    • キャリア出口exit_bindings を保持。
  3. merge_joinir_mir_blocks が(マルチ関数対応):
    • 全関数の BlockID を再割り当てblock_allocatorし、ValueId はパラメータを除外して収集。
    • Boundary の condition/exit Bindings の JoinIR ValueId も remap 対象に追加。
    • LoopHeader PHI を生成loop_header_phi_builderし、latch 側は instruction_rewriter が埋める。
    • instruction_rewriter で関数をマージしつつ Call→Jump に変換、k_exit 関数はスキップ。
    • BoundaryInjector で entry block に Copy を注入join_inputs + condition_bindings
    • Header PHI を finalize → exit_phi_builder で expr_result/carrier の exit PHI を構築。
    • ExitLineOrchestrator がヘッダ PHI dst を使って variable_map を更新。
    • host の現在ブロックから JoinIR entry へ jump を張り、exit ブロックに切り替える。

この全体フローの詳細は src/mir/builder/control_flow/joinir/merge/mod.rsphase-189-multi-function-mir-merge/README.md を参照。


4. JsonParser / Trim / P5 ループの現在地Phase 170181

4.1 JsonParser ループ空間と P1P5

Phase 181 で JsonParserBox 内の 11 ループを棚卸しした結果、 構造的には すべて JoinIR Pattern14 (+ P5) で扱える ことが分かったよ。

  • 既に JoinIR 経路で動作しているもの:
    • _skip_whitespaceP2 + P5 Trim
    • _trim leading/trailingP2 + P5 Trim
  • Phase 182 で P1/P2 パターン検証完了 :
    • Pattern1 (Simple): _match_literal 系ループで動作確認済みapps/tests/phase182_p1_match_literal.hako
    • Pattern2 (Break): 整数演算ループで動作確認済みapps/tests/phase182_p2_break_integer.hako
    • ブロッカー発見: 実際の JsonParser ループには 2 つの制約が必要:
      1. LoopBodyLocal 変数の扱い(ch, digit_pos, pos など)
        • 現状は Trim pattern 専用の carrier 昇格を試みてエラーになる
        • P1/P2 では純粋なローカル変数(昇格不要)として扱うべき
      2. 文字列連結フィルタPhase 178
        • num_str = num_str + ch のような string concat を保守的に reject
        • JsonParser では必須の操作なので段階的に有効化が必要
        • 設計原則:
          • string は「特別扱いのパターン」ではなく、あくまで MirType の 1 種類として扱う。
          • Pattern2/4 側で型名や変数名("result", "num_str" など)に依存した分岐は入れない。
          • LoopUpdateAnalyzer の UpdateKind / UpdateRhs で「安全な更新パターン」を列挙し、 そのうち string にも適用可能なものだけを ホワイトリストで許可する。
          • 実際の lowering は CarrierUpdateLowerer / 式 Lowerer 側で行い、JoinIR のループ形P1P4は増やさない。
      3. 数値の桁展開Phase 190 設計完了)
        • v = v * 10 + digit のような NumberAccumulation パターンを UpdateKind で whitelist 制御。
        • 型制約: Integer のみ許可String は StringAppendChar 使用)。
        • 検出: AST 構造解析名前依存禁止、Complex パターンは Fail-Fast で reject。
  • Phase 183 で LoopBodyLocal 役割分離完了 :
    • 設計: LoopBodyLocal を 2 カテゴリに分類:
      • Condition LoopBodyLocal: ループ条件header/break/continueで使用 → Trim 昇格対象
      • Body-only LoopBodyLocal: ループ本体のみで使用 → 昇格不要、pure local 扱い
    • 実装: TrimLoopLowerer に is_var_used_in_condition() ヘルパー追加
      • 条件で使われていない LoopBodyLocal は Trim 昇格スキップ
      • 5 つの unit test で変数検出ロジックを検証
    • テスト: apps/tests/phase183_body_only_loopbodylocal.hako で動作確認
      • [TrimLoopLowerer] No LoopBodyLocal detected トレース出力で body-only 判定成功
    • 次の課題→Phase 184 で対応): body-local 変数の MIR lowering 対応(local temp in loop body
      • Phase 183 では "Trim promotion しない" 判定まで完了
      • 実際の MIR 生成インフラは Phase 184 で実装済みPattern2/4 への統合は次フェーズ)

4.2 Body-local 変数の MIR lowering 基盤Phase 184

Phase 184 では、「条件には出てこない LoopBodyLocal 変数」を安全に JoinIR→MIR に落とすためのインフラ箱だけを追加したよ。

  • LoopBodyLocalEnv

    • 責務: ループ本体内で local 定義された変数の「JoinIR 側 ValueId のみ」を管理する。
    • 入力: ループ本体 AST / JoinIR ビルダー。
    • 出力: name -> join_value_id のマップ。
    • 特徴: host 側との対応は持たない。ConditionEnv とは完全に分離された「本体専用ローカル環境」。
  • UpdateEnv

    • 責務: UpdateExpr lowering 時の変数解決順序をカプセル化する。
    • 仕様: ConditionEnv(条件・キャリア)と LoopBodyLocalEnv(本体ローカル)を中で束ねて、 resolve(name) で「条件→ローカル」の順に ValueId を返す。
    • 利用箇所: CarrierUpdateEmitter / CarrierUpdateLowerer が、変数名ベースで UpdateExpr を JoinIR に落とす時に利用。
  • CarrierUpdateEmitter 拡張

    • 責務: LoopUpdateSummaryUpdateKindに応じて、int 系キャリア更新を JoinIR 命令に変換する。
    • 変更点: 直接 variable_map を読むのではなく、UpdateEnv 経由で名前解決するように変更。
    • 効果: 本体専用の LoopBodyLocal 変数(tempを、Pattern2/4 から安全に扱える土台が整った。

このフェーズではあくまで「ストレージ・名前解決・emit の箱」までで止めてあり、 Pattern2/4 への統合(実際に Body-local 更新を使うループを JoinIR 経路に載せるは次フェーズPhase 185 以降)の仕事として分離している。

  • 構造的に P1P4 で対応可能(代表例):
    • _parse_number / _atoiP2 Break- Phase 182 でブロッカー特定済み
    • _match_literalP1 Simple while- Phase 182 で動作確認済み
    • _parse_string / _parse_array / _parse_object P2 + P4 + P5 の組み合わせで表現可能なことを設計上確認済み)
  • 低優先度だが理論上は P1P4 からの拡張で吸収可能:
    • _unescape_string など、複雑な continue / 条件付き更新を含むループ

方針:

  • ループの「形」は P1P4 から増やさない
    複雑さLoopBodyLocal 条件、OR chain、continue 多用など)は BoolExprLowerer / ContinueBranchNormalizer / TrimLoopLowerer (P5) といった補助箱側で吸収する。
  • JsonParser 側の P5 適用Trim / _skip_whitespace / _parse_string 最小版)は実証済み。
    残りのループは Phase 17x18x で、P1P4+P5 の組み合わせとして段階的に実装していく。

5. selfhost / .hako JoinIR Frontend との関係

JoinIR は Rust 側だけでなく、将来的に .hako selfhost コンパイラ側でも生成・解析される予定だよ:

  • .hako 側の JsonParser/分析箱は、Program JSON / MIR JSON v1 を読んで JoinIR/MIR を解析する。
  • Rust 側 JoinIR ラインの設計変更(特に ValueId/ExitLine/Boundary 周り)は、 必ずこのファイルを更新してから .hako 側にも段階的に反映する方針。

「JoinIR の仕様」「箱の責務」「境界の契約」は、このファイルを SSOT として運用していく。


5. 関連ドキュメント

  • docs/development/current/main/10-Now.md
    • 全体の「いまどこ」を短くまとめたダッシュボード。
  • docs/private/roadmap2/phases/phase-180-joinir-unification-before-selfhost/README.md
    • JoinIR 統一フェーズ全体のロードマップと進捗。
  • 各 Phase 詳細:
    • 185188: Strict mode / LoopBuilder 削除 / Pattern14 基盤
    • 189193: Multi-function merge / Select bridge / ExitLine 箱化
    • 171172 / 3310/13: ConditionEnv, ConditionBinding, JoinFragmentMeta, ExitLineRefactor 等
  • docs/development/current/main/loop_pattern_space.md
    • JoinIR ループパターン空間の整理メモ。
      どの軸(継続条件 / break / continue / PHI / 条件変数スコープ / 更新パターン)でパターンを分けるか、
      そして P1P4 / Trim(P5) の位置づけと、今後追加候補のパターン一覧がまとまっている。

6. RoadmapJoinIR の今後のゴール)

ここから先の JoinIR の「目指す形」を、箱レベルでざっくり書いておくよ。フェーズ詳細は各 phase ドキュメントに分散させて、このセクションは常に最新の方向性だけを保つ。

6.1 直近Phase 176-177 まわり)

  • P5Trim/JsonParser 系)ループの複数キャリア対応 Phase 176 完了 (2025-12-08)
    • 完了内容:
      • Pattern2 lowerer を全キャリア対応に拡張(ヘッダ PHI / ループ更新 / ExitLine
      • CarrierUpdateLowerer ヘルパで UpdateExpr → JoinIR 変換を統一。
      • 2キャリアpos + resultE2E テスト完全成功。
    • 技術的成果:
      • CarrierInfo / ExitMeta / ExitLine / LoopHeaderPhiBuilder の multi-carrier 対応を Pattern2 lowerer で完全活用。
      • Trim pattern の「キャリア = ループ変数」という誤解を解消loop_var は特殊キャリア)。
    • 次のステップ (Phase 177):
      • JsonParser _parse_string 本体を P2+P5 で通すpos + result の 2 キャリアで実ループ動作確認)。

6.2 中期selfhost depth2 / JsonParser 本体)

  • JsonParserBox / Trim 系ループの本線化

    • 目標:
      • _trim / _skip_whitespace / _parse_string / _parse_array などの主要ループが、すべて JoinIR Pattern14 + P5 で通ること。
      • LoopConditionScopeBox + LoopBodyCarrierPromoter + TrimLoopHelper の上で安全に正規化できるループを広げていく。
    • 方針:
      • 「ループの形」は P1P4 から増やさず、複雑さは BoolExprLowerer / ContinueBranchNormalizer / P5 系の補助箱で吸収する。
      • LoopPatternSpace の P6/P7/P12 候補break+continue 同時 / 複数キャリア条件更新 / early returnは、実アプリで必要になった順に小さく足す。
  • selfhost depth2.hako JoinIR/MIR Frontend

    • 目標:
      • .hako → JsonParserBox → Program/MIR JSON → MirAnalyzerBox/JoinIrAnalyzerBox → VM/LLVM の深度 2 ループを、日常的に回せるようにする。
      • Rust 側の JoinIR は「JSON を受け取って実行・検証するランナー層」、.hako 側が「JoinIR/MIR を構築・解析する言語側 SSOT」という役割分担に近づける。
    • 前提:
      • 本ドキュメントjoinir-architecture-overview.mdを .hako 側の JoinIR 実装の参照設計として維持し、仕様変更は必ずここを更新してから .hako にも反映する。

6.3 当面やらないことNonGoals

  • ループパターンを闇雲に増やすこと
    • P1P4構造 P5bodylocal 条件を昇格する補助パス)を「骨格」とみなし、
      新しいパターンが必要になったときは LoopPatternSpace に追記してから、小さな箱で補う方針。
  • LoopBuilder の復活や、JoinIR 以外の別ラインによるループ lowering
    • LoopBuilder 系は Phase 186187 で完全に削除済み。
      ループに関する新しい要件はすべて JoinIR 側のパターン/箱の拡張で扱う。
  • JoinIR の中に言語固有のハードコード(特定 Box 名や変数名)を戻すこと
    • Trim/JsonParser 系は、構造パターンと補助箱Promoter/Helperで扱い、
      「sum」「ch」など名前ベースの判定は LoopUpdateSummary / TrimLoopHelper の内部に閉じ込める。

この Roadmap は、JoinIR 層の変更や selfhost 深度を進めるたびに更新していくよ。


7. JoinIR 第1章基盤完成サマリ2025-12-09 時点)

7.1 現在の対応状況

Pattern サポート:

Pattern 説明 状態
P1 Simple loop(cond) { body } 完成
P2 Break loop(cond) { if(...) break } 完成
P3 If-PHI loop { if(...) a else b; use(φ) } 完成
P4 Continue loop { if(...) continue } 完成
P5 Trim LoopBodyLocal → bool carrier 昇格 基本完成

UpdateKind サポート:

UpdateKind 状態
CounterLike i = i + 1
AccumulationLike sum = sum + x
StringAppendChar s = s + ch
StringAppendLiteral s = s + "lit"
NumberAccumulation v = v * 10 + digit (Phase 190)
Complex method call 含む Fail-Fast

アーキテクチャ SSOT ライン:

  • LoopHeaderPhiBuilder: ループ変数・キャリアの PHI を SSOT で生成
  • ExitLineReconnector: PHI dst → variable_map 接続
  • JoinInlineBoundaryBuilder: 全パターンで Builder パターン統一
  • JoinIRVerifier: デバッグビルドで契約検証
  • ExitLine Contract Verifier: PHI 配線検証Phase 190-impl-D

7.2 残タスクPhase 192+ で対応予定)

  1. body-local 変数の init + update lowering → Phase 191 完了

    • local digit = i + 1 のような body-local 変数の JoinIR/MIR 生成完了
    • 対応済み: 整数リテラル、変数参照、二項演算
    • テスト: phase191_body_local_atoi.hako → 期待値 123
  2. Complex addend 対応 → Phase 192 完了

    • v = v * 10 + digits.indexOf(ch) のような method call を含む NumberAccumulation対応
    • ComplexAddendNormalizer で temp = f(x) に分解してから NumberAccumulation に載せる実装完了
    • テスト: phase192_normalization_demo.hako → 123
    • 制約: MethodCall を含む init 式は Phase 193 で対応予定
  3. MethodCall を含む init 式の対応Phase 193

    • local digit = digits.indexOf(ch) のような MethodCall init の lowering
    • LoopBodyLocalInitLowerer 拡張BoxCall emission
    • メソッド whitelist: indexOf, substring 等
  4. JsonParser 残り複雑ループ・selfhost ループへの適用Phase 194+

    • _parse_array / _parse_objectP4 Continue + 複数 MethodCall
    • _unescape_string(複雑なキャリア + flatten
    • selfhost .hako コンパイラの全ループを JoinIR で処理