refactor(mir): Remove VariableContext legacy fields (Phase 2-6/7)

完全移行→削除の安全順序(Option C)に従い、VariableContext の
deprecated フィールドと sync helpers を完全削除。

## Changes
- Migrated all 66+ access sites to variable_ctx.variable_map
- Removed 1 deprecated field (variable_map) from MirBuilder
- Removed 2 sync helpers (sync_variable_ctx_to_legacy, sync_legacy_to_variable_ctx)
- Fixed BoxCompilationContext.variable_map references (kept as-is, different scope)
- Fixed ExitBindingBuilder.variable_map references (kept as-is, local field)
- Updated observer.rs to use variable_map() accessor method

## JoinIR Integration Verified
- CarrierInfo::from_variable_map() works correctly
- ExitLine contract maintained (Phase 132-135)
- NYASH_TRACE_VARMAP debug support preserved
- Pattern 1-5 lowering all functional

## Tests
- cargo test --release --lib: 1033 passed, 0 failed
- phase135_trim_mir_verify.sh: PASS (MIR SSA/ValueId OK)
- cargo build --release: SUCCESS
- Deprecation warnings: reduced (86 remaining, from other contexts)

## Statistics
- 27 files changed
- 146 insertions(+), 174 deletions(-)
- Net: -28 lines

Phase 2 Progress: 6/7 contexts complete (86%)
-  MetadataContext
-  CoreContext
-  TypeContext
-  ScopeContext
-  BindingContext
-  VariableContext (this commit)
-  CompilationContext (Phase 2-7 next)

🤖 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-16 03:48:44 +09:00
parent 44b20bfe28
commit 9170f0a85d
27 changed files with 146 additions and 174 deletions

View File

