- Integrated LoopBodyLocalInitLowerer into Pattern2 lowering - Fixed ValueId double-allocation issue (delegate to InitLowerer) - Added body_ast parameter to lower_loop_with_break_minimal() - Fixed json_program_loop.rs test for body-local scope - New test: phase191_body_local_atoi.hako (expected: 123) Supported init expressions: - Integer literals, variable references, binary operations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9.4 KiB
Phase 191: Body-Local Init & Update Lowering Integration
Status: Ready for Implementation Date: 2025-12-09 Prerequisite: Phase 190-impl complete (NumberAccumulation + PHI wiring fixed)
目的
Phase 184/186 で作った LoopBodyLocalEnv, UpdateEnv, LoopBodyLocalInitLowerer を
Pattern2/4 の中に本番統合して、local digit = ... などの body-local を JoinIR/MIR にきちんと落とす。
P2/P4 の既存ループ(_atoi など)を、body-local を含んだ形でも JoinIR で動かせるようにする。
Task 191-1: 対象ケースの再確認(1本に絞る)
目標
「いま body-local が原因で JoinIR を OFF にしている代表ループ」を 1 本だけ選ぶ。
候補
// _atoi 簡略版
local digit = s[i] - '0'
result = result * 10 + digit
または body-local を使う最小テスト:
// phase191_body_local_atoi.hako
static box Main {
main() {
local result = 0
local i = 0
loop(i < 3) {
local digit = i + 1 // body-local
result = result * 10 + digit
i = i + 1
}
print(result) // Expected: 123
return 0
}
}
成果物
- 選定した代表ループのファイルパス
- なぜ現在 JoinIR で通らないかの説明(body-local init が emit されていない)
Task 191-2: LoopBodyLocalInitLowerer の統合
対象ファイル
src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs- 必要なら
pattern4_with_continue.rsも
実装内容
ループ lowering の流れの中で:
-
ループ本体 AST を
LoopBodyLocalInitLowererに渡して、 body-local のlocal定義 (digit = ...) を JoinIR に emit しつつ、LoopBodyLocalEnvにname -> join_idを登録させる。 -
ここで emit するのは「init 分」だけ(Update 分は既に
CarrierUpdateEmitter+UpdateEnvに任せる)。
init emission の位置
- ループ body の 先頭(carrier update より前)に出るようにする。
- JoinIR 側の ValueId 空間は、Phase 190-impl-D での衝突回避ルール (
body_local_start_offset) に従う。
コード変更例
// pattern2_with_break.rs 内
// Phase 191: Emit body-local initializations
let body_local_env = LoopBodyLocalInitLowerer::lower_init(
&body_ast,
&mut join_builder,
&mut alloc_body_local_value,
)?;
// Phase 191: Create UpdateEnv with both condition and body-local
let update_env = UpdateEnv::new(condition_env.clone(), body_local_env.clone());
// Emit carrier updates using UpdateEnv
for (carrier_name, update_expr) in &carrier_info.updates {
CarrierUpdateEmitter::emit_carrier_update_with_env(
&mut join_builder,
carrier_name,
update_expr,
&update_env,
)?;
}
Task 191-3: UpdateEnv 統合の確認
対象ファイル
src/mir/join_ir/lowering/carrier_update_emitter.rs(すでに UpdateEnv 対応済み)
確認内容
選んだ代表ループで:
UpdateEnvが:ConditionEnv(LoopParam / OuterLocal)LoopBodyLocalEnv(今回 lower した init の join_id) 両方を見てdigitやtempを正しく解決できているか確認。
ユニットテスト追加
body-local digit を含む NumberAccumulation 更新を与えて、
JoinIR 側で Mul/Add 生成がエラーなく通ること:
#[test]
fn test_number_accumulation_with_body_local() {
// UpdateEnv with body-local "digit" → ValueId(10)
let mut body_local_env = LoopBodyLocalEnv::new();
body_local_env.register("digit", ValueId(10));
let condition_env = ConditionEnv::new();
let update_env = UpdateEnv::new(condition_env, body_local_env);
// Resolve "digit" should return ValueId(10)
assert_eq!(update_env.resolve("digit"), Some(ValueId(10)));
}
Task 191-4: E2E テスト
テストケース
191-1 で選んだ Minimal _atoi ループを:
- body-local 版(
local digit = ...)に戻して、 NYASH_JOINIR_CORE=1で実行 → 期待値が返ることを確認。
# E2E テスト実行
./target/release/hakorune apps/tests/phase191_body_local_atoi.hako
# Expected output: 123
退行チェック
- 既存の int-only ループ(body-local なし)が引き続き動くこと
phase190_atoi_impl.hako→ 12phase190_parse_number_impl.hako→ 123
- Trim/JsonParser の P5/P2 ラインに影響がないこと
Task 191-5: ドキュメント更新
更新対象
-
phase184-body-local-mir-lowering.md / phase186-body-local-init-lowering.md:
- 「Phase 191 で Pattern2/4 に統合完了」と追記
- 代表ループ名と、init → UpdateEnv → PHI → ExitLine までの流れを 1 ケースだけ図解
-
CURRENT_TASK.md:
- Phase 191: 完了マーク
- 残タスク(もし他のループは後回しにするなら)を更新
-
joinir-architecture-overview.md:
- Section 7.2 の残タスク「body-local 変数の init + update lowering」を完了マークに更新
成功基準
- 代表ループ(body-local 版
_atoi)が JoinIR only で期待値を返す - 既存テスト(phase190_*.hako)が退行しない
- UpdateEnv が body-local 変数を正しく解決できる
- ドキュメントが更新されている
実装完了レポート (2025-12-09)
実装概要
Phase 191 が完全成功しました! LoopBodyLocalInitLowerer を Pattern2 に統合し、body-local 変数の初期化式を JoinIR に正しく降下できるようになりました。
主な変更
-
loop_with_break_minimal.rs:- 関数シグネチャに
body_ast: &[ASTNode]を追加 body_local_env: Option<&mut LoopBodyLocalEnv>に変更(mutable)- ループ body の先頭で
LoopBodyLocalInitLowererを呼び出し、初期化式を JoinIR に emit - Carrier update の前に body-local init を配置(正しい依存順序)
- 関数シグネチャに
-
pattern2_with_break.rs:collect_body_local_variables呼び出しを削除(ValueId の二重割り当てを回避)- 空の
LoopBodyLocalEnvを作成し、LoopBodyLocalInitLowererに委譲 lower_loop_with_break_minimalに_bodyAST を渡すよう修正
-
テストファイル:
apps/tests/phase191_body_local_atoi.hako新規作成local digit = i + 1パターンで body-local 変数を使用result = result * 10 + digitで NumberAccumulation パターン検証
-
テスト修正:
tests/json_program_loop.rsのprogram_loop_body_local_exitを修正- スコープ外の body-local 変数参照を削除(正しい動作に修正)
実行結果
$ ./target/release/hakorune apps/tests/phase191_body_local_atoi.hako
123 # ✅ 期待値通り
$ ./target/release/hakorune apps/tests/phase190_atoi_impl.hako
12 # ✅ 退行なし
$ ./target/release/hakorune apps/tests/phase190_parse_number_impl.hako
123 # ✅ 退行なし
$ cargo test --release json_program_loop
test json_loop_simple_verifies ... ok
test json_loop_body_local_exit_verifies ... ok
test json_loop_with_continue_verifies ... ok
# ✅ 全テストパス
技術的発見
-
ValueId 二重割り当て問題:
- 旧実装:
collect_body_local_variablesが ValueId を事前割り当て →LoopBodyLocalInitLowererがスキップ - 解決: 空の
LoopBodyLocalEnvを渡し、LoopBodyLocalInitLowererに完全委譲
- 旧実装:
-
JoinIR ValueId 空間:
- JoinIR は独立した ValueId 空間を持つ(0 から開始)
- Host ValueId へのマッピングは merge 段階で実施
body_local_start_offsetは Host 空間の概念であり、JoinIR には不要
-
UpdateEnv の優先順位:
- ConditionEnv(ループパラメータ・条件変数)が最優先
- LoopBodyLocalEnv(body-local 変数)がフォールバック
- この順序により、シャドウイングが正しく動作
制限事項
現在の実装では以下の初期化式のみサポート:
- 整数リテラル:
local x = 42 - 変数参照:
local y = i - 二項演算:
local z = i + 1,local w = pos - start
未サポート(Fail-Fast):
- メソッド呼び出し:
local s = str.substring(...) - 文字列操作:
local t = s + "abc" - 複雑な式: ネストした呼び出し、非算術演算
次のステップ
Phase 191 で以下が達成されました:
- Pattern 2 への body-local init lowering 統合
- UpdateEnv による body-local 変数解決
- NumberAccumulation パターンでの動作検証
- 既存テストの退行なし
今後の拡張:
- Pattern 4 (continue) への同様の統合(必要に応じて)
- 文字列初期化式のサポート(Phase 188 の延長)
- メソッド呼び出し初期化式のサポート(Phase 192+)
関連ファイル
インフラ(Phase 184 で実装済み)
src/mir/join_ir/lowering/loop_body_local_env.rssrc/mir/join_ir/lowering/update_env.rssrc/mir/join_ir/lowering/carrier_update_emitter.rs
統合対象
src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rssrc/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs
テストファイル
apps/tests/phase191_body_local_atoi.hako(新規作成)apps/tests/phase190_atoi_impl.hako(退行確認)apps/tests/phase190_parse_number_impl.hako(退行確認)