Files
hakorune/docs/development/current/main/joinir-architecture-overview.md
nyash-codex 88400e7e22 feat(joinir): Phase 171-C-2 Trim pattern detection in LoopBodyCarrierPromoter
Implements the Trim pattern detection logic for carrier promotion:

- find_definition_in_body(): Iterative AST traversal to locate variable definitions
- is_substring_method_call(): Detects substring() method calls
- extract_equality_literals(): Extracts string literals from OR chains (ch == " " || ch == "\t")
- TrimPatternInfo: Captures detected pattern details for carrier promotion

This enables Pattern 5 to detect trim-style loops:
```hako
loop(start < end) {
    local ch = s.substring(start, start+1)
    if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
        start = start + 1
    } else {
        break
    }
}
```

Unit tests cover:
- Simple and nested definition detection
- substring method call detection
- Single and chained equality literal extraction
- Full Trim pattern detection with 2-4 whitespace characters

Next: Phase 171-C-3 integration with Pattern 2/4 routing

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 23:09:25 +09:00

13 KiB
Raw Blame History

JoinIR Architecture Overview (20251206)

このドキュメントは、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. 式としての戻り値とキャリア更新を分離する

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

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

    • JoinIR が対応していないループパターン / if パターンは、必ず [joinir/freeze] 等で明示的にエラーにする。
    • LoopBuilder 等へのサイレントフォールバックは禁止Phase 186187 で完全削除済み)。

2. 主な箱と責務

