Files
hakorune/docs/development/current/main/phase230-expr-lowering-inventory.md
nyash-codex 13a676d406 feat(joinir): Phase 231 - ExprLowerer/ScopeManager pilot implementation
Pilot implementation of unified expression lowering for Pattern2 break conditions:

New files:
- scope_manager.rs (280 lines) - ScopeManager trait + Pattern2ScopeManager
- expr_lowerer.rs (455 lines) - ExprLowerer with Condition context support

Features:
- Unified variable lookup across ConditionEnv/LoopBodyLocalEnv/CapturedEnv/CarrierInfo
- Pre-validation of condition AST before lowering
- Fail-safe design with fallback to legacy path
- 8 new unit tests (all pass)

Integration:
- Pattern2 break condition uses ExprLowerer for pre-validation
- Existing proven lowering path preserved
- Zero impact on existing functionality (890/897 tests pass)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 22:48:45 +09:00

6.9 KiB
Raw Blame History

Phase 230: Expr Lowering Inventory

このメモは、既存の式 lowering がどこに散らばっているかを棚卸しするためのインベントリだよ。
Phase 230 では「コードをいじらずに把握だけする」のが目的。


1. condition_to_joinir.rs / condition_lowerer.rs

  • 役割:
    • ループの条件式header 条件 / break 条件)を AST → JoinIR の Compare/BinOp/UnaryOp 列に落とす高レベル入口。
    • ConditionEnv を使って「変数名 → JoinIR ValueId」の解決を行う。
  • 主な機能:
    • lower_condition_to_joinir(ast, alloc_value, &ConditionEnv):
      • 二項比較(var < literal, var == var)を JoinIR Compare に lowering。
      • ConditionPatternBox による正規化後の単純条件を対象。
    • lower_value_expression(ast, alloc_value, &ConditionEnv, &mut instructions):
      • 条件式の内部で出てくるサブ式(i+1, s.length(), digits.indexOf(ch) など)を JoinIR 値に潰す。
      • MethodCallLowerer を経由してメソッド呼び出しを BoxCall に変換。
  • 制約:
    • JoinIR 専用MirBuilder には触らない)。
    • 変数解決は ConditionEnv に限定LoopBodyLocalEnv や UpdateEnv には直接アクセスしない)。
    • support 対象外の AST ノードは Fail-FastResult::Err)で返す。

2. bool_expr_lowerer.rs

  • 役割:
    • 「MIR 向け」の boolean 式 loweringAST → MirBuilder / SSAを行う旧来の箱。
    • OR チェーンや &&/||/! を MIR の Compare / BinOp / UnaryOp に展開する。
  • 主な機能:
    • BoolExprLowerer::lower_condition(&ASTNode) -> Result<ValueId, String>:
      • BinaryOp比較演算子 + &&/||を再帰的に潰し、MirInstruction を emit。
      • 変数・リテラル・メソッド呼び出しなどは MirBuilder の build_expression に委譲。
  • 制約:
    • MirBuilder 前提の API で、JoinIR condition_to_joinir とは別ライン。
    • 現時点では「ほぼ未使用(テストもコメントアウト)」扱いの歴史的モジュール。
    • condition_to_joinir 側と直接の接点はなく、将来 ExprLowerer に統合する際の候補。

3. loop_body_local_init.rsLoopBodyLocalInitLowerer

  • 役割:
    • ループ本体の local 宣言の初期化式を AST → JoinIR に落として LoopBodyLocalEnv に格納する。
    • 「body-local 変数の定義側init」専用の lowering。
  • 主な機能:
    • lower_inits_for_loop(body_ast, &mut LoopBodyLocalEnv):
      • ループ本体 AST から ASTNode::Local をスキャンし、各変数の init 式を順番に処理。
    • lower_init_expr(expr, &LoopBodyLocalEnv) -> Result<ValueId, String>:
      • リテラル(整数/文字列)→ Const
      • 変数参照 → ConditionEnv 経由で解決
      • 二項演算(+ - * /)→ BinOp
      • MethodCalls.substring, digits.indexOf)→ emit_method_call_init 経由で MethodCallLowerer に委譲
  • 制約:
    • 変数解決は ConditionEnv + 既存の LoopBodyLocalEnvcascadingのみ。
    • サポート外のリテラル種別・演算子・複雑な式は Fail-Fast。
    • lowering 対象は「init 式」だけで、更新式UpdateExprは別の箱CarrierUpdateEmitterが担当。

