feat(joinir): Phase 80-B/C/D - Pattern3/4 BindingId wiring + E2E tests (dev-only)

Task 80-B (P1): Pattern3 (if-sum) BindingId registration
- pattern3_with_if_phi.rs: Added BindingId→ValueId registration
- Loop var + condition bindings registration (lines 131-159)
- Debug logs: [phase80/p3] tags
- Follows Pattern2 template structure

Task 80-C (P2): Pattern4 (continue) BindingId registration
- pattern4_with_continue.rs: Pass binding_map to lowerer (lines 341-352)
- loop_with_continue_minimal.rs: Added BindingId→ValueId registration (lines 206-230)
- Loop var + condition bindings registration
- Debug logs: [phase80/p4] tags
- Follows Pattern2 template structure

Task 80-D (P3): E2E tests for BindingId lookup
- tests/normalized_joinir_min.rs: Added 2 new tests (lines 2182-2222)
- test_phase80_p3_bindingid_lookup_works(): Pattern3 verification
- test_phase80_p4_bindingid_lookup_works(): Pattern4 verification
- Manual fallback detection via NYASH_JOINIR_DEBUG=1

Task P4: Cleanup
- Fixed unused variable warnings (loop_var_join_id → _loop_var_join_id)
- Fixed unnecessary mut warning (cargo fix auto-applied)
- pattern2_with_break.rs: Clean up pre-existing unused warning

Result: BindingId operational across Pattern2/3/4
Tests: 970/970 PASS (baseline, E2E tests in normalized_dev feature)
Design: dev-only, dual-path maintained, zero production impact

Phase 74-80 complete: BindingId migration fully operational across all patterns

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-13 18:05:14 +09:00
parent 889492b617
commit 84129a7ed4
5 changed files with 98 additions and 192 deletions

View File

@ -104,7 +104,7 @@ fn prepare_pattern2_inputs(
// Value space + condition env
let mut join_value_space = JoinValueSpace::new();
let (mut env, mut condition_bindings, loop_var_join_id) =
let (mut env, mut condition_bindings, _loop_var_join_id) =
ConditionEnvBuilder::build_for_break_condition_v2(
condition,
&loop_var_name,
@ -116,13 +116,13 @@ fn prepare_pattern2_inputs(
// Phase 79-2: Register loop variable BindingId (dev-only)
#[cfg(feature = "normalized_dev")]
if let Some(loop_var_bid) = builder.binding_map.get(&loop_var_name).copied() {
env.register_loop_var_binding(loop_var_bid, loop_var_join_id);
env.register_loop_var_binding(loop_var_bid, _loop_var_join_id);
log_pattern2(
verbose,
"phase79",
format!(
"Registered loop var BindingId: '{}' BindingId({}) → ValueId({})",
loop_var_name, loop_var_bid.0, loop_var_join_id.0
loop_var_name, loop_var_bid.0, _loop_var_join_id.0
),
);
}

View File

@ -128,6 +128,36 @@ impl MirBuilder {
&mut join_value_space,
)?;
// Phase 80-B (P1): Register BindingIds for condition variables (dev-only)
#[cfg(feature = "normalized_dev")]
{
// Register loop variable BindingId
if let Some(bid) = self.binding_map.get(&loop_var_name) {
cond_env.register_loop_var_binding(*bid, _loop_var_join_id);
if debug {
eprintln!(
"[phase80/p3] Registered loop var '{}' BindingId({}) -> ValueId({})",
loop_var_name, bid.0, _loop_var_join_id.0
);
}
}
// Register condition binding BindingIds
// These are variables from the condition expression (e.g., "len" in "i < len")
// May include ConditionOnly carriers if they appear in the condition
for binding in &condition_bindings {
if let Some(bid) = self.binding_map.get(&binding.name) {
cond_env.register_condition_binding(*bid, binding.join_value);
if debug {
eprintln!(
"[phase80/p3] Registered condition binding '{}' BindingId({}) -> ValueId({})",
binding.name, bid.0, binding.join_value.0
);
}
}
}
}
trace::trace().debug(
"pattern3/if-sum",
&format!("ConditionEnv bindings = {}", condition_bindings.len()),

View File

@ -338,6 +338,9 @@ fn lower_pattern4_joinir(
let mut join_value_space = JoinValueSpace::new();
#[cfg(feature = "normalized_dev")]
let binding_map_clone = builder.binding_map.clone();
let (join_module, exit_meta) = match lower_loop_with_continue_minimal(
prepared.loop_scope.clone(),
condition,
@ -345,6 +348,8 @@ fn lower_pattern4_joinir(
&prepared.carrier_info,
&prepared.carrier_updates,
&mut join_value_space,
#[cfg(feature = "normalized_dev")]
Some(&binding_map_clone),
) {
Ok(result) => result,
Err(e) => {

View File

@ -126,6 +126,7 @@ pub(crate) fn lower_loop_with_continue_minimal(
carrier_info: &CarrierInfo,
carrier_updates: &BTreeMap<String, UpdateExpr>, // Phase 222.5-D: HashMap → BTreeMap for determinism
join_value_space: &mut JoinValueSpace,
#[cfg(feature = "normalized_dev")] binding_map: Option<&std::collections::BTreeMap<String, crate::mir::BindingId>>,
) -> Result<(JoinModule, ExitMeta), String> {
// Phase 170-D-impl-3: Validate that loop condition only uses supported variable scopes
// LoopConditionScopeBox checks that loop conditions don't reference loop-body-local variables
@ -195,9 +196,37 @@ pub(crate) fn lower_loop_with_continue_minimal(
// Extract and add condition-only variables (Param region)
let condition_var_names = extract_condition_variables(condition, &[loop_var_name.clone()]);
let mut condition_var_join_ids = std::collections::BTreeMap::new();
for var_name in &condition_var_names {
let join_id = join_value_space.alloc_param();
env.insert(var_name.clone(), join_id);
condition_var_join_ids.insert(var_name.clone(), join_id);
}
// Phase 80-C (P2): Register BindingIds for condition variables (dev-only)
#[cfg(feature = "normalized_dev")]
if let Some(binding_map) = binding_map {
// Register loop variable BindingId
if let Some(bid) = binding_map.get(&loop_var_name) {
env.register_loop_var_binding(*bid, i_param);
#[cfg(debug_assertions)]
eprintln!(
"[phase80/p4] Registered loop var '{}' BindingId({}) -> ValueId({})",
loop_var_name, bid.0, i_param.0
);
}
// Register condition binding BindingIds
for (var_name, join_id) in &condition_var_join_ids {
if let Some(bid) = binding_map.get(var_name) {
env.register_condition_binding(*bid, *join_id);
#[cfg(debug_assertions)]
eprintln!(
"[phase80/p4] Registered condition binding '{}' BindingId({}) -> ValueId({})",
var_name, bid.0, join_id.0
);
}
}
}
// Phase 202-C: Create allocator closure AFTER all direct allocations