2.1 Loop 構造・検出ライン

  • LoopFeatures / LoopPatternKind / router

    • ファイル:
      • src/mir/loop_pattern_detection.rs
      • src/mir/builder/control_flow/joinir/patterns/router.rs
    • 責務:
      • AST からループ構造の特徴(has_break, has_continue, has_if_else_phi, carrier_count 等)を抽出。
      • classify(&LoopFeatures) で Pattern14 に分類。
      • LOOP_PATTERNS テーブルを通じて該当 lowererpattern*_minimal.rsにルーティング。
      • Phase 170C 系で LoopUpdateSummary(各キャリアの UpdateKind 情報)を統合し、
        CaseALoweringShape が関数名ではなく構造+更新パターンだけを見て判定できるようにする計画。
  • Pattern Lowerers (Pattern14)

    • ファイル例:
      • simple_while_minimal.rsPattern1
      • loop_with_break_minimal.rsPattern2
      • loop_with_if_phi_minimal.rsPattern3
      • loop_with_continue_minimal.rsPattern4
    • 責務:
      • LoopScopeShape / AST / LoopFeatures を入力として JoinIR の JoinModule を構築。
      • JoinFragmentMeta{ expr_result, exit_meta } を返し、出口情報を ExitLine に渡す。
      • host/MIR の ValueId は一切扱わないJoinIR ローカルの ValueId のみ)。
  • CommonPatternInitializer (Phase 33-22)

    • ファイル: src/mir/builder/control_flow/joinir/patterns/common_init.rs
    • 責務:
      • 全 Pattern 共通の初期化ロジック統一化(ループ変数抽出 + CarrierInfo 構築)。
      • All 4 loop patterns use this for unified initialization, guaranteeing boundary.loop_var_name is always set and preventing SSA-undef bugs.
  • JoinIRConversionPipeline (Phase 33-22)

    • ファイル: src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs
    • 責務:
      • JoinIR → MIR 変換フロー統一化JoinModule → MirModule → merge_joinir_mir_blocks
      • Single entry point for JoinIR→MIR conversion, encapsulating phases 1-6 and ensuring consistent transformation across all patterns.

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

  • BoolExprLowerer

    • ファイル: src/mir/join_ir/lowering/bool_expr_lowerer.rs
    • 責務:
      • AST の boolean 式 → MIR の Compare/BinOp/UnaryOp に lowering通常の if/while 用)。
      • <, ==, !=, <=, >=, >&&, ||, ! の組合せを扱う。
  • condition_to_joinir + ConditionEnv/ConditionBinding

    • ファイル: src/mir/join_ir/lowering/condition_to_joinir.rs
    • 責務:
      • ループ lowerer 用の「AST 条件 → JoinIR Compute命令列」。
      • ConditionEnv 経由で「変数名 → JoinIR ValueId」のみを見る。
      • host 側の ValueId は ConditionBinding { name, host_value, join_value } として JoinInlineBoundary に記録する。
  • LoopConditionScopeBoxPhase 170-D 実装済み)

    • ファイル: src/mir/loop_pattern_detection/loop_condition_scope.rs
    • 責務:
      • 条件式に登場する変数が、ループパラメータLoopParam/ループ外ローカルOuterLocal/ループ本体ローカルLoopBodyLocalのどれかを分類する。
      • Pattern2/4 が「対応してよい条件のスコープ」を判定するための箱。
      • ループ本体ローカルを条件に含む高度なパターンは、LoopBodyCarrierPromoterPhase 171 で carrier に昇格させる。
    • Bug Fix2025-12-07:
      • 関数パラメータが LoopBodyLocal と誤分類される問題を修正。
      • condition_var_analyzer.rsis_outer_scope_variable() で、variable_definitions に含まれない変数を OuterLocal とする。
      • これにより JsonParserBox などの関数パラメータを含むループが正しく動作。
  • LoopBodyCarrierPromoterPhase 171-C-1 実装中)

    • ファイル: src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs
    • 責務:
      • LoopBodyLocal 変数を carrier に昇格させ、Pattern 2/4 で処理可能にする。
      • 昇格成功 → Pattern 2/4 にルーティング(新しい carrier 情報付き)。
      • 昇格失敗 → UnsupportedPatternFail-Fast
    • Pattern 2/4 + Pattern 5 の境界線:
      • Pattern 2/4 の守備範囲: LoopParam + OuterLocal のみ。LoopBodyLocal 条件は受け入れない。
      • Pattern 5 の守備範囲: LoopBodyLocal を carrier に昇格。成功なら Pattern 2/4 へ委譲。
      • 境界: LoopConditionScopeBox が LoopBodyLocal 検出 → LoopBodyCarrierPromoter で昇格試行。
    • Design StrategyDesign D: Evaluated Bool Carrier:
      • ch == " " || ... のような条件を is_whitespace (bool carrier) に変換。
      • 昇格例:
        // Before (blocked)
        loop(start < end) {
            local ch = s.substring(start, start+1)
            if ch == " " || ... { ... } else { break }
        }
        
        // After (Pattern2 compatible)
        local is_whitespace = true
        loop(start < end && is_whitespace) {
            local ch = s.substring(start, start+1)
            is_whitespace = (ch == " " || ...)
            if is_whitespace { ... } else { break }
        }
        
    • Current StatusPhase 171-C-1:
      • API 定義: PromotionRequestPromotionResult
      • Skeleton 実装: LoopBodyLocal 検出・定義探索
      • Promotion logic: Phase 171-C-2 で Trim パターンの実際の昇格ロジックを実装予定
    • 詳細: docs/development/current/main/phase171-pattern5-loop-inventory.md

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

  • CarrierInfo / LoopUpdateAnalyzer

    • ファイル:
      • src/mir/join_ir/lowering/carrier_info.rs
      • LoopUpdateAnalyzer 周辺
    • 責務:
      • ループ内で更新される変数carrierの名前と host ValueId を検出。
      • 更新式(sum = sum + i, count = count + 1 等)を UpdateExpr として保持。
  • ExitMeta / JoinFragmentMeta

    • ファイル: carrier_info.rs
    • 責務:
      • JoinIR lowerer が「どの carrier が、どの JoinIR ValueId で出口に出るか」を記録。
      • JoinFragmentMeta の一部として expr_result: Option<ValueId>exit_meta をまとめる。
  • ExitMetaCollector

    • ファイル: src/mir/builder/control_flow/joinir/merge/exit_line/meta_collector.rs
    • 責務:
      • ExitMeta + CarrierInfo から Vec<LoopExitBinding{ carrier_name, join_exit_value, host_slot }> を構築。
      • 副作用なしの pure function。
  • JoinInlineBoundary

    • ファイル: src/mir/join_ir/lowering/inline_boundary.rs
    • フィールド(主なもの):
      • join_inputs / host_inputs:ループパラメータの橋渡し
      • condition_bindings: Vec<ConditionBinding>:条件専用変数の橋渡し
      • exit_bindings: Vec<LoopExitBinding>:キャリア出口の橋渡し
    • 責務:
      • 「host 関数 ↔ JoinIR fragment」の境界情報の SSOT。
  • BoundaryInjector

    • ファイル: src/mir/builder/joinir_inline_boundary_injector.rs
    • 責務:
      • join_inputs + host_inputs / condition_bindings に基づき、entry block に Copy 命令を挿して host→JoinIR を接続。
  • 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、 remapper と組み合わせて builder.variable_map のキャリアスロットを更新Reconnector
      • expr 用の PHI には一切触れないcarrier 専用ライン)。

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

  • exit_phi_builder

    • ファイル: src/mir/builder/control_flow/joinir/merge/exit_phi_builder.rs
    • 責務:
      • JoinIR fragment が「式としての戻り値expr_result」を持つ場合にだけ、 Return 値を exit block の PHI にまとめて 1 つの ValueId を返す※Phase 3316 で正式再実装予定)。
      • ループキャリア(start/end/sumは扱わないcarrier は ExitLine 専用ライン)。
  • InstructionRewriterexpr_result のみを exit_phi_inputs に流す)

    • ファイル: instruction_rewriter.rs
    • 責務:
      • JoinFragmentMeta.expr_resultSome の場合だけ、該当 return 値を exit_phi_inputs に積むのが理想形。
      • carrier 用の return/jump は ExitMeta/ExitLine 側で扱う。
      • 現状Phase 3315 時点):
        • SSAundef を避けるため、一時的に exit_phi_inputs / carrier_inputs の収集を停止している。
        • そのため「ループを式として評価する」ケースでは PHI を経由した expr 結果はまだ生成されない。
        • これは 一時的な止血措置 であり、Phase 3316 で「Loop ヘッダ PHI を出口値の SSOT とする」設計に差し替える予定。

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/ValueID remap
    • JoinIR 関数群の inline
    • Return→jump の書き換え
    • expr result 用 PHIexit_phi_builder
    • ExitLineOrchestratorExitMetaCollector + ExitLineReconnector を順に実行。

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


4. 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 等