4. method_call_lowerer.rsMethodCallLowerer

  • 役割:
    • MethodCall AST ノードを CoreMethodId メタデータに基づいて JoinIR BoxCall に lowering する箱。
    • 同じメソッド呼び出しでも「条件文から使うか」「init から使うか」でホワイトリストを分けている。
  • 主な機能:
    • lower_for_condition(recv_val, method_name, args, alloc, &ConditionEnv, &mut instructions):
      • allowed_in_condition() に通る CoreMethodId だけ許可(例: length, 一部の indexOf)。
      • 引数は condition_lowerer::lower_value_expression で JoinIR 値に lowering。
    • lower_for_init(recv_val, method_name, args, alloc, &ConditionEnv, &LoopBodyLocalEnv, &mut instructions):
      • allowed_in_init() に通るメソッド(substring, indexOf など)を body-local init 用に lowering。
      • 引数の変数は LoopBodyLocalEnv → ConditionEnv の優先順で解決cascading local をサポート)。
    • lower_arg_with_cascading:
      • 引数用の小さなヘルパー。変数なら LoopBodyLocalEnv/ConditionEnv を見て、それ以外は condition_lowerer に委譲。
  • 制約:
    • CoreMethodId メタデータが前提(メソッド名や Box 名のハードコード禁止)。
    • 文脈condition/initごとに別 API で呼び分ける必要がある。
    • 型情報は暗黙的CoreMethodId 側に埋め込まれており、TypeContext のような統一ビューはまだない)。

5. carrier_update_emitter.rsCarrierUpdateEmitter

  • 役割:
    • LoopUpdateAnalyzer で分類された UpdateExprsum = sum + digit など)を JoinIR 命令列に変換する。
    • 「キャリア更新の右辺式」を安全なパターンだけ受理して lowering するホワイトリスト箱。
  • 主な機能:
    • emit_carrier_update_with_env(carrier, &UpdateExpr, alloc, &UpdateEnv, &mut instructions):
      • UpdateRhs::Const → Const + BinOp(Add/Mul)。
      • UpdateRhs::Variable → UpdateEnv.resolve(name) 経由で条件変数・body-local を横断解決。
      • UpdateRhs::StringLiteral → Const(String)。
      • UpdateRhs::NumberAccumulation → base/digit 組み合わせを Mul + Add の2段構成で emit。
    • emit_carrier_update(レガシー):
      • ConditionEnv ベースの旧 APIbody-local 非対応)を後方互換のために残している。
  • 制約:
    • lowering 対象は「UpdateExpr に正規化済みの式」に限る(生 AST は扱わない)。
    • UpdateRhs::Other や method call を含む複雑な更新は can_lower() 側で reject される前提。
    • 型は整数/String の一部パターンに限定TypeContext への統合は未実施)。

6. 小まとめPhase 230 時点の散らばり方)

  • 「条件式」と「init/body-local」と「UpdateExpr」が、それぞれ別の箱で AST / 中間表現を潰している:
    • 条件式: condition_to_joinir + condition_lowerer+ 一部 BoolExprLowerer/MIR 側)
    • body-local init: LoopBodyLocalInitLowerer + MethodCallLowerer(lower_for_init)
    • carrier 更新: CarrierUpdateEmitter + UpdateEnvUpdateExpr ベース)
  • 変数解決も 3 系統に分かれている:
    • ConditionEnvloop param / captured / condition-only
    • LoopBodyLocalEnvbody 内 local
    • UpdateEnvConditionEnv + LoopBodyLocalEnv の合成ビュー)
  • 将来の ExprLowerer/ScopeManager では、これらを
    • 「式 lowering の SSOT」として ExprLowerer
    • 「名前解決の SSOT」として ScopeManager に段階統合していくのがターゲット、という整理になっているよ。