Unify condition lowering logic across Pattern 2/4 with trait-based API. New infrastructure: - condition_lowering_box.rs: ConditionLoweringBox trait + ConditionContext (293 lines) - ExprLowerer implements ConditionLoweringBox trait (+51 lines) Pattern migrations: - Pattern 2 (loop_with_break_minimal.rs): Use trait API - Pattern 4 (loop_with_continue_minimal.rs): Use trait API Benefits: - Unified condition lowering interface - Extensible for future lowering strategies - Clean API boundary between patterns and lowering logic - Zero code duplication Test results: 911/911 PASS (+2 new tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
120 lines
6.9 KiB
Markdown
120 lines
6.9 KiB
Markdown
# 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-Fast(`Result::Err`)で返す。
|
||
|
||
---
|
||
|
||
## 2. bool_expr_lowerer.rs
|
||
|
||
- 役割:
|
||
- 「MIR 向け」の boolean 式 lowering(AST → 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.rs(LoopBodyLocalInitLowerer)
|
||
|
||
- 役割:
|
||
- ループ本体の `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
|
||
- MethodCall(`s.substring`, `digits.indexOf`)→ `emit_method_call_init` 経由で MethodCallLowerer に委譲
|
||
- 制約:
|
||
- 変数解決は ConditionEnv + 既存の LoopBodyLocalEnv(cascading)のみ。
|
||
- サポート外のリテラル種別・演算子・複雑な式は Fail-Fast。
|
||
- lowering 対象は「init 式」だけで、更新式(UpdateExpr)は別の箱(CarrierUpdateEmitter)が担当。
|
||
|
||
---
|
||
|
||
## 4. method_call_lowerer.rs(MethodCallLowerer)
|
||
|
||
- 役割:
|
||
- 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.rs(CarrierUpdateEmitter)
|
||
|
||
- 役割:
|
||
- LoopUpdateAnalyzer で分類された UpdateExpr(`sum = 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 ベースの旧 API(body-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` + `UpdateEnv`(UpdateExpr ベース)
|
||
- 変数解決も 3 系統に分かれている:
|
||
- `ConditionEnv`(loop param / captured / condition-only)
|
||
- `LoopBodyLocalEnv`(body 内 `local`)
|
||
- `UpdateEnv`(ConditionEnv + LoopBodyLocalEnv の合成ビュー)
|
||
- 将来の ExprLowerer/ScopeManager では、これらを
|
||
- 「式 lowering の SSOT」として ExprLowerer
|
||
- 「名前解決の SSOT」として ScopeManager
|
||
に段階統合していくのがターゲット、という整理になっているよ。
|
||
Status: Active
|
||
Scope: Expr Lowering 在庫(JoinIR/ExprLowerer ライン)
|