@ -127,13 +127,6 @@ pub struct MirBuilder {
/// Direct field access for backward compatibility (migration in progress).
pub(super) comp_ctx: compilation_context::CompilationContext,
/// [DEPRECATED] Variable name to ValueId mapping (for SSA conversion)
/// Phase 136 Step 5/7: Moved to variable_ctx.variable_map (backward compat wrapper)
/// 注意: compilation_contextがSomeの場合は使用されません
/// Phase 25.1: HashMap → BTreeMapPHI生成の決定性確保
#[deprecated(note = "Use variable_ctx.variable_map instead")]
pub(super) variable_map: BTreeMap<String, ValueId>,
/// Pending phi functions to be inserted
#[allow(dead_code)]
pub(super) pending_phis: Vec<(BasicBlockId, ValueId, String)>,
@ -300,7 +293,6 @@ impl MirBuilder {
variable_ctx: variable_context::VariableContext::new(), // Phase 136 Step 5/7: Variable context
metadata_ctx: metadata_context::MetadataContext::new(), // Phase 136 Step 6/7: Metadata context
comp_ctx, // Phase 136 Step 7/7: Compilation context
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保 (backward compat)
pending_phis: Vec::new(),
user_defined_boxes: HashSet::new(),
weak_fields_by_box: HashMap::new(),
@ -342,18 +334,7 @@ impl MirBuilder {
}
// Phase 2-5: BindingContext sync helpers removed - binding_ctx is now SSOT
/// Phase 136 Step 5/7: Sync variable_ctx changes back to legacy field (backward compatibility)
#[allow(deprecated)]
fn sync_variable_ctx_to_legacy(&mut self) {
self.variable_map = self.variable_ctx.variable_map.clone();
}
/// Phase 136 Step 5/7: Sync legacy field changes to variable_ctx (backward compatibility)
#[allow(deprecated)]
fn sync_legacy_to_variable_ctx(&mut self) {
self.variable_ctx.variable_map = self.variable_map.clone();
}
// Phase 2-6: VariableContext sync helpers removed - variable_ctx is now SSOT
/// Push/pop helpers for If merge context (best-effort; optional usage)
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
@ -616,7 +597,7 @@ impl MirBuilder {
));
}
if let Some(&value_id) = self.variable_map.get(&name) {
if let Some(&value_id) = self.variable_ctx.variable_map.get(&name) {
Ok(value_id)
} else {
Err(self.undefined_variable_message(&name))
@ -681,7 +662,7 @@ impl MirBuilder {
// Result: VM would try to read undefined ValueIds (e.g., ValueId(270) at bb303).
if !var_name.starts_with("__pin$") {
// In SSA form, each assignment creates a new value
self.variable_map.insert(var_name.clone(), value_id);
self.variable_ctx.variable_map.insert(var_name.clone(), value_id);
}
Ok(value_id)
@ -808,7 +789,7 @@ impl MirBuilder {
}) = callee
{
let names: Vec<String> = self
.variable_map
.variable_ctx.variable_map
.iter()
.filter(|(_, &vid)| vid == *r)
.map(|(k, _)| k.clone())
@ -1148,13 +1129,11 @@ mod binding_id_tests {
use super::*;
#[test]
#[allow(deprecated)]
fn test_binding_map_initialization() {
let builder = MirBuilder::new();
assert_eq!(builder.core_ctx.next_binding_id, 0);
// Phase 136 Step 4/7: Check both binding_ctx (SSOT) and legacy field
// Phase 2-6: binding_ctx is now SSOT (legacy field removed)
assert!(builder.binding_ctx.is_empty());
assert!(builder.binding_map.is_empty());
}
#[test]
@ -1171,7 +1150,6 @@ mod binding_id_tests {
}
#[test]
#[allow(deprecated)]
fn test_shadowing_binding_restore() {
let mut builder = MirBuilder::new();
@ -1184,11 +1162,9 @@ mod binding_id_tests {
builder
.declare_local_in_current_scope("x", outer_vid)
.unwrap();
// Phase 136 Step 4/7: Check binding_ctx (SSOT)
// Phase 2-6: Check binding_ctx (SSOT)
let outer_bid = builder.binding_ctx.lookup("x").unwrap();
assert_eq!(outer_bid.raw(), 0);
// Also verify legacy field is synced
assert_eq!(*builder.binding_map.get("x").unwrap(), outer_bid);
// Enter inner scope and shadow x
builder.push_lexical_scope();
@ -1197,20 +1173,16 @@ mod binding_id_tests {
builder
.declare_local_in_current_scope("x", inner_vid)
.unwrap();
// Phase 136 Step 4/7: Check binding_ctx (SSOT)
// Phase 2-6: Check binding_ctx (SSOT)
let inner_bid = builder.binding_ctx.lookup("x").unwrap();
assert_eq!(inner_bid.raw(), 1);
// Also verify legacy field is synced
assert_eq!(*builder.binding_map.get("x").unwrap(), inner_bid);
// Exit inner scope - should restore outer binding
builder.pop_lexical_scope();
// Phase 136 Step 4/7: Check binding_ctx (SSOT)
// Phase 2-6: Check binding_ctx (SSOT)
let restored_bid = builder.binding_ctx.lookup("x").unwrap();
assert_eq!(restored_bid, outer_bid);
assert_eq!(restored_bid.raw(), 0);
// Also verify legacy field is synced
assert_eq!(*builder.binding_map.get("x").unwrap(), restored_bid);
// Cleanup
builder.pop_lexical_scope();

View File

@ -421,7 +421,7 @@ impl MirBuilder {
method: &str,
arguments: &[ASTNode],
) -> Result<Option<ValueId>, String> {
let is_local_var = self.variable_map.contains_key(obj_name);
let is_local_var = self.variable_ctx.variable_map.contains_key(obj_name);
// Debug trace
if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") {
@ -434,7 +434,7 @@ impl MirBuilder {
eprintln!("[DEBUG] variable_map contains '{}' - treating as local variable, will use method call", obj_name);
eprintln!(
"[DEBUG] variable_map keys: {:?}",
self.variable_map.keys().collect::<Vec<_>>()
self.variable_ctx.variable_map.keys().collect::<Vec<_>>()
);
} else {
eprintln!("[DEBUG] '{}' not in variable_map - treating as static box, will use global call", obj_name);
@ -570,7 +570,7 @@ impl MirBuilder {
if let Some(origin) = self.type_ctx.value_origin_newbox.get(&object_value) {
eprintln!("[DEBUG/param-recv] origin: {}", origin);
}
if let Some(&mapped_id) = self.variable_map.get(name) {
if let Some(&mapped_id) = self.variable_ctx.variable_map.get(name) {
eprintln!(
"[DEBUG/param-recv] variable_map['{}'] = ValueId({})",
name, mapped_id.0

View File

@ -37,7 +37,7 @@ impl MirBuilder {
// BoxCompilationContext vs saved_var_map モード判定
let context_active = self.compilation_context.is_some();
let saved_var_map = if !context_active {
Some(std::mem::take(&mut self.variable_map))
Some(std::mem::take(&mut self.variable_ctx.variable_map))
} else {
None
};
@ -47,7 +47,7 @@ impl MirBuilder {
// BoxCompilationContext mode: clear()で完全独立化
if context_active {
self.variable_map.clear();
self.variable_ctx.variable_map.clear();
self.type_ctx.value_origin_newbox.clear();
// value_types も static box 単位で独立させる。
// これにより、前の static box で使用された ValueId に紐づく型情報が
@ -139,7 +139,7 @@ impl MirBuilder {
f.params.push(new_pid);
new_pid
};
self.variable_map.insert(p.clone(), pid);
self.variable_ctx.variable_map.insert(p.clone(), pid);
// Phase 136 Step 3/7: Insert into scope_ctx (SSOT)
self.scope_ctx.function_param_names.insert(p.clone());
@ -237,13 +237,13 @@ impl MirBuilder {
// モード別にcontext復元
if ctx.context_active {
// BoxCompilationContext mode: clear のみ(次回も完全独立)
self.variable_map.clear();
self.variable_ctx.variable_map.clear();
self.type_ctx.value_origin_newbox.clear();
// static box ごとに型情報も独立させる(前 box の型メタデータを引きずらない)
self.type_ctx.value_types.clear();
} else if let Some(saved) = ctx.saved_var_map {
// Legacy mode: Main.main 側の variable_map を元に戻す
self.variable_map = saved;
self.variable_ctx.variable_map = saved;
}
// Static box context復元
@ -307,7 +307,7 @@ impl MirBuilder {
// me
let me_id = f.params[0];
self.variable_map.insert("me".to_string(), me_id);
self.variable_ctx.variable_map.insert("me".to_string(), me_id);
self.type_ctx.value_origin_newbox.insert(me_id, box_name.to_string());
slot_regs.push(("me".to_string(), None));
@ -316,13 +316,13 @@ impl MirBuilder {
let param_idx = idx + 1;
if param_idx < f.params.len() {
let pid = f.params[param_idx];
self.variable_map.insert(p.clone(), pid);
self.variable_ctx.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
} else {
// 念のため足りない場合は新規に確保(互換用)
let pid = f.next_value_id();
f.params.push(pid);
self.variable_map.insert(p.clone(), pid);
self.variable_ctx.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
}
}
@ -402,7 +402,7 @@ impl MirBuilder {
// Step 1: Context準備instance methodでは不要だがAPI統一のため
let mut ctx = LoweringContext {
context_active: false,
saved_var_map: Some(std::mem::take(&mut self.variable_map)),
saved_var_map: Some(std::mem::take(&mut self.variable_ctx.variable_map)),
saved_static_ctx: None,
saved_function: None,
saved_block: None,
@ -473,7 +473,7 @@ impl MirBuilder {
self.scope_ctx.current_function = ctx.saved_function;
self.current_block = ctx.saved_block;
if let Some(saved) = ctx.saved_var_map {
self.variable_map = saved;
self.variable_ctx.variable_map = saved;
}
self.current_slot_registry = ctx.saved_slot_registry;

View File

@ -39,7 +39,7 @@ impl MirBuilder {
super::method_resolution::resolve_call_target(
name,
&self.current_static_box,
&self.variable_map,
&self.variable_ctx.variable_map,
)
}
}

View File

@ -25,6 +25,6 @@ impl MirBuilder {
/// Enable with NYASH_TRACE_VARMAP=1
#[allow(dead_code)]
pub(in crate::mir::builder) fn trace_varmap(&self, context: &str) {
super::joinir::trace::trace().varmap(context, &self.variable_map);
super::joinir::trace::trace().varmap(context, &self.variable_ctx.variable_map);
}
}

View File

@ -3,7 +3,7 @@
//! Modularizes the exit_bindings collection logic from Pattern lowerers
//! into a focused, testable Box.
//!
//! **Responsibility**: Construct exit_bindings from ExitMeta + variable_map lookup
//! **Responsibility**: Construct exit_bindings from ExitMeta + variable_ctx.variable_map lookup
use crate::mir::builder::MirBuilder;
use crate::mir::join_ir::lowering::carrier_info::ExitMeta;
@ -16,10 +16,10 @@ use crate::mir::ValueId; // Phase 228-8: For ConditionOnly placeholder
///
/// ## Pure Function Philosophy
/// ExitMetaCollector::collect() is a **pure function**:
/// - Input: builder (read-only for variable_map lookup)
/// - Input: builder (read-only for variable_ctx.variable_map lookup)
/// - Input: exit_meta (data structure)
/// - Output: Vec<LoopExitBinding> (new data)
/// - No side effects (except reading builder.variable_map)
/// - No side effects (except reading builder.variable_ctx.variable_map)
///
/// ## Why Pure Functions?
/// - Easy to test (no mocks needed)
@ -40,7 +40,7 @@ use crate::mir::ValueId; // Phase 228-8: For ConditionOnly placeholder
///
/// **Input**:
/// - ExitMeta with exit_values (carrier_name → join_exit_value mappings)
/// - MirBuilder with variable_map for host ValueId lookup
/// - MirBuilder with variable_ctx.variable_map for host ValueId lookup
///
/// **Effect**:
/// - Creates LoopExitBinding vector (pure function, no side effects)
@ -50,25 +50,25 @@ use crate::mir::ValueId; // Phase 228-8: For ConditionOnly placeholder
pub struct ExitMetaCollector;
impl ExitMetaCollector {
/// Build exit_bindings from ExitMeta and variable_map
/// Build exit_bindings from ExitMeta and variable_ctx.variable_map
///
/// # Algorithm
///
/// For each entry in exit_meta.exit_values:
/// 1. Look up the carrier's host ValueId from builder.variable_map
/// 1. Look up the carrier's host ValueId from builder.variable_ctx.variable_map
/// 2. Create LoopExitBinding with carrier_name, join_exit_value, host_slot
/// 3. Collect into Vec<LoopExitBinding>
///
/// # Phase 228-8: ConditionOnly carrier handling
///
/// ConditionOnly carriers are included in exit_bindings even if they're not
/// in variable_map, because they need latch incoming values for header PHI.
/// in variable_ctx.variable_map, because they need latch incoming values for header PHI.
/// The host_slot is set to ValueId(0) as a placeholder since ConditionOnly
/// carriers don't participate in exit PHI.
///
/// # Skipped carriers
///
/// Carriers not found in variable_map AND not in carrier_info are silently skipped.
/// Carriers not found in variable_ctx.variable_map AND not in carrier_info are silently skipped.
/// This is intentional: some carriers may not be relevant to the current pattern.
///
/// # Logging
@ -96,13 +96,13 @@ impl ExitMetaCollector {
for (carrier_name, join_exit_value) in &exit_meta.exit_values {
if verbose {
eprintln!(
"[joinir/exit-line] checking carrier '{}' in variable_map",
"[joinir/exit-line] checking carrier '{}' in variable_ctx.variable_map",
carrier_name
);
}
// Look up host slot from variable_map
if let Some(&host_slot) = builder.variable_map.get(carrier_name) {
// Look up host slot from variable_ctx.variable_map
if let Some(&host_slot) = builder.variable_ctx.variable_map.get(carrier_name) {
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
// Phase 228-8: Look up role from carrier_info if available
@ -157,7 +157,7 @@ impl ExitMetaCollector {
if verbose {
eprintln!(
"[joinir/exit-line] collected ConditionOnly carrier '{}' JoinIR {:?} (not in variable_map)",
"[joinir/exit-line] collected ConditionOnly carrier '{}' JoinIR {:?} (not in variable_ctx.variable_map)",
carrier_name, join_exit_value
);
}
@ -166,7 +166,7 @@ impl ExitMetaCollector {
}
Some((CarrierRole::LoopState, CarrierInit::FromHost)) => {
// Phase 247-EX: Include FromHost carrier in exit_bindings
// (needed for latch incoming, not for exit PHI or variable_map)
// (needed for latch incoming, not for exit PHI or variable_ctx.variable_map)
let binding = LoopExitBinding {
carrier_name: carrier_name.clone(),
join_exit_value: *join_exit_value,
@ -176,7 +176,7 @@ impl ExitMetaCollector {
if verbose {
eprintln!(
"[joinir/exit-line] collected FromHost carrier '{}' JoinIR {:?} (not in variable_map)",
"[joinir/exit-line] collected FromHost carrier '{}' JoinIR {:?} (not in variable_ctx.variable_map)",
carrier_name, join_exit_value
);
}
@ -203,7 +203,7 @@ impl ExitMetaCollector {
}
_ => {
let msg = format!(
"[joinir/exit-line] carrier '{}' not in variable_map and not ConditionOnly/FromHost (skip)",
"[joinir/exit-line] carrier '{}' not in variable_ctx.variable_map and not ConditionOnly/FromHost (skip)",
carrier_name
);
if strict {
@ -243,7 +243,7 @@ mod tests {
fn test_missing_carrier_in_variable_map() {
// This test would require full MirBuilder setup
// Placeholder for future detailed testing
// When carrier not in variable_map, should be silently skipped
// When carrier not in variable_ctx.variable_map, should be silently skipped
assert!(true);
}
}

View File

@ -3,7 +3,7 @@
//! Modularizes the exit line reconnection logic (Phase 6 from merge/mod.rs)
//! into a focused, testable Box.
//!
//! **Responsibility**: Update host variable_map with PHI dst values from exit block
//! **Responsibility**: Update host variable_ctx.variable_map with PHI dst values from exit block
//!
//! # Phase 33-13 Architecture Change
//!
@ -23,15 +23,15 @@ use std::collections::BTreeMap;
/// # Design Notes
///
/// ## Why Separate Box?
/// - Responsibility: Update host variable_map with PHI dst values
/// - Responsibility: Update host variable_ctx.variable_map with PHI dst values
/// - Input: JoinInlineBoundary.exit_bindings + carrier_phis map
/// - Output: Updated MirBuilder.variable_map
/// - No side effects beyond variable_map updates
/// - Output: Updated MirBuilder.variable_ctx.variable_map
/// - No side effects beyond variable_ctx.variable_map updates
///
/// ## Phase 33-13 Carrier PHI Integration
/// This Box now uses carrier_phis from exit_phi_builder:
/// - Before: `variable_map[carrier] = remapper.get(join_exit)` (SSA-incorrect!)
/// - After: `variable_map[carrier] = carrier_phis[carrier]` (SSA-correct!)
/// - Before: `variable_ctx.variable_map[carrier] = remapper.get(join_exit)` (SSA-incorrect!)
/// - After: `variable_ctx.variable_map[carrier] = carrier_phis[carrier]` (SSA-correct!)
///
/// The key insight is that remapped exit values are PHI INPUTS, not OUTPUTS.
/// Only the PHI dst ValueId is defined in the exit block.
@ -40,7 +40,7 @@ use std::collections::BTreeMap;
/// Can be tested independently:
/// 1. Create mock boundary with exit_bindings
/// 2. Create mock carrier_phis map
/// 3. Call reconnect() and verify variable_map updates
/// 3. Call reconnect() and verify variable_ctx.variable_map updates
/// 4. No need to construct full merge/mod.rs machinery
///
/// # Box Contract
@ -50,14 +50,14 @@ use std::collections::BTreeMap;
/// - carrier_phis: Map from carrier name to PHI dst ValueId
///
/// **Effect**:
/// - Updates builder.variable_map entries for each carrier with PHI dst values
/// - Updates builder.variable_ctx.variable_map entries for each carrier with PHI dst values
///
/// **Output**:
/// - Result<(), String> (side effect on builder)
pub struct ExitLineReconnector;
impl ExitLineReconnector {
/// Reconnect exit values to host variable_map using carrier PHI dst values
/// Reconnect exit values to host variable_ctx.variable_map using carrier PHI dst values
///
/// # Phase 33-13: Carrier PHI Integration
///
@ -71,7 +71,7 @@ impl ExitLineReconnector {
///
/// For each exit_binding:
/// 1. Look up the PHI dst for this carrier in carrier_phis
/// 2. Update variable_map[binding.carrier_name] with PHI dst
/// 2. Update variable_ctx.variable_map[binding.carrier_name] with PHI dst
/// 3. Log each update (if debug enabled)
pub fn reconnect(
builder: &mut MirBuilder,
@ -119,12 +119,12 @@ impl ExitLineReconnector {
// Process each exit binding
for binding in &boundary.exit_bindings {
// Phase 228-8: Skip ConditionOnly carriers (no variable_map update needed)
// Phase 228-8: Skip ConditionOnly carriers (no variable_ctx.variable_map update needed)
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
if binding.role == CarrierRole::ConditionOnly {
if verbose {
eprintln!(
"[joinir/exit-line] skip ConditionOnly carrier '{}' (no variable_map update)",
"[joinir/exit-line] skip ConditionOnly carrier '{}' (no variable_ctx.variable_map update)",
binding.carrier_name
);
}
@ -141,25 +141,25 @@ impl ExitLineReconnector {
);
}
// Update variable_map with PHI dst
// Update variable_ctx.variable_map with PHI dst
if let Some(&phi_value) = phi_dst {
if let Some(var_vid) = builder.variable_map.get_mut(&binding.carrier_name) {
if let Some(var_vid) = builder.variable_ctx.variable_map.get_mut(&binding.carrier_name) {
// Phase 177-STRUCT: Always log for debugging
if verbose {
eprintln!(
"[joinir/exit-line] variable_map['{}'] {:?}{:?}",
"[joinir/exit-line] variable_ctx.variable_map['{}'] {:?}{:?}",
binding.carrier_name, *var_vid, phi_value
);
}
*var_vid = phi_value;
} else if verbose {
eprintln!(
"[joinir/exit-line] warning: carrier '{}' not found in variable_map",
"[joinir/exit-line] warning: carrier '{}' not found in variable_ctx.variable_map",
binding.carrier_name
);
} else if strict {
return Err(format!(
"[joinir/exit-line] missing variable_map entry for carrier '{}' (exit reconnection)",
"[joinir/exit-line] missing variable_ctx.variable_map entry for carrier '{}' (exit reconnection)",
binding.carrier_name
));
}
@ -188,9 +188,9 @@ impl ExitLineReconnector {
}
// Phase 190-impl-D-3: Contract verification (debug build only)
// Ensures all exit_bindings have corresponding entries in carrier_phis and variable_map
// Ensures all exit_bindings have corresponding entries in carrier_phis and variable_ctx.variable_map
#[cfg(debug_assertions)]
Self::verify_exit_line_contract(boundary, carrier_phis, &builder.variable_map);
Self::verify_exit_line_contract(boundary, carrier_phis, &builder.variable_ctx.variable_map);
Ok(())
}
@ -200,14 +200,14 @@ impl ExitLineReconnector {
/// # Contract Requirements
///
/// 1. Every exit_binding must have a corresponding entry in carrier_phis
/// 2. Every exit_binding's carrier must exist in variable_map after reconnect
/// 3. The variable_map entry must point to the PHI dst (not the original host value)
/// 2. Every exit_binding's carrier must exist in variable_ctx.variable_map after reconnect
/// 3. The variable_ctx.variable_map entry must point to the PHI dst (not the original host value)
///
/// # Panics
///
/// Panics if any contract violation is detected. This helps catch bugs where:
/// - PHI is missing for a carrier (Phase 190-impl-D root cause)
/// - variable_map update was skipped
/// - variable_ctx.variable_map update was skipped
/// - ValueId collision occurred
#[cfg(debug_assertions)]
fn verify_exit_line_contract(
@ -218,10 +218,10 @@ impl ExitLineReconnector {
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
for binding in &boundary.exit_bindings {
// Phase 228-8: Skip ConditionOnly carriers (not in variable_map by design)
// Phase 228-8: Skip ConditionOnly carriers (not in variable_ctx.variable_map by design)
if binding.role == CarrierRole::ConditionOnly {
eprintln!(
"[JoinIR/ExitLine/Contract] Phase 228-8: Skipping ConditionOnly carrier '{}' (not in variable_map)",
"[JoinIR/ExitLine/Contract] Phase 228-8: Skipping ConditionOnly carrier '{}' (not in variable_ctx.variable_map)",
binding.carrier_name
);
continue;
@ -240,20 +240,20 @@ impl ExitLineReconnector {
// Future: Distinguish loop_var from carriers in exit_bindings
}
// Contract 2: variable_map must contain this carrier after reconnect
// Contract 2: variable_ctx.variable_map must contain this carrier after reconnect
let var_value = variable_map.get(&binding.carrier_name);
if var_value.is_none() {
panic!(
"[JoinIR/ExitLine/Contract] VIOLATION: Carrier '{}' missing from variable_map after reconnect",
"[JoinIR/ExitLine/Contract] VIOLATION: Carrier '{}' missing from variable_ctx.variable_map after reconnect",
binding.carrier_name
);
}
// Contract 3: variable_map entry should point to PHI dst (if PHI exists)
// Contract 3: variable_ctx.variable_map entry should point to PHI dst (if PHI exists)
if let (Some(&phi), Some(&var)) = (phi_dst, var_value) {
if phi != var {
panic!(
"[JoinIR/ExitLine/Contract] VIOLATION: Carrier '{}' variable_map={:?} but PHI dst={:?} (mismatch!)",
"[JoinIR/ExitLine/Contract] VIOLATION: Carrier '{}' variable_ctx.variable_map={:?} but PHI dst={:?} (mismatch!)",
binding.carrier_name, var, phi
);
}

View File

@ -54,7 +54,7 @@ impl MirBuilder {
let ctx = build_pattern_context(self, condition, body, PatternVariant::Pattern1)?;
// Phase 195: Use unified trace
trace::trace().varmap("pattern1_start", &self.variable_map);
trace::trace().varmap("pattern1_start", &self.variable_ctx.variable_map);
// Phase 202-A: Create JoinValueSpace for unified ValueId allocation
// Pattern 1 uses Param region for boundary input slots (loop var) and Local region for temps.

View File

@ -108,7 +108,7 @@ fn prepare_pattern2_inputs(
ConditionEnvBuilder::build_for_break_condition_v2(
condition,
&loop_var_name,
&builder.variable_map,
&builder.variable_ctx.variable_map,
loop_var_id,
&mut join_value_space,
)?;
@ -140,7 +140,7 @@ fn prepare_pattern2_inputs(
// Add captured vars
for var in &captured_env.vars {
if let Some(&host_id) = builder.variable_map.get(&var.name) {
if let Some(&host_id) = builder.variable_ctx.variable_map.get(&var.name) {
let join_id = join_value_space.alloc_param();
env.insert(var.name.clone(), join_id);
condition_bindings.push(ConditionBinding {
@ -676,7 +676,7 @@ pub(crate) fn can_lower(builder: &MirBuilder, ctx: &super::router::LoopPatternCo
CommonPatternInitializer::check_carrier_updates_allowed(
ctx.body,
&loop_var_name,
&builder.variable_map,
&builder.variable_ctx.variable_map,
)
}
@ -745,7 +745,7 @@ impl MirBuilder {
use super::pattern_pipeline::{build_pattern_context, PatternVariant};
let ctx = build_pattern_context(self, condition, _body, PatternVariant::Pattern2)?;
trace::trace().varmap("pattern2_start", &self.variable_map);
trace::trace().varmap("pattern2_start", &self.variable_ctx.variable_map);
let mut inputs =
prepare_pattern2_inputs(self, condition, _body, fn_body, &ctx, verbose)?;
@ -977,11 +977,11 @@ mod tests {
use crate::mir::ValueId;
let mut builder = MirBuilder::new();
builder.variable_map.insert("i".to_string(), ValueId(1));
builder.variable_map.insert("len".to_string(), ValueId(2));
builder.variable_map.insert("s".to_string(), ValueId(3));
builder.variable_map.insert("digits".to_string(), ValueId(4));
builder.variable_map.insert("result".to_string(), ValueId(5));
builder.variable_ctx.variable_map.insert("i".to_string(), ValueId(1));
builder.variable_ctx.variable_map.insert("len".to_string(), ValueId(2));
builder.variable_ctx.variable_map.insert("s".to_string(), ValueId(3));
builder.variable_ctx.variable_map.insert("digits".to_string(), ValueId(4));
builder.variable_ctx.variable_map.insert("result".to_string(), ValueId(5));
let condition = bin(BinaryOperator::Less, var("i"), var("len"));

View File

@ -124,7 +124,7 @@ impl MirBuilder {
ConditionEnvBuilder::build_for_break_condition_v2(
condition,
&loop_var_name,
&self.variable_map,
&self.variable_ctx.variable_map,
loop_var_id,
&mut join_value_space,
)?;
@ -183,7 +183,7 @@ impl MirBuilder {
// Collect parent-defined variables from function scope
// For now, use all variables in variable_map except loop_var
let parent_defined: Vec<String> = self
.variable_map
.variable_ctx.variable_map
.keys()
.filter(|name| *name != &loop_var_name)
.cloned()

View File

@ -81,7 +81,7 @@ pub(crate) fn can_lower(builder: &MirBuilder, ctx: &super::router::LoopPatternCo
CommonPatternInitializer::check_carrier_updates_allowed(
ctx.body,
&loop_var_name,
&builder.variable_map,
&builder.variable_ctx.variable_map,
)
}
@ -335,7 +335,7 @@ fn lower_pattern4_joinir(
use crate::mir::join_ir::lowering::loop_with_continue_minimal::lower_loop_with_continue_minimal;
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
trace::trace().varmap("pattern4_start", &builder.variable_map);
trace::trace().varmap("pattern4_start", &builder.variable_ctx.variable_map);
let mut join_value_space = JoinValueSpace::new();

View File

@ -316,9 +316,9 @@ pub(crate) fn lower(
);
}
// Step 2: Get counter ValueId from variable_map
let counter_id = builder.variable_map.get(&counter_name).copied().ok_or_else(|| {
format!("Counter variable '{}' not found in variable_map", counter_name)
// Step 2: Get counter ValueId from variable_ctx.variable_map
let counter_id = builder.variable_ctx.variable_map.get(&counter_name).copied().ok_or_else(|| {
format!("Counter variable '{}' not found in variable_ctx.variable_map", counter_name)
})?;
if debug {

View File

@ -263,7 +263,7 @@ pub(crate) fn build_pattern_context(
let (loop_var_name, loop_var_id, carrier_info) = CommonPatternInitializer::initialize_pattern(
builder,
condition,
&builder.variable_map,
&builder.variable_ctx.variable_map,
None, // No exclusions for now (Pattern 2/4 will filter carriers later)
)?;

View File

@ -280,7 +280,7 @@ impl TrimLoopLowerer {
Self::generate_carrier_initialization(builder, body, trim_helper)?;
eprintln!(
"[TrimLoopLowerer] Registered carrier '{}' in variable_map",
"[TrimLoopLowerer] Registered carrier '{}' in variable_ctx.variable_map",
trim_helper.carrier_name
);
@ -328,7 +328,7 @@ impl TrimLoopLowerer {
/// Generates:
/// 1. ch0 = s.substring(start, start+1)
/// 2. is_ch_match0 = (ch0 == " " || ch0 == "\t" || ...)
/// 3. Registers carrier in variable_map
/// 3. Registers carrier in variable_ctx.variable_map
fn generate_carrier_initialization(
builder: &mut MirBuilder,
body: &[ASTNode],
@ -353,7 +353,7 @@ impl TrimLoopLowerer {
// Get ValueIds for string and start
let s_id =
builder.variable_map.get(&s_name).copied().ok_or_else(|| {
builder.variable_ctx.variable_map.get(&s_name).copied().ok_or_else(|| {
format!("[TrimLoopLowerer] String variable '{}' not found", s_name)
})?;
@ -401,9 +401,9 @@ impl TrimLoopLowerer {
is_ch_match0
);
// Register carrier in variable_map
// Register carrier in variable_ctx.variable_map
builder
.variable_map
.variable_ctx.variable_map
.insert(trim_helper.carrier_name.clone(), is_ch_match0);
Ok(())
@ -438,7 +438,7 @@ impl TrimLoopLowerer {
let mut bindings = Vec::new();
// Add carrier to ConditionEnv
let get_value = |name: &str| builder.variable_map.get(name).copied();
let get_value = |name: &str| builder.variable_ctx.variable_map.get(name).copied();
let mut env_temp = std::collections::HashMap::new(); // Temporary env for closure
let binding = TrimPatternLowerer::add_to_condition_env(

View File

@ -47,7 +47,7 @@ impl super::MirBuilder {
);
eprintln!("[DEBUG] params.len() = {}", params.len());
eprintln!("[DEBUG] body.len() = {}", body.len());
eprintln!("[DEBUG] variable_map = {:?}", self.variable_map);
eprintln!("[DEBUG] variable_map = {:?}", self.variable_ctx.variable_map);
// Note: Metadata clearing is now handled by BoxCompilationContext (箱理論)
// See lifecycle.rs and builder_calls.rs for context swap implementation
let _ = self.lower_static_method_as_function(
@ -58,11 +58,11 @@ impl super::MirBuilder {
eprintln!(
"[DEBUG] build_static_main_box: After lower_static_method_as_function"
);
eprintln!("[DEBUG] variable_map = {:?}", self.variable_map);
eprintln!("[DEBUG] variable_map = {:?}", self.variable_ctx.variable_map);
}
// Initialize local variables for Main.main() parameters
// Note: These are local variables in the wrapper main() function, NOT parameters
let saved_var_map = std::mem::take(&mut self.variable_map);
let saved_var_map = std::mem::take(&mut self.variable_ctx.variable_map);
let script_args = collect_script_args_from_env();
for p in params.iter() {
// Allocate a value ID using the current function's value generator
@ -109,7 +109,7 @@ impl super::MirBuilder {
self.emit_instruction(MirInstruction::Copy { dst: pid, src: v })?;
crate::mir::builder::metadata::propagate::propagate(self, v, pid);
}
self.variable_map.insert(p.clone(), pid);
self.variable_ctx.variable_map.insert(p.clone(), pid);
// 関数スコープ SlotRegistry にも登録しておくよ(観測専用)
if let Some(reg) = self.current_slot_registry.as_mut() {
let ty = self.type_ctx.value_types.get(&pid).cloned();
@ -129,7 +129,7 @@ impl super::MirBuilder {
// Phase 200-C: Clear fn_body_ast after main() lowering
self.fn_body_ast = None;
self.variable_map = saved_var_map;
self.variable_ctx.variable_map = saved_var_map;
lowered
} else {
Err("main method in static box is not a FunctionDeclaration".to_string())

View File

@ -157,11 +157,11 @@ impl super::MirBuilder {
}
let mut captures: Vec<(String, ValueId)> = Vec::new();
for name in used.into_iter() {
if let Some(&vid) = self.variable_map.get(&name) {
if let Some(&vid) = self.variable_ctx.variable_map.get(&name) {
captures.push((name, vid));
}
}
let me = self.variable_map.get("me").copied();
let me = self.variable_ctx.variable_map.get("me").copied();
let dst = self.next_value_id();
self.emit_instruction(super::MirInstruction::NewClosure {
dst,

View File

@ -43,7 +43,7 @@ impl<'a> PhiBuilderOps for ToplevelOps<'a> {
}
fn update_var(&mut self, name: String, value: ValueId) {
self.0.variable_map.insert(name, value);
self.0.variable_ctx.variable_map.insert(name, value);
}
fn get_block_predecessors(&self, block: BasicBlockId) -> Vec<BasicBlockId> {
@ -113,7 +113,7 @@ impl MirBuilder {
)?;
// Snapshot variables before entering branches
let pre_if_var_map = self.variable_map.clone();
let pre_if_var_map = self.variable_ctx.variable_map.clone();
let trace_if = std::env::var("NYASH_IF_TRACE").ok().as_deref() == Some("1");
@ -124,11 +124,11 @@ impl MirBuilder {
// Scope enter for then-branch
self.hint_scope_enter(0);
let then_ast_for_analysis = then_branch.clone();
self.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map = pre_if_var_map.clone();
// Materialize all variables at block entry via single-pred Phi (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
self.variable_ctx.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] then-entry phi var={} pre={:?} -> dst={:?}",
@ -139,7 +139,7 @@ impl MirBuilder {
let then_value_raw = self.build_expression(then_branch)?;
let then_exit_block = self.current_block()?;
let then_reaches_merge = !self.is_current_block_terminated();
let then_var_map_end = self.variable_map.clone();
let then_var_map_end = self.variable_ctx.variable_map.clone();
if then_reaches_merge {
// Scope leave for then-branch
self.hint_scope_leave(0);
@ -157,11 +157,11 @@ impl MirBuilder {
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) =
if let Some(else_ast) = else_branch {
// Reset variable_map BEFORE materializing PHI nodes (same pattern as then-branch)
self.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map = pre_if_var_map.clone();
// Materialize all variables at block entry via single-pred Phi (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
self.variable_ctx.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
@ -170,13 +170,13 @@ impl MirBuilder {
}
}
let val = self.build_expression(else_ast.clone())?;
(val, Some(else_ast), Some(self.variable_map.clone()))
(val, Some(else_ast), Some(self.variable_ctx.variable_map.clone()))
} else {
// No else branch: materialize PHI nodes for the empty else block
self.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map = pre_if_var_map.clone();
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
self.variable_ctx.variable_map.insert(name.clone(), phi_val);
if trace_if {
eprintln!(
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
@ -187,7 +187,7 @@ impl MirBuilder {
let void_val = crate::mir::builder::emission::constant::emit_void(self);
// Phase 25.1c/k: Pass PHI-renamed variable_map for empty else branch
// This ensures merge_modified_vars uses correct ValueIds after PHI renaming
(void_val, None, Some(self.variable_map.clone()))
(void_val, None, Some(self.variable_ctx.variable_map.clone()))
};
let else_exit_block = self.current_block()?;
let else_reaches_merge = !self.is_current_block_terminated();

View File

@ -354,17 +354,17 @@ impl super::MirBuilder {
let pre_branch_bb = self.current_block()?;
// Snapshot variables before entering branches
let pre_if_var_map = self.variable_map.clone();
let pre_if_var_map = self.variable_ctx.variable_map.clone();
// ---- THEN branch ----
self.start_new_block(then_block)?;
self.hint_scope_enter(0);
// Reset scope to pre-if snapshot for clean deltas
self.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map = pre_if_var_map.clone();
// Materialize all variables at entry via single-pred PHI (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
self.variable_ctx.variable_map.insert(name.clone(), phi_val);
}
// AND: then → evaluate RHS and reduce to bool
@ -404,7 +404,7 @@ impl super::MirBuilder {
};
let then_exit_block = self.current_block()?;
let then_reaches_merge = !self.is_current_block_terminated();
let then_var_map_end = self.variable_map.clone();
let then_var_map_end = self.variable_ctx.variable_map.clone();
if then_reaches_merge {
self.hint_scope_leave(0);
crate::mir::builder::emission::branch::emit_jump(self, merge_block)?;
@ -413,11 +413,11 @@ impl super::MirBuilder {
// ---- ELSE branch ----
self.start_new_block(else_block)?;
self.hint_scope_enter(0);
self.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map = pre_if_var_map.clone();
// Materialize all variables at entry via single-pred PHI (correctness-first)
for (name, &pre_v) in pre_if_var_map.iter() {
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
self.variable_map.insert(name.clone(), phi_val);
self.variable_ctx.variable_map.insert(name.clone(), phi_val);
}
// AND: else → false
// OR: else → evaluate RHS and reduce to bool
@ -455,7 +455,7 @@ impl super::MirBuilder {
};
let else_exit_block = self.current_block()?;
let else_reaches_merge = !self.is_current_block_terminated();
let else_var_map_end = self.variable_map.clone();
let else_var_map_end = self.variable_ctx.variable_map.clone();
if else_reaches_merge {
self.hint_scope_leave(0);
crate::mir::builder::emission::branch::emit_jump(self, merge_block)?;

View File

@ -64,7 +64,7 @@ impl MirBuilder {
0 => {}
1 => {
let (_pred, v) = inputs[0];
self.variable_map.insert(pin_name.clone(), v);
self.variable_ctx.variable_map.insert(pin_name.clone(), v);
}
_ => {
if let Some(func) = self.scope_ctx.current_function.as_mut() {
@ -94,7 +94,7 @@ impl MirBuilder {
type_hint: None, // Phase 63-6: Legacy path, no type hint
})?;
}
self.variable_map.insert(pin_name.clone(), merged);
self.variable_ctx.variable_map.insert(pin_name.clone(), merged);
}
}
}
@ -164,8 +164,8 @@ impl MirBuilder {
0 => {}
1 => {
// Direct bind (no PHI needed)
self.variable_map = pre_if_var_map.clone();
self.variable_map.insert(var_name, inputs[0].1);
self.variable_ctx.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map.insert(var_name, inputs[0].1);
return Ok(inputs[0].1);
}
_ => {
@ -181,8 +181,8 @@ impl MirBuilder {
self.insert_phi_with_dst(result_val, inputs)?;
}
}
self.variable_map = pre_if_var_map.clone();
self.variable_map.insert(var_name, result_val);
self.variable_ctx.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map.insert(var_name, result_val);
} else {
// No variable assignment pattern detected just emit Phi for expression result
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
@ -215,7 +215,7 @@ impl MirBuilder {
}
}
// Merge variable map conservatively to pre-if snapshot (no new bindings)
self.variable_map = pre_if_var_map.clone();
self.variable_ctx.variable_map = pre_if_var_map.clone();
}
Ok(result_val)

View File

@ -81,7 +81,7 @@ impl<'a> PhiMergeHelper<'a> {
1 => {
// Single predecessor - direct insert (no PHI)
let (_pred, v) = inputs[0];
self.builder.variable_map.insert(name, v);
self.builder.variable_ctx.variable_map.insert(name, v);
Ok(())
}
_ => {
@ -95,7 +95,7 @@ impl<'a> PhiMergeHelper<'a> {
crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs);
}
let merged = self.builder.insert_phi(inputs)?;
self.builder.variable_map.insert(name, merged);
self.builder.variable_ctx.variable_map.insert(name, merged);
Ok(())
}
}

View File

@ -29,7 +29,7 @@ pub fn finalize_method_receiver(builder: &mut MirBuilder, callee: &mut Callee) {
.unwrap_or_else(|| "<none>".to_string());
let bb = builder.current_block;
let names: Vec<String> = builder
.variable_map
.variable_ctx.variable_map
.iter()
.filter(|(_, &vid)| vid == r)
.map(|(k, _)| k.clone())

View File

@ -54,16 +54,16 @@ pub fn ensure(builder: &mut MirBuilder, v: ValueId, kind: LocalKind) -> ValueId
}
// CRITICAL FIX: If `v` is from a pinned slot, check if there's a PHI value for that slot
// in the current block's variable_map. If so, use the PHI value directly instead of
// in the current block's variable_ctx.variable_map. If so, use the PHI value directly instead of
// emitting a Copy from the old value (which might not be defined in this block).
// Try to detect pinned slots for this value and redirect to the latest slot value.
// 1) First, look for "__pin$" entries in variable_map that still point to v.
// 1) First, look for "__pin$" entries in variable_ctx.variable_map that still point to v.
// 2) If not found, consult builder.pin_slot_names to recover the slot name
// and then look up the current ValueId for that slot.
let mut slot_name_opt: Option<String> = None;
let names_for_v: Vec<String> = builder
.variable_map
.variable_ctx.variable_map
.iter()
.filter(|(k, &vid)| vid == v && k.starts_with("__pin$"))
.map(|(k, _)| k.clone())
@ -76,7 +76,7 @@ pub fn ensure(builder: &mut MirBuilder, v: ValueId, kind: LocalKind) -> ValueId
}
if let Some(slot_name) = slot_name_opt {
if let Some(&current_val) = builder.variable_map.get(&slot_name) {
if let Some(&current_val) = builder.variable_ctx.variable_map.get(&slot_name) {
if current_val != v {
// The slot has been updated (likely by a PHI or header rewrite).
// Use the updated value instead of the stale pinned ValueId.

View File

@ -429,7 +429,7 @@ impl super::MirBuilder {
// Register at least Future<Unknown> to avoid later fail-fast type inference panics.
self.type_ctx.value_types
.insert(future_id, MirType::Future(Box::new(MirType::Unknown)));
self.variable_map.insert(variable.clone(), future_id);
self.variable_ctx.variable_map.insert(variable.clone(), future_id);
if let Some(reg) = self.current_slot_registry.as_mut() {
reg.ensure_slot(&variable, None);
}
@ -448,7 +448,7 @@ impl super::MirBuilder {
.unwrap_or(MirType::Unknown);
self.type_ctx.value_types
.insert(future_id, MirType::Future(Box::new(inner)));
self.variable_map.insert(variable.clone(), future_id);
self.variable_ctx.variable_map.insert(variable.clone(), future_id);
if let Some(reg) = self.current_slot_registry.as_mut() {
reg.ensure_slot(&variable, None);
}
@ -478,7 +478,7 @@ impl super::MirBuilder {
// me: resolve to param if present; else symbolic const (stable mapping)
pub(super) fn build_me_expression(&mut self) -> Result<ValueId, String> {
if let Some(id) = self.variable_map.get("me").cloned() {
if let Some(id) = self.variable_ctx.variable_map.get("me").cloned() {
return Ok(id);
}
let me_tag = if let Some(ref cls) = self.current_static_box {
@ -487,7 +487,7 @@ impl super::MirBuilder {
"__me__".to_string()
};
let me_value = crate::mir::builder::emission::constant::emit_string(self, me_tag);
self.variable_map.insert("me".to_string(), me_value);
self.variable_ctx.variable_map.insert("me".to_string(), me_value);
if let Some(reg) = self.current_slot_registry.as_mut() {
reg.ensure_slot("me", None);
}

View File

@ -132,31 +132,31 @@ impl super::MirBuilder {
if false && !self.suppress_pin_entry_copy_next {
// Keep old code for reference
// First pass: copy all pin slots and remember old->new mapping
let names: Vec<String> = self.variable_map.keys().cloned().collect();
let names: Vec<String> = self.variable_ctx.variable_map.keys().cloned().collect();
let mut pin_renames: Vec<(super::ValueId, super::ValueId)> = Vec::new();
for name in names.iter() {
if !name.starts_with("__pin$") {
continue;
}
if let Some(&src) = self.variable_map.get(name) {
if let Some(&src) = self.variable_ctx.variable_map.get(name) {
let dst = self.next_value_id();
self.emit_instruction(super::MirInstruction::Copy { dst, src })?;
crate::mir::builder::metadata::propagate::propagate(self, src, dst);
self.variable_map.insert(name.clone(), dst);
self.variable_ctx.variable_map.insert(name.clone(), dst);
pin_renames.push((src, dst));
}
}
// Second pass: update any user variables that pointed to old pin ids to the new ones
if !pin_renames.is_empty() {
let snapshot: Vec<(String, super::ValueId)> = self
.variable_map
.variable_ctx.variable_map
.iter()
.filter(|(k, _)| !k.starts_with("__pin$"))
.map(|(k, &v)| (k.clone(), v))
.collect();
for (k, v) in snapshot.into_iter() {
if let Some((_, newv)) = pin_renames.iter().find(|(oldv, _)| *oldv == v) {
self.variable_map.insert(k, *newv);
self.variable_ctx.variable_map.insert(k, *newv);
}
}
}
@ -460,7 +460,7 @@ impl super::MirBuilder {
// LocalSSA uses this to redirect old pinned values to the latest slot value.
self.pin_slot_names.insert(v, slot_name.clone());
self.pin_slot_names.insert(dst, slot_name.clone());
self.variable_map.insert(slot_name, dst);
self.variable_ctx.variable_map.insert(slot_name, dst);
Ok(dst)
}

View File

@ -17,7 +17,7 @@ impl AssignmentResolverBox {
return Ok(());
}
if builder.variable_map.contains_key(var_name) {
if builder.variable_ctx.variable_map.contains_key(var_name) {
return Ok(());
}

View File

@ -51,10 +51,10 @@ impl super::super::MirBuilder {
for (name, previous) in frame.restore {
match previous {
Some(prev_id) => {
self.variable_map.insert(name, prev_id);
self.variable_ctx.variable_map.insert(name, prev_id);
}
None => {
self.variable_map.remove(&name);
self.variable_ctx.variable_map.remove(&name);
}
}
}
@ -85,7 +85,7 @@ impl super::super::MirBuilder {
if frame.declared.insert(name.to_string()) {
// Capture previous ValueId for restoration
let previous = self.variable_map.get(name).copied();
let previous = self.variable_ctx.variable_map.get(name).copied();
frame.restore.insert(name.to_string(), previous);
// Phase 74: Capture previous BindingId for parallel restoration
@ -97,7 +97,7 @@ impl super::super::MirBuilder {
}
// Update both ValueId and BindingId mappings
self.variable_map.insert(name.to_string(), value);
self.variable_ctx.variable_map.insert(name.to_string(), value);
// Phase 74: Allocate and register new BindingId for this binding
let binding_id = self.allocate_binding_id();

View File

@ -167,7 +167,7 @@ fn classify_slots_from_registry(reg: &mut FunctionSlotRegistry) -> Vec<SlotMetad
fn classify_slots_from_variable_map(builder: &MirBuilder) -> Vec<SlotMetadata> {
let mut slots = Vec::new();
for (name, &vid) in builder.variable_map.iter() {
for (name, &vid) in builder.variable_ctx.variable_map().iter() {
let ref_kind = classify_slot(builder, vid, name.as_str());
slots.push(SlotMetadata {
name: name.clone(),