diff --git a/docs/development/current/main/phase80-bindingid-p3p4-plan.md b/docs/development/current/main/phase80-bindingid-p3p4-plan.md index b85f5873..c718d49c 100644 --- a/docs/development/current/main/phase80-bindingid-p3p4-plan.md +++ b/docs/development/current/main/phase80-bindingid-p3p4-plan.md @@ -1,15 +1,15 @@ # Phase 80: BindingId P3/P4 Expansion Plan -**Status**: Ready for Task 80-B (Pattern3 Wiring) +**Status**: Completed (commit `84129a7e`) **Created**: 2025-12-13 **Progress**: - ✅ Task 80-0: Current Status Verification (complete) - ✅ Task 80-A: SSOT Design Doc (complete) -- ⏳ Task 80-B: Pattern3 BindingId Wiring (next) -- ⏳ Task 80-C: Pattern4 BindingId Wiring -- ⏳ Task 80-D: E2E Tests +- ✅ Task 80-B: Pattern3 BindingId Wiring (dev-only) +- ✅ Task 80-C: Pattern4 BindingId Wiring (dev-only) +- ✅ Task 80-D: E2E Tests (P3/P4, dev-only) --- @@ -57,7 +57,7 @@ tools/smokes/v2/run.sh --profile quick --filter "json_pp_vm" ## Decision: Defer Pattern2 E2E(DigitPos/Trim)until ExitLine contract is stabilized -Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の E2E は Phase 80-D に回し、 +Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の E2E は Phase 81+ に回し、 さらに “promoted carriers(DigitPos/Trim)を含む Pattern2 の ExitLine 接続” が安定してから固定する。 ## Task 80-0: Summary @@ -74,7 +74,7 @@ Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の **Classification**: - **Phase 80 blockers**: NONE - **Phase 80 out-of-scope**: - - Pattern2(DigitPos/Trim)promoted carriers の ExitLine 契約安定化(Phase 80-D と合わせて着手) + - Pattern2(DigitPos/Trim)promoted carriers の ExitLine 契約安定化(Phase 81+) - json_lint_vm smoke test failure (pre-existing Pattern2 verifier issue) **Decision**: ✅ **Proceed to Task 80-A** @@ -130,11 +130,11 @@ Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の **Key function**: `lower_pattern3_if_sum()` -**ConditionEnv creation**: Line ~195 (passed to `lower_if_sum_pattern()`) +**ConditionEnv creation**: `ConditionEnvBuilder` 生成直後(`lower_if_sum_pattern()` に渡す前) **BindingId registration points**: -1. **Loop var registration** (lines ~116-128, Pattern2 reference): +1. **Loop var registration**(dev-only): ```rust #[cfg(feature = "normalized_dev")] if let Some(loop_var_bid) = builder.binding_map.get(&loop_var_name).copied() { @@ -144,28 +144,25 @@ Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の } ``` -2. **Carrier BindingId registration** (via CarrierVar.binding_id): +2. **Condition bindings registration**(dev-only): ```rust #[cfg(feature = "normalized_dev")] - for carrier in &carrier_info.carriers { - if let Some(bid) = carrier.binding_id { - match carrier.role { - CarrierRole::ConditionOnly => { - cond_env.register_condition_binding(bid, carrier.join_id); - } - _ => { - cond_env.register_carrier_binding(bid, carrier.join_id)?; - } - } - eprintln!("[phase80/p3] Registered carrier '{}' BindingId({}) -> ValueId({})", - carrier.name, bid.0, carrier.join_id.0); + for binding in &inline_boundary.condition_bindings { + if let Some(bid) = builder.binding_map.get(&binding.name).copied() { + cond_env.register_condition_binding(bid, binding.join_value); + eprintln!( + "[phase80/p3] Registered condition binding '{}' BindingId({}) -> ValueId({})", + binding.name, bid.0, binding.join_value.0 + ); } } ``` -**Timing**: AFTER ValueId allocation, BEFORE condition lowering +**Timing**: BEFORE condition lowering -**Data source**: `CarrierVar.binding_id` (populated by CarrierBindingAssigner in Phase 78) +**Note (重要)**: +- Pattern3/4 は lowering の後段(ExitMeta / merge 側)で carrier join_id が確定するため、Phase 80 では **carriers の BindingId 登録はしない**。 +- ここでの目的は「条件 lowering(lookup_with_binding)」の経路を先に BindingId 化して、shadowing の破綻を防ぐこと。 --- @@ -175,35 +172,19 @@ Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の **Key function**: `cf_loop_pattern4_with_continue()` -**ConditionEnv creation**: Within `lower_loop_with_continue_minimal()` (lines ~341-350) +**ConditionEnv creation**: `lower_loop_with_continue_minimal()` 内 **BindingId registration points**: -1. **Loop var registration** (same pattern as P3): - ```rust - #[cfg(feature = "normalized_dev")] - if let Some(loop_var_bid) = builder.binding_map.get(&loop_var_name).copied() { - cond_env.register_loop_var_binding(loop_var_bid, loop_var_join_id); - eprintln!("[phase80/p4] Registered loop var '{}' BindingId({}) -> ValueId({})", - loop_var_name, loop_var_bid.0, loop_var_join_id.0); - } - ``` +1. **Caller side**(dev-only): `binding_map` を lowerer に渡す -2. **Carrier BindingId registration** (via CarrierVar.binding_id from Pattern4CarrierAnalyzer): - ```rust - #[cfg(feature = "normalized_dev")] - for carrier in &carrier_info.carriers { - if let Some(bid) = carrier.binding_id { - cond_env.register_carrier_binding(bid, carrier.join_id)?; - eprintln!("[phase80/p4] Registered carrier '{}' BindingId({}) -> ValueId({})", - carrier.name, bid.0, carrier.join_id.0); - } - } - ``` +2. **Lowerer side**(dev-only): join_id が確定したタイミングで + - loop var / condition bindings / carriers を BindingId 登録する + - ログは `[phase80/p4]` タグで可視化する **Special note**: Trim patterns (skip_whitespace) use promoted carriers, BindingId comes from `promoted_bindings` map via CarrierBindingAssigner -**Timing**: AFTER ValueId allocation, BEFORE continue condition lowering +**Timing**: ValueId allocation の直後(condition lowering の前) --- @@ -228,29 +209,19 @@ Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の ### Implementation Order 1. ✅ Task 80-A: Design doc (this section) -2. ⏳ Task 80-B: Pattern3 wiring - - Modify `pattern3_with_if_phi.rs` - - Add BindingId registration for loop var + carriers - - Add `[phase80/p3]` debug logs -3. ⏳ Task 80-C: Pattern4 wiring - - Modify `pattern4_with_continue.rs` - - Add BindingId registration for loop var + carriers - - Add `[phase80/p4]` debug logs -4. ⏳ Task 80-D: E2E tests - - Add 2 tests to `tests/normalized_joinir_min.rs` - - Verify BindingId hit, NO fallback - - 972/972 lib tests PASS (970 + 2 new) +2. ✅ Task 80-B: Pattern3 wiring(loop var + condition bindings) +3. ✅ Task 80-C: Pattern4 wiring(lowerer 側で登録) +4. ✅ Task 80-D: E2E tests(P3 1本 / P4 1本, `tests/normalized_joinir_min.rs`) --- ### Success Metrics -- [ ] P3 BindingId registration operational (debug logs show hits) -- [ ] P4 BindingId registration operational (debug logs show hits) -- [ ] Fallback detection working (tests can detect fallback) -- [ ] 972/972 lib tests PASS (970 existing + 2 new E2E) -- [ ] Smoke tests stable (no new failures) -- [ ] All code dev-only (`#[cfg(feature = "normalized_dev")]`) +- [x] P3: 条件 lowering が BindingId 経路で解決できる(E2Eテストで固定) +- [x] P4: 条件 lowering が BindingId 経路で解決できる(E2Eテストで固定) +- [x] Fallback 検知(`[binding_pilot/fallback]` をテストで検知できる) +- [x] `cargo test --release --lib` が PASS(production 影響なし) +- [x] 追加コードは dev-only(`normalized_dev`)に閉じている --- @@ -273,12 +244,12 @@ Phase 80 の主目的は Pattern3/4 の BindingId 配線なので、Pattern2 の ## Implementation Tasks (pending Task 80-0 completion) -1. Pattern3 (if-sum) BindingId 登録配線 -2. Pattern4 (continue) BindingId 登録配線 -3. E2E tests (P3 1本 / P4 1本) +1. Pattern3 (if-sum) BindingId 登録配線 ✅ +2. Pattern4 (continue) BindingId 登録配線 ✅ +3. E2E tests (P3 1本 / P4 1本) ✅ ## Success Metrics - P3/P4 代表ケースで lookup_with_binding() 経路がヒット(ログ or テスト) - Fallback 検知可能(既存 `[binding_pilot/fallback]` タグ活用) -- 970/970 lib tests PASS (+ new tests) +- `cargo test --release --lib` PASS(退行なし) diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs index 2cc3217e..d58e916e 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs @@ -119,7 +119,8 @@ impl MirBuilder { let loop_var_name = ctx.loop_var_name.clone(); let loop_var_id = ctx.loop_var_id; - let (cond_env, condition_bindings, _loop_var_join_id) = + #[allow(unused_mut)] + let (mut cond_env, condition_bindings, _loop_var_join_id) = ConditionEnvBuilder::build_for_break_condition_v2( condition, &loop_var_name,