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:
@ -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 → BTreeMap(PHI生成の決定性確保)
|
||||
#[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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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"));
|
||||
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
)?;
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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)?;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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(¤t_val) = builder.variable_map.get(&slot_name) {
|
||||
if let Some(¤t_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.
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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(());
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user