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).
|
/// Direct field access for backward compatibility (migration in progress).
|
||||||
pub(super) comp_ctx: compilation_context::CompilationContext,
|
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
|
/// Pending phi functions to be inserted
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(super) pending_phis: Vec<(BasicBlockId, ValueId, String)>,
|
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
|
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
|
metadata_ctx: metadata_context::MetadataContext::new(), // Phase 136 Step 6/7: Metadata context
|
||||||
comp_ctx, // Phase 136 Step 7/7: Compilation context
|
comp_ctx, // Phase 136 Step 7/7: Compilation context
|
||||||
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保 (backward compat)
|
|
||||||
pending_phis: Vec::new(),
|
pending_phis: Vec::new(),
|
||||||
user_defined_boxes: HashSet::new(),
|
user_defined_boxes: HashSet::new(),
|
||||||
weak_fields_by_box: HashMap::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 2-5: BindingContext sync helpers removed - binding_ctx is now SSOT
|
||||||
|
// Phase 2-6: VariableContext sync helpers removed - variable_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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Push/pop helpers for If merge context (best-effort; optional usage)
|
/// Push/pop helpers for If merge context (best-effort; optional usage)
|
||||||
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
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)
|
Ok(value_id)
|
||||||
} else {
|
} else {
|
||||||
Err(self.undefined_variable_message(&name))
|
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).
|
// Result: VM would try to read undefined ValueIds (e.g., ValueId(270) at bb303).
|
||||||
if !var_name.starts_with("__pin$") {
|
if !var_name.starts_with("__pin$") {
|
||||||
// In SSA form, each assignment creates a new value
|
// 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)
|
Ok(value_id)
|
||||||
@ -808,7 +789,7 @@ impl MirBuilder {
|
|||||||
}) = callee
|
}) = callee
|
||||||
{
|
{
|
||||||
let names: Vec<String> = self
|
let names: Vec<String> = self
|
||||||
.variable_map
|
.variable_ctx.variable_map
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, &vid)| vid == *r)
|
.filter(|(_, &vid)| vid == *r)
|
||||||
.map(|(k, _)| k.clone())
|
.map(|(k, _)| k.clone())
|
||||||
@ -1148,13 +1129,11 @@ mod binding_id_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)]
|
|
||||||
fn test_binding_map_initialization() {
|
fn test_binding_map_initialization() {
|
||||||
let builder = MirBuilder::new();
|
let builder = MirBuilder::new();
|
||||||
assert_eq!(builder.core_ctx.next_binding_id, 0);
|
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_ctx.is_empty());
|
||||||
assert!(builder.binding_map.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1171,7 +1150,6 @@ mod binding_id_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(deprecated)]
|
|
||||||
fn test_shadowing_binding_restore() {
|
fn test_shadowing_binding_restore() {
|
||||||
let mut builder = MirBuilder::new();
|
let mut builder = MirBuilder::new();
|
||||||
|
|
||||||
@ -1184,11 +1162,9 @@ mod binding_id_tests {
|
|||||||
builder
|
builder
|
||||||
.declare_local_in_current_scope("x", outer_vid)
|
.declare_local_in_current_scope("x", outer_vid)
|
||||||
.unwrap();
|
.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();
|
let outer_bid = builder.binding_ctx.lookup("x").unwrap();
|
||||||
assert_eq!(outer_bid.raw(), 0);
|
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
|
// Enter inner scope and shadow x
|
||||||
builder.push_lexical_scope();
|
builder.push_lexical_scope();
|
||||||
@ -1197,20 +1173,16 @@ mod binding_id_tests {
|
|||||||
builder
|
builder
|
||||||
.declare_local_in_current_scope("x", inner_vid)
|
.declare_local_in_current_scope("x", inner_vid)
|
||||||
.unwrap();
|
.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();
|
let inner_bid = builder.binding_ctx.lookup("x").unwrap();
|
||||||
assert_eq!(inner_bid.raw(), 1);
|
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
|
// Exit inner scope - should restore outer binding
|
||||||
builder.pop_lexical_scope();
|
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();
|
let restored_bid = builder.binding_ctx.lookup("x").unwrap();
|
||||||
assert_eq!(restored_bid, outer_bid);
|
assert_eq!(restored_bid, outer_bid);
|
||||||
assert_eq!(restored_bid.raw(), 0);
|
assert_eq!(restored_bid.raw(), 0);
|
||||||
// Also verify legacy field is synced
|
|
||||||
assert_eq!(*builder.binding_map.get("x").unwrap(), restored_bid);
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
builder.pop_lexical_scope();
|
builder.pop_lexical_scope();
|
||||||
|
|||||||
@ -421,7 +421,7 @@ impl MirBuilder {
|
|||||||
method: &str,
|
method: &str,
|
||||||
arguments: &[ASTNode],
|
arguments: &[ASTNode],
|
||||||
) -> Result<Option<ValueId>, String> {
|
) -> 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
|
// Debug trace
|
||||||
if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") {
|
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 contains '{}' - treating as local variable, will use method call", obj_name);
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[DEBUG] variable_map keys: {:?}",
|
"[DEBUG] variable_map keys: {:?}",
|
||||||
self.variable_map.keys().collect::<Vec<_>>()
|
self.variable_ctx.variable_map.keys().collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("[DEBUG] '{}' not in variable_map - treating as static box, will use global call", obj_name);
|
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) {
|
if let Some(origin) = self.type_ctx.value_origin_newbox.get(&object_value) {
|
||||||
eprintln!("[DEBUG/param-recv] origin: {}", origin);
|
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!(
|
eprintln!(
|
||||||
"[DEBUG/param-recv] variable_map['{}'] = ValueId({})",
|
"[DEBUG/param-recv] variable_map['{}'] = ValueId({})",
|
||||||
name, mapped_id.0
|
name, mapped_id.0
|
||||||
|
|||||||
@ -37,7 +37,7 @@ impl MirBuilder {
|
|||||||
// BoxCompilationContext vs saved_var_map モード判定
|
// BoxCompilationContext vs saved_var_map モード判定
|
||||||
let context_active = self.compilation_context.is_some();
|
let context_active = self.compilation_context.is_some();
|
||||||
let saved_var_map = if !context_active {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -47,7 +47,7 @@ impl MirBuilder {
|
|||||||
|
|
||||||
// BoxCompilationContext mode: clear()で完全独立化
|
// BoxCompilationContext mode: clear()で完全独立化
|
||||||
if context_active {
|
if context_active {
|
||||||
self.variable_map.clear();
|
self.variable_ctx.variable_map.clear();
|
||||||
self.type_ctx.value_origin_newbox.clear();
|
self.type_ctx.value_origin_newbox.clear();
|
||||||
// value_types も static box 単位で独立させる。
|
// value_types も static box 単位で独立させる。
|
||||||
// これにより、前の static box で使用された ValueId に紐づく型情報が
|
// これにより、前の static box で使用された ValueId に紐づく型情報が
|
||||||
@ -139,7 +139,7 @@ impl MirBuilder {
|
|||||||
f.params.push(new_pid);
|
f.params.push(new_pid);
|
||||||
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)
|
// Phase 136 Step 3/7: Insert into scope_ctx (SSOT)
|
||||||
self.scope_ctx.function_param_names.insert(p.clone());
|
self.scope_ctx.function_param_names.insert(p.clone());
|
||||||
|
|
||||||
@ -237,13 +237,13 @@ impl MirBuilder {
|
|||||||
// モード別にcontext復元
|
// モード別にcontext復元
|
||||||
if ctx.context_active {
|
if ctx.context_active {
|
||||||
// BoxCompilationContext mode: clear のみ(次回も完全独立)
|
// BoxCompilationContext mode: clear のみ(次回も完全独立)
|
||||||
self.variable_map.clear();
|
self.variable_ctx.variable_map.clear();
|
||||||
self.type_ctx.value_origin_newbox.clear();
|
self.type_ctx.value_origin_newbox.clear();
|
||||||
// static box ごとに型情報も独立させる(前 box の型メタデータを引きずらない)
|
// static box ごとに型情報も独立させる(前 box の型メタデータを引きずらない)
|
||||||
self.type_ctx.value_types.clear();
|
self.type_ctx.value_types.clear();
|
||||||
} else if let Some(saved) = ctx.saved_var_map {
|
} else if let Some(saved) = ctx.saved_var_map {
|
||||||
// Legacy mode: Main.main 側の variable_map を元に戻す
|
// Legacy mode: Main.main 側の variable_map を元に戻す
|
||||||
self.variable_map = saved;
|
self.variable_ctx.variable_map = saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static box context復元
|
// Static box context復元
|
||||||
@ -307,7 +307,7 @@ impl MirBuilder {
|
|||||||
|
|
||||||
// me
|
// me
|
||||||
let me_id = f.params[0];
|
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());
|
self.type_ctx.value_origin_newbox.insert(me_id, box_name.to_string());
|
||||||
slot_regs.push(("me".to_string(), None));
|
slot_regs.push(("me".to_string(), None));
|
||||||
|
|
||||||
@ -316,13 +316,13 @@ impl MirBuilder {
|
|||||||
let param_idx = idx + 1;
|
let param_idx = idx + 1;
|
||||||
if param_idx < f.params.len() {
|
if param_idx < f.params.len() {
|
||||||
let pid = f.params[param_idx];
|
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));
|
slot_regs.push((p.clone(), None));
|
||||||
} else {
|
} else {
|
||||||
// 念のため足りない場合は新規に確保(互換用)
|
// 念のため足りない場合は新規に確保(互換用)
|
||||||
let pid = f.next_value_id();
|
let pid = f.next_value_id();
|
||||||
f.params.push(pid);
|
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));
|
slot_regs.push((p.clone(), None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,7 +402,7 @@ impl MirBuilder {
|
|||||||
// Step 1: Context準備(instance methodでは不要だがAPI統一のため)
|
// Step 1: Context準備(instance methodでは不要だがAPI統一のため)
|
||||||
let mut ctx = LoweringContext {
|
let mut ctx = LoweringContext {
|
||||||
context_active: false,
|
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_static_ctx: None,
|
||||||
saved_function: None,
|
saved_function: None,
|
||||||
saved_block: None,
|
saved_block: None,
|
||||||
@ -473,7 +473,7 @@ impl MirBuilder {
|
|||||||
self.scope_ctx.current_function = ctx.saved_function;
|
self.scope_ctx.current_function = ctx.saved_function;
|
||||||
self.current_block = ctx.saved_block;
|
self.current_block = ctx.saved_block;
|
||||||
if let Some(saved) = ctx.saved_var_map {
|
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;
|
self.current_slot_registry = ctx.saved_slot_registry;
|
||||||
|
|
||||||
|
|||||||
@ -39,7 +39,7 @@ impl MirBuilder {
|
|||||||
super::method_resolution::resolve_call_target(
|
super::method_resolution::resolve_call_target(
|
||||||
name,
|
name,
|
||||||
&self.current_static_box,
|
&self.current_static_box,
|
||||||
&self.variable_map,
|
&self.variable_ctx.variable_map,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,6 @@ impl MirBuilder {
|
|||||||
/// Enable with NYASH_TRACE_VARMAP=1
|
/// Enable with NYASH_TRACE_VARMAP=1
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(in crate::mir::builder) fn trace_varmap(&self, context: &str) {
|
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
|
//! Modularizes the exit_bindings collection logic from Pattern lowerers
|
||||||
//! into a focused, testable Box.
|
//! 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::builder::MirBuilder;
|
||||||
use crate::mir::join_ir::lowering::carrier_info::ExitMeta;
|
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
|
/// ## Pure Function Philosophy
|
||||||
/// ExitMetaCollector::collect() is a **pure function**:
|
/// 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)
|
/// - Input: exit_meta (data structure)
|
||||||
/// - Output: Vec<LoopExitBinding> (new data)
|
/// - 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?
|
/// ## Why Pure Functions?
|
||||||
/// - Easy to test (no mocks needed)
|
/// - Easy to test (no mocks needed)
|
||||||
@ -40,7 +40,7 @@ use crate::mir::ValueId; // Phase 228-8: For ConditionOnly placeholder
|
|||||||
///
|
///
|
||||||
/// **Input**:
|
/// **Input**:
|
||||||
/// - ExitMeta with exit_values (carrier_name → join_exit_value mappings)
|
/// - 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**:
|
/// **Effect**:
|
||||||
/// - Creates LoopExitBinding vector (pure function, no side effects)
|
/// - 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;
|
pub struct ExitMetaCollector;
|
||||||
|
|
||||||
impl ExitMetaCollector {
|
impl ExitMetaCollector {
|
||||||
/// Build exit_bindings from ExitMeta and variable_map
|
/// Build exit_bindings from ExitMeta and variable_ctx.variable_map
|
||||||
///
|
///
|
||||||
/// # Algorithm
|
/// # Algorithm
|
||||||
///
|
///
|
||||||
/// For each entry in exit_meta.exit_values:
|
/// 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
|
/// 2. Create LoopExitBinding with carrier_name, join_exit_value, host_slot
|
||||||
/// 3. Collect into Vec<LoopExitBinding>
|
/// 3. Collect into Vec<LoopExitBinding>
|
||||||
///
|
///
|
||||||
/// # Phase 228-8: ConditionOnly carrier handling
|
/// # Phase 228-8: ConditionOnly carrier handling
|
||||||
///
|
///
|
||||||
/// ConditionOnly carriers are included in exit_bindings even if they're not
|
/// 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
|
/// The host_slot is set to ValueId(0) as a placeholder since ConditionOnly
|
||||||
/// carriers don't participate in exit PHI.
|
/// carriers don't participate in exit PHI.
|
||||||
///
|
///
|
||||||
/// # Skipped carriers
|
/// # 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.
|
/// This is intentional: some carriers may not be relevant to the current pattern.
|
||||||
///
|
///
|
||||||
/// # Logging
|
/// # Logging
|
||||||
@ -96,13 +96,13 @@ impl ExitMetaCollector {
|
|||||||
for (carrier_name, join_exit_value) in &exit_meta.exit_values {
|
for (carrier_name, join_exit_value) in &exit_meta.exit_values {
|
||||||
if verbose {
|
if verbose {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[joinir/exit-line] checking carrier '{}' in variable_map",
|
"[joinir/exit-line] checking carrier '{}' in variable_ctx.variable_map",
|
||||||
carrier_name
|
carrier_name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up host slot from variable_map
|
// Look up host slot from variable_ctx.variable_map
|
||||||
if let Some(&host_slot) = builder.variable_map.get(carrier_name) {
|
if let Some(&host_slot) = builder.variable_ctx.variable_map.get(carrier_name) {
|
||||||
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||||
|
|
||||||
// Phase 228-8: Look up role from carrier_info if available
|
// Phase 228-8: Look up role from carrier_info if available
|
||||||
@ -157,7 +157,7 @@ impl ExitMetaCollector {
|
|||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
eprintln!(
|
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
|
carrier_name, join_exit_value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ impl ExitMetaCollector {
|
|||||||
}
|
}
|
||||||
Some((CarrierRole::LoopState, CarrierInit::FromHost)) => {
|
Some((CarrierRole::LoopState, CarrierInit::FromHost)) => {
|
||||||
// Phase 247-EX: Include FromHost carrier in exit_bindings
|
// 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 {
|
let binding = LoopExitBinding {
|
||||||
carrier_name: carrier_name.clone(),
|
carrier_name: carrier_name.clone(),
|
||||||
join_exit_value: *join_exit_value,
|
join_exit_value: *join_exit_value,
|
||||||
@ -176,7 +176,7 @@ impl ExitMetaCollector {
|
|||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
eprintln!(
|
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
|
carrier_name, join_exit_value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ impl ExitMetaCollector {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg = format!(
|
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
|
carrier_name
|
||||||
);
|
);
|
||||||
if strict {
|
if strict {
|
||||||
@ -243,7 +243,7 @@ mod tests {
|
|||||||
fn test_missing_carrier_in_variable_map() {
|
fn test_missing_carrier_in_variable_map() {
|
||||||
// This test would require full MirBuilder setup
|
// This test would require full MirBuilder setup
|
||||||
// Placeholder for future detailed testing
|
// 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);
|
assert!(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
//! Modularizes the exit line reconnection logic (Phase 6 from merge/mod.rs)
|
//! Modularizes the exit line reconnection logic (Phase 6 from merge/mod.rs)
|
||||||
//! into a focused, testable Box.
|
//! 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
|
//! # Phase 33-13 Architecture Change
|
||||||
//!
|
//!
|
||||||
@ -23,15 +23,15 @@ use std::collections::BTreeMap;
|
|||||||
/// # Design Notes
|
/// # Design Notes
|
||||||
///
|
///
|
||||||
/// ## Why Separate Box?
|
/// ## 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
|
/// - Input: JoinInlineBoundary.exit_bindings + carrier_phis map
|
||||||
/// - Output: Updated MirBuilder.variable_map
|
/// - Output: Updated MirBuilder.variable_ctx.variable_map
|
||||||
/// - No side effects beyond variable_map updates
|
/// - No side effects beyond variable_ctx.variable_map updates
|
||||||
///
|
///
|
||||||
/// ## Phase 33-13 Carrier PHI Integration
|
/// ## Phase 33-13 Carrier PHI Integration
|
||||||
/// This Box now uses carrier_phis from exit_phi_builder:
|
/// This Box now uses carrier_phis from exit_phi_builder:
|
||||||
/// - Before: `variable_map[carrier] = remapper.get(join_exit)` (SSA-incorrect!)
|
/// - Before: `variable_ctx.variable_map[carrier] = remapper.get(join_exit)` (SSA-incorrect!)
|
||||||
/// - After: `variable_map[carrier] = carrier_phis[carrier]` (SSA-correct!)
|
/// - After: `variable_ctx.variable_map[carrier] = carrier_phis[carrier]` (SSA-correct!)
|
||||||
///
|
///
|
||||||
/// The key insight is that remapped exit values are PHI INPUTS, not OUTPUTS.
|
/// The key insight is that remapped exit values are PHI INPUTS, not OUTPUTS.
|
||||||
/// Only the PHI dst ValueId is defined in the exit block.
|
/// Only the PHI dst ValueId is defined in the exit block.
|
||||||
@ -40,7 +40,7 @@ use std::collections::BTreeMap;
|
|||||||
/// Can be tested independently:
|
/// Can be tested independently:
|
||||||
/// 1. Create mock boundary with exit_bindings
|
/// 1. Create mock boundary with exit_bindings
|
||||||
/// 2. Create mock carrier_phis map
|
/// 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
|
/// 4. No need to construct full merge/mod.rs machinery
|
||||||
///
|
///
|
||||||
/// # Box Contract
|
/// # Box Contract
|
||||||
@ -50,14 +50,14 @@ use std::collections::BTreeMap;
|
|||||||
/// - carrier_phis: Map from carrier name to PHI dst ValueId
|
/// - carrier_phis: Map from carrier name to PHI dst ValueId
|
||||||
///
|
///
|
||||||
/// **Effect**:
|
/// **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**:
|
/// **Output**:
|
||||||
/// - Result<(), String> (side effect on builder)
|
/// - Result<(), String> (side effect on builder)
|
||||||
pub struct ExitLineReconnector;
|
pub struct ExitLineReconnector;
|
||||||
|
|
||||||
impl 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
|
/// # Phase 33-13: Carrier PHI Integration
|
||||||
///
|
///
|
||||||
@ -71,7 +71,7 @@ impl ExitLineReconnector {
|
|||||||
///
|
///
|
||||||
/// For each exit_binding:
|
/// For each exit_binding:
|
||||||
/// 1. Look up the PHI dst for this carrier in carrier_phis
|
/// 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)
|
/// 3. Log each update (if debug enabled)
|
||||||
pub fn reconnect(
|
pub fn reconnect(
|
||||||
builder: &mut MirBuilder,
|
builder: &mut MirBuilder,
|
||||||
@ -119,12 +119,12 @@ impl ExitLineReconnector {
|
|||||||
|
|
||||||
// Process each exit binding
|
// Process each exit binding
|
||||||
for binding in &boundary.exit_bindings {
|
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;
|
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||||
if binding.role == CarrierRole::ConditionOnly {
|
if binding.role == CarrierRole::ConditionOnly {
|
||||||
if verbose {
|
if verbose {
|
||||||
eprintln!(
|
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
|
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(&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
|
// Phase 177-STRUCT: Always log for debugging
|
||||||
if verbose {
|
if verbose {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[joinir/exit-line] variable_map['{}'] {:?} → {:?}",
|
"[joinir/exit-line] variable_ctx.variable_map['{}'] {:?} → {:?}",
|
||||||
binding.carrier_name, *var_vid, phi_value
|
binding.carrier_name, *var_vid, phi_value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
*var_vid = phi_value;
|
*var_vid = phi_value;
|
||||||
} else if verbose {
|
} else if verbose {
|
||||||
eprintln!(
|
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
|
binding.carrier_name
|
||||||
);
|
);
|
||||||
} else if strict {
|
} else if strict {
|
||||||
return Err(format!(
|
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
|
binding.carrier_name
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -188,9 +188,9 @@ impl ExitLineReconnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Phase 190-impl-D-3: Contract verification (debug build only)
|
// 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)]
|
#[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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -200,14 +200,14 @@ impl ExitLineReconnector {
|
|||||||
/// # Contract Requirements
|
/// # Contract Requirements
|
||||||
///
|
///
|
||||||
/// 1. Every exit_binding must have a corresponding entry in carrier_phis
|
/// 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
|
/// 2. Every exit_binding's carrier must exist in variable_ctx.variable_map after reconnect
|
||||||
/// 3. The variable_map entry must point to the PHI dst (not the original host value)
|
/// 3. The variable_ctx.variable_map entry must point to the PHI dst (not the original host value)
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if any contract violation is detected. This helps catch bugs where:
|
/// Panics if any contract violation is detected. This helps catch bugs where:
|
||||||
/// - PHI is missing for a carrier (Phase 190-impl-D root cause)
|
/// - 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
|
/// - ValueId collision occurred
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
fn verify_exit_line_contract(
|
fn verify_exit_line_contract(
|
||||||
@ -218,10 +218,10 @@ impl ExitLineReconnector {
|
|||||||
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
use crate::mir::join_ir::lowering::carrier_info::CarrierRole;
|
||||||
|
|
||||||
for binding in &boundary.exit_bindings {
|
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 {
|
if binding.role == CarrierRole::ConditionOnly {
|
||||||
eprintln!(
|
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
|
binding.carrier_name
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
@ -240,20 +240,20 @@ impl ExitLineReconnector {
|
|||||||
// Future: Distinguish loop_var from carriers in exit_bindings
|
// 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);
|
let var_value = variable_map.get(&binding.carrier_name);
|
||||||
if var_value.is_none() {
|
if var_value.is_none() {
|
||||||
panic!(
|
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
|
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 let (Some(&phi), Some(&var)) = (phi_dst, var_value) {
|
||||||
if phi != var {
|
if phi != var {
|
||||||
panic!(
|
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
|
binding.carrier_name, var, phi
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ impl MirBuilder {
|
|||||||
let ctx = build_pattern_context(self, condition, body, PatternVariant::Pattern1)?;
|
let ctx = build_pattern_context(self, condition, body, PatternVariant::Pattern1)?;
|
||||||
|
|
||||||
// Phase 195: Use unified trace
|
// 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
|
// 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.
|
// 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(
|
ConditionEnvBuilder::build_for_break_condition_v2(
|
||||||
condition,
|
condition,
|
||||||
&loop_var_name,
|
&loop_var_name,
|
||||||
&builder.variable_map,
|
&builder.variable_ctx.variable_map,
|
||||||
loop_var_id,
|
loop_var_id,
|
||||||
&mut join_value_space,
|
&mut join_value_space,
|
||||||
)?;
|
)?;
|
||||||
@ -140,7 +140,7 @@ fn prepare_pattern2_inputs(
|
|||||||
|
|
||||||
// Add captured vars
|
// Add captured vars
|
||||||
for var in &captured_env.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();
|
let join_id = join_value_space.alloc_param();
|
||||||
env.insert(var.name.clone(), join_id);
|
env.insert(var.name.clone(), join_id);
|
||||||
condition_bindings.push(ConditionBinding {
|
condition_bindings.push(ConditionBinding {
|
||||||
@ -676,7 +676,7 @@ pub(crate) fn can_lower(builder: &MirBuilder, ctx: &super::router::LoopPatternCo
|
|||||||
CommonPatternInitializer::check_carrier_updates_allowed(
|
CommonPatternInitializer::check_carrier_updates_allowed(
|
||||||
ctx.body,
|
ctx.body,
|
||||||
&loop_var_name,
|
&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};
|
use super::pattern_pipeline::{build_pattern_context, PatternVariant};
|
||||||
let ctx = build_pattern_context(self, condition, _body, PatternVariant::Pattern2)?;
|
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 =
|
let mut inputs =
|
||||||
prepare_pattern2_inputs(self, condition, _body, fn_body, &ctx, verbose)?;
|
prepare_pattern2_inputs(self, condition, _body, fn_body, &ctx, verbose)?;
|
||||||
@ -977,11 +977,11 @@ mod tests {
|
|||||||
use crate::mir::ValueId;
|
use crate::mir::ValueId;
|
||||||
|
|
||||||
let mut builder = MirBuilder::new();
|
let mut builder = MirBuilder::new();
|
||||||
builder.variable_map.insert("i".to_string(), ValueId(1));
|
builder.variable_ctx.variable_map.insert("i".to_string(), ValueId(1));
|
||||||
builder.variable_map.insert("len".to_string(), ValueId(2));
|
builder.variable_ctx.variable_map.insert("len".to_string(), ValueId(2));
|
||||||
builder.variable_map.insert("s".to_string(), ValueId(3));
|
builder.variable_ctx.variable_map.insert("s".to_string(), ValueId(3));
|
||||||
builder.variable_map.insert("digits".to_string(), ValueId(4));
|
builder.variable_ctx.variable_map.insert("digits".to_string(), ValueId(4));
|
||||||
builder.variable_map.insert("result".to_string(), ValueId(5));
|
builder.variable_ctx.variable_map.insert("result".to_string(), ValueId(5));
|
||||||
|
|
||||||
let condition = bin(BinaryOperator::Less, var("i"), var("len"));
|
let condition = bin(BinaryOperator::Less, var("i"), var("len"));
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,7 @@ impl MirBuilder {
|
|||||||
ConditionEnvBuilder::build_for_break_condition_v2(
|
ConditionEnvBuilder::build_for_break_condition_v2(
|
||||||
condition,
|
condition,
|
||||||
&loop_var_name,
|
&loop_var_name,
|
||||||
&self.variable_map,
|
&self.variable_ctx.variable_map,
|
||||||
loop_var_id,
|
loop_var_id,
|
||||||
&mut join_value_space,
|
&mut join_value_space,
|
||||||
)?;
|
)?;
|
||||||
@ -183,7 +183,7 @@ impl MirBuilder {
|
|||||||
// Collect parent-defined variables from function scope
|
// Collect parent-defined variables from function scope
|
||||||
// For now, use all variables in variable_map except loop_var
|
// For now, use all variables in variable_map except loop_var
|
||||||
let parent_defined: Vec<String> = self
|
let parent_defined: Vec<String> = self
|
||||||
.variable_map
|
.variable_ctx.variable_map
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|name| *name != &loop_var_name)
|
.filter(|name| *name != &loop_var_name)
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|||||||
@ -81,7 +81,7 @@ pub(crate) fn can_lower(builder: &MirBuilder, ctx: &super::router::LoopPatternCo
|
|||||||
CommonPatternInitializer::check_carrier_updates_allowed(
|
CommonPatternInitializer::check_carrier_updates_allowed(
|
||||||
ctx.body,
|
ctx.body,
|
||||||
&loop_var_name,
|
&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::loop_with_continue_minimal::lower_loop_with_continue_minimal;
|
||||||
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
|
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();
|
let mut join_value_space = JoinValueSpace::new();
|
||||||
|
|
||||||
|
|||||||
@ -316,9 +316,9 @@ pub(crate) fn lower(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Get counter ValueId from variable_map
|
// Step 2: Get counter ValueId from variable_ctx.variable_map
|
||||||
let counter_id = builder.variable_map.get(&counter_name).copied().ok_or_else(|| {
|
let counter_id = builder.variable_ctx.variable_map.get(&counter_name).copied().ok_or_else(|| {
|
||||||
format!("Counter variable '{}' not found in variable_map", counter_name)
|
format!("Counter variable '{}' not found in variable_ctx.variable_map", counter_name)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
|
|||||||
@ -263,7 +263,7 @@ pub(crate) fn build_pattern_context(
|
|||||||
let (loop_var_name, loop_var_id, carrier_info) = CommonPatternInitializer::initialize_pattern(
|
let (loop_var_name, loop_var_id, carrier_info) = CommonPatternInitializer::initialize_pattern(
|
||||||
builder,
|
builder,
|
||||||
condition,
|
condition,
|
||||||
&builder.variable_map,
|
&builder.variable_ctx.variable_map,
|
||||||
None, // No exclusions for now (Pattern 2/4 will filter carriers later)
|
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)?;
|
Self::generate_carrier_initialization(builder, body, trim_helper)?;
|
||||||
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[TrimLoopLowerer] Registered carrier '{}' in variable_map",
|
"[TrimLoopLowerer] Registered carrier '{}' in variable_ctx.variable_map",
|
||||||
trim_helper.carrier_name
|
trim_helper.carrier_name
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ impl TrimLoopLowerer {
|
|||||||
/// Generates:
|
/// Generates:
|
||||||
/// 1. ch0 = s.substring(start, start+1)
|
/// 1. ch0 = s.substring(start, start+1)
|
||||||
/// 2. is_ch_match0 = (ch0 == " " || ch0 == "\t" || ...)
|
/// 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(
|
fn generate_carrier_initialization(
|
||||||
builder: &mut MirBuilder,
|
builder: &mut MirBuilder,
|
||||||
body: &[ASTNode],
|
body: &[ASTNode],
|
||||||
@ -353,7 +353,7 @@ impl TrimLoopLowerer {
|
|||||||
|
|
||||||
// Get ValueIds for string and start
|
// Get ValueIds for string and start
|
||||||
let s_id =
|
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)
|
format!("[TrimLoopLowerer] String variable '{}' not found", s_name)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -401,9 +401,9 @@ impl TrimLoopLowerer {
|
|||||||
is_ch_match0
|
is_ch_match0
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register carrier in variable_map
|
// Register carrier in variable_ctx.variable_map
|
||||||
builder
|
builder
|
||||||
.variable_map
|
.variable_ctx.variable_map
|
||||||
.insert(trim_helper.carrier_name.clone(), is_ch_match0);
|
.insert(trim_helper.carrier_name.clone(), is_ch_match0);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -438,7 +438,7 @@ impl TrimLoopLowerer {
|
|||||||
let mut bindings = Vec::new();
|
let mut bindings = Vec::new();
|
||||||
|
|
||||||
// Add carrier to ConditionEnv
|
// 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 mut env_temp = std::collections::HashMap::new(); // Temporary env for closure
|
||||||
|
|
||||||
let binding = TrimPatternLowerer::add_to_condition_env(
|
let binding = TrimPatternLowerer::add_to_condition_env(
|
||||||
|
|||||||
@ -47,7 +47,7 @@ impl super::MirBuilder {
|
|||||||
);
|
);
|
||||||
eprintln!("[DEBUG] params.len() = {}", params.len());
|
eprintln!("[DEBUG] params.len() = {}", params.len());
|
||||||
eprintln!("[DEBUG] body.len() = {}", body.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 (箱理論)
|
// Note: Metadata clearing is now handled by BoxCompilationContext (箱理論)
|
||||||
// See lifecycle.rs and builder_calls.rs for context swap implementation
|
// See lifecycle.rs and builder_calls.rs for context swap implementation
|
||||||
let _ = self.lower_static_method_as_function(
|
let _ = self.lower_static_method_as_function(
|
||||||
@ -58,11 +58,11 @@ impl super::MirBuilder {
|
|||||||
eprintln!(
|
eprintln!(
|
||||||
"[DEBUG] build_static_main_box: After lower_static_method_as_function"
|
"[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
|
// Initialize local variables for Main.main() parameters
|
||||||
// Note: These are local variables in the wrapper main() function, NOT 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();
|
let script_args = collect_script_args_from_env();
|
||||||
for p in params.iter() {
|
for p in params.iter() {
|
||||||
// Allocate a value ID using the current function's value generator
|
// 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 })?;
|
self.emit_instruction(MirInstruction::Copy { dst: pid, src: v })?;
|
||||||
crate::mir::builder::metadata::propagate::propagate(self, v, pid);
|
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 にも登録しておくよ(観測専用)
|
// 関数スコープ SlotRegistry にも登録しておくよ(観測専用)
|
||||||
if let Some(reg) = self.current_slot_registry.as_mut() {
|
if let Some(reg) = self.current_slot_registry.as_mut() {
|
||||||
let ty = self.type_ctx.value_types.get(&pid).cloned();
|
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
|
// Phase 200-C: Clear fn_body_ast after main() lowering
|
||||||
self.fn_body_ast = None;
|
self.fn_body_ast = None;
|
||||||
|
|
||||||
self.variable_map = saved_var_map;
|
self.variable_ctx.variable_map = saved_var_map;
|
||||||
lowered
|
lowered
|
||||||
} else {
|
} else {
|
||||||
Err("main method in static box is not a FunctionDeclaration".to_string())
|
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();
|
let mut captures: Vec<(String, ValueId)> = Vec::new();
|
||||||
for name in used.into_iter() {
|
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));
|
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();
|
let dst = self.next_value_id();
|
||||||
self.emit_instruction(super::MirInstruction::NewClosure {
|
self.emit_instruction(super::MirInstruction::NewClosure {
|
||||||
dst,
|
dst,
|
||||||
|
|||||||
@ -43,7 +43,7 @@ impl<'a> PhiBuilderOps for ToplevelOps<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_var(&mut self, name: String, value: ValueId) {
|
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> {
|
fn get_block_predecessors(&self, block: BasicBlockId) -> Vec<BasicBlockId> {
|
||||||
@ -113,7 +113,7 @@ impl MirBuilder {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Snapshot variables before entering branches
|
// 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");
|
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
|
// Scope enter for then-branch
|
||||||
self.hint_scope_enter(0);
|
self.hint_scope_enter(0);
|
||||||
let then_ast_for_analysis = then_branch.clone();
|
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)
|
// Materialize all variables at block entry via single-pred Phi (correctness-first)
|
||||||
for (name, &pre_v) in pre_if_var_map.iter() {
|
for (name, &pre_v) in pre_if_var_map.iter() {
|
||||||
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
|
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 {
|
if trace_if {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[if-trace] then-entry phi var={} pre={:?} -> dst={:?}",
|
"[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_value_raw = self.build_expression(then_branch)?;
|
||||||
let then_exit_block = self.current_block()?;
|
let then_exit_block = self.current_block()?;
|
||||||
let then_reaches_merge = !self.is_current_block_terminated();
|
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 {
|
if then_reaches_merge {
|
||||||
// Scope leave for then-branch
|
// Scope leave for then-branch
|
||||||
self.hint_scope_leave(0);
|
self.hint_scope_leave(0);
|
||||||
@ -157,11 +157,11 @@ impl MirBuilder {
|
|||||||
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) =
|
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) =
|
||||||
if let Some(else_ast) = else_branch {
|
if let Some(else_ast) = else_branch {
|
||||||
// Reset variable_map BEFORE materializing PHI nodes (same pattern as then-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)
|
// Materialize all variables at block entry via single-pred Phi (correctness-first)
|
||||||
for (name, &pre_v) in pre_if_var_map.iter() {
|
for (name, &pre_v) in pre_if_var_map.iter() {
|
||||||
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
|
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 {
|
if trace_if {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
|
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
|
||||||
@ -170,13 +170,13 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let val = self.build_expression(else_ast.clone())?;
|
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 {
|
} else {
|
||||||
// No else branch: materialize PHI nodes for the empty else block
|
// 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() {
|
for (name, &pre_v) in pre_if_var_map.iter() {
|
||||||
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
|
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 {
|
if trace_if {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[if-trace] else-entry phi var={} pre={:?} -> dst={:?}",
|
"[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);
|
let void_val = crate::mir::builder::emission::constant::emit_void(self);
|
||||||
// Phase 25.1c/k: Pass PHI-renamed variable_map for empty else branch
|
// Phase 25.1c/k: Pass PHI-renamed variable_map for empty else branch
|
||||||
// This ensures merge_modified_vars uses correct ValueIds after PHI renaming
|
// 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_exit_block = self.current_block()?;
|
||||||
let else_reaches_merge = !self.is_current_block_terminated();
|
let else_reaches_merge = !self.is_current_block_terminated();
|
||||||
|
|||||||
@ -354,17 +354,17 @@ impl super::MirBuilder {
|
|||||||
let pre_branch_bb = self.current_block()?;
|
let pre_branch_bb = self.current_block()?;
|
||||||
|
|
||||||
// Snapshot variables before entering branches
|
// 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 ----
|
// ---- THEN branch ----
|
||||||
self.start_new_block(then_block)?;
|
self.start_new_block(then_block)?;
|
||||||
self.hint_scope_enter(0);
|
self.hint_scope_enter(0);
|
||||||
// Reset scope to pre-if snapshot for clean deltas
|
// 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)
|
// Materialize all variables at entry via single-pred PHI (correctness-first)
|
||||||
for (name, &pre_v) in pre_if_var_map.iter() {
|
for (name, &pre_v) in pre_if_var_map.iter() {
|
||||||
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
|
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
|
// AND: then → evaluate RHS and reduce to bool
|
||||||
@ -404,7 +404,7 @@ impl super::MirBuilder {
|
|||||||
};
|
};
|
||||||
let then_exit_block = self.current_block()?;
|
let then_exit_block = self.current_block()?;
|
||||||
let then_reaches_merge = !self.is_current_block_terminated();
|
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 {
|
if then_reaches_merge {
|
||||||
self.hint_scope_leave(0);
|
self.hint_scope_leave(0);
|
||||||
crate::mir::builder::emission::branch::emit_jump(self, merge_block)?;
|
crate::mir::builder::emission::branch::emit_jump(self, merge_block)?;
|
||||||
@ -413,11 +413,11 @@ impl super::MirBuilder {
|
|||||||
// ---- ELSE branch ----
|
// ---- ELSE branch ----
|
||||||
self.start_new_block(else_block)?;
|
self.start_new_block(else_block)?;
|
||||||
self.hint_scope_enter(0);
|
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)
|
// Materialize all variables at entry via single-pred PHI (correctness-first)
|
||||||
for (name, &pre_v) in pre_if_var_map.iter() {
|
for (name, &pre_v) in pre_if_var_map.iter() {
|
||||||
let phi_val = self.insert_phi_single(pre_branch_bb, pre_v)?;
|
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
|
// AND: else → false
|
||||||
// OR: else → evaluate RHS and reduce to bool
|
// OR: else → evaluate RHS and reduce to bool
|
||||||
@ -455,7 +455,7 @@ impl super::MirBuilder {
|
|||||||
};
|
};
|
||||||
let else_exit_block = self.current_block()?;
|
let else_exit_block = self.current_block()?;
|
||||||
let else_reaches_merge = !self.is_current_block_terminated();
|
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 {
|
if else_reaches_merge {
|
||||||
self.hint_scope_leave(0);
|
self.hint_scope_leave(0);
|
||||||
crate::mir::builder::emission::branch::emit_jump(self, merge_block)?;
|
crate::mir::builder::emission::branch::emit_jump(self, merge_block)?;
|
||||||
|
|||||||
@ -64,7 +64,7 @@ impl MirBuilder {
|
|||||||
0 => {}
|
0 => {}
|
||||||
1 => {
|
1 => {
|
||||||
let (_pred, v) = inputs[0];
|
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() {
|
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
|
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 => {}
|
0 => {}
|
||||||
1 => {
|
1 => {
|
||||||
// Direct bind (no PHI needed)
|
// Direct bind (no PHI needed)
|
||||||
self.variable_map = pre_if_var_map.clone();
|
self.variable_ctx.variable_map = pre_if_var_map.clone();
|
||||||
self.variable_map.insert(var_name, inputs[0].1);
|
self.variable_ctx.variable_map.insert(var_name, inputs[0].1);
|
||||||
return Ok(inputs[0].1);
|
return Ok(inputs[0].1);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -181,8 +181,8 @@ impl MirBuilder {
|
|||||||
self.insert_phi_with_dst(result_val, inputs)?;
|
self.insert_phi_with_dst(result_val, inputs)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.variable_map = pre_if_var_map.clone();
|
self.variable_ctx.variable_map = pre_if_var_map.clone();
|
||||||
self.variable_map.insert(var_name, result_val);
|
self.variable_ctx.variable_map.insert(var_name, result_val);
|
||||||
} else {
|
} else {
|
||||||
// No variable assignment pattern detected – just emit Phi for expression result
|
// No variable assignment pattern detected – just emit Phi for expression result
|
||||||
let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new();
|
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)
|
// 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)
|
Ok(result_val)
|
||||||
|
|||||||
@ -81,7 +81,7 @@ impl<'a> PhiMergeHelper<'a> {
|
|||||||
1 => {
|
1 => {
|
||||||
// Single predecessor - direct insert (no PHI)
|
// Single predecessor - direct insert (no PHI)
|
||||||
let (_pred, v) = inputs[0];
|
let (_pred, v) = inputs[0];
|
||||||
self.builder.variable_map.insert(name, v);
|
self.builder.variable_ctx.variable_map.insert(name, v);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -95,7 +95,7 @@ impl<'a> PhiMergeHelper<'a> {
|
|||||||
crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs);
|
crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs);
|
||||||
}
|
}
|
||||||
let merged = self.builder.insert_phi(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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ pub fn finalize_method_receiver(builder: &mut MirBuilder, callee: &mut Callee) {
|
|||||||
.unwrap_or_else(|| "<none>".to_string());
|
.unwrap_or_else(|| "<none>".to_string());
|
||||||
let bb = builder.current_block;
|
let bb = builder.current_block;
|
||||||
let names: Vec<String> = builder
|
let names: Vec<String> = builder
|
||||||
.variable_map
|
.variable_ctx.variable_map
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, &vid)| vid == r)
|
.filter(|(_, &vid)| vid == r)
|
||||||
.map(|(k, _)| k.clone())
|
.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
|
// 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).
|
// 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.
|
// 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
|
// 2) If not found, consult builder.pin_slot_names to recover the slot name
|
||||||
// and then look up the current ValueId for that slot.
|
// and then look up the current ValueId for that slot.
|
||||||
let mut slot_name_opt: Option<String> = None;
|
let mut slot_name_opt: Option<String> = None;
|
||||||
|
|
||||||
let names_for_v: Vec<String> = builder
|
let names_for_v: Vec<String> = builder
|
||||||
.variable_map
|
.variable_ctx.variable_map
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(k, &vid)| vid == v && k.starts_with("__pin$"))
|
.filter(|(k, &vid)| vid == v && k.starts_with("__pin$"))
|
||||||
.map(|(k, _)| k.clone())
|
.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(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 {
|
if current_val != v {
|
||||||
// The slot has been updated (likely by a PHI or header rewrite).
|
// The slot has been updated (likely by a PHI or header rewrite).
|
||||||
// Use the updated value instead of the stale pinned ValueId.
|
// 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.
|
// Register at least Future<Unknown> to avoid later fail-fast type inference panics.
|
||||||
self.type_ctx.value_types
|
self.type_ctx.value_types
|
||||||
.insert(future_id, MirType::Future(Box::new(MirType::Unknown)));
|
.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() {
|
if let Some(reg) = self.current_slot_registry.as_mut() {
|
||||||
reg.ensure_slot(&variable, None);
|
reg.ensure_slot(&variable, None);
|
||||||
}
|
}
|
||||||
@ -448,7 +448,7 @@ impl super::MirBuilder {
|
|||||||
.unwrap_or(MirType::Unknown);
|
.unwrap_or(MirType::Unknown);
|
||||||
self.type_ctx.value_types
|
self.type_ctx.value_types
|
||||||
.insert(future_id, MirType::Future(Box::new(inner)));
|
.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() {
|
if let Some(reg) = self.current_slot_registry.as_mut() {
|
||||||
reg.ensure_slot(&variable, None);
|
reg.ensure_slot(&variable, None);
|
||||||
}
|
}
|
||||||
@ -478,7 +478,7 @@ impl super::MirBuilder {
|
|||||||
|
|
||||||
// me: resolve to param if present; else symbolic const (stable mapping)
|
// me: resolve to param if present; else symbolic const (stable mapping)
|
||||||
pub(super) fn build_me_expression(&mut self) -> Result<ValueId, String> {
|
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);
|
return Ok(id);
|
||||||
}
|
}
|
||||||
let me_tag = if let Some(ref cls) = self.current_static_box {
|
let me_tag = if let Some(ref cls) = self.current_static_box {
|
||||||
@ -487,7 +487,7 @@ impl super::MirBuilder {
|
|||||||
"__me__".to_string()
|
"__me__".to_string()
|
||||||
};
|
};
|
||||||
let me_value = crate::mir::builder::emission::constant::emit_string(self, me_tag);
|
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() {
|
if let Some(reg) = self.current_slot_registry.as_mut() {
|
||||||
reg.ensure_slot("me", None);
|
reg.ensure_slot("me", None);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,31 +132,31 @@ impl super::MirBuilder {
|
|||||||
if false && !self.suppress_pin_entry_copy_next {
|
if false && !self.suppress_pin_entry_copy_next {
|
||||||
// Keep old code for reference
|
// Keep old code for reference
|
||||||
// First pass: copy all pin slots and remember old->new mapping
|
// 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();
|
let mut pin_renames: Vec<(super::ValueId, super::ValueId)> = Vec::new();
|
||||||
for name in names.iter() {
|
for name in names.iter() {
|
||||||
if !name.starts_with("__pin$") {
|
if !name.starts_with("__pin$") {
|
||||||
continue;
|
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();
|
let dst = self.next_value_id();
|
||||||
self.emit_instruction(super::MirInstruction::Copy { dst, src })?;
|
self.emit_instruction(super::MirInstruction::Copy { dst, src })?;
|
||||||
crate::mir::builder::metadata::propagate::propagate(self, src, dst);
|
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));
|
pin_renames.push((src, dst));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Second pass: update any user variables that pointed to old pin ids to the new ones
|
// Second pass: update any user variables that pointed to old pin ids to the new ones
|
||||||
if !pin_renames.is_empty() {
|
if !pin_renames.is_empty() {
|
||||||
let snapshot: Vec<(String, super::ValueId)> = self
|
let snapshot: Vec<(String, super::ValueId)> = self
|
||||||
.variable_map
|
.variable_ctx.variable_map
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(k, _)| !k.starts_with("__pin$"))
|
.filter(|(k, _)| !k.starts_with("__pin$"))
|
||||||
.map(|(k, &v)| (k.clone(), v))
|
.map(|(k, &v)| (k.clone(), v))
|
||||||
.collect();
|
.collect();
|
||||||
for (k, v) in snapshot.into_iter() {
|
for (k, v) in snapshot.into_iter() {
|
||||||
if let Some((_, newv)) = pin_renames.iter().find(|(oldv, _)| *oldv == v) {
|
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.
|
// 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(v, slot_name.clone());
|
||||||
self.pin_slot_names.insert(dst, 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)
|
Ok(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ impl AssignmentResolverBox {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if builder.variable_map.contains_key(var_name) {
|
if builder.variable_ctx.variable_map.contains_key(var_name) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,10 +51,10 @@ impl super::super::MirBuilder {
|
|||||||
for (name, previous) in frame.restore {
|
for (name, previous) in frame.restore {
|
||||||
match previous {
|
match previous {
|
||||||
Some(prev_id) => {
|
Some(prev_id) => {
|
||||||
self.variable_map.insert(name, prev_id);
|
self.variable_ctx.variable_map.insert(name, prev_id);
|
||||||
}
|
}
|
||||||
None => {
|
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()) {
|
if frame.declared.insert(name.to_string()) {
|
||||||
// Capture previous ValueId for restoration
|
// 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);
|
frame.restore.insert(name.to_string(), previous);
|
||||||
|
|
||||||
// Phase 74: Capture previous BindingId for parallel restoration
|
// Phase 74: Capture previous BindingId for parallel restoration
|
||||||
@ -97,7 +97,7 @@ impl super::super::MirBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update both ValueId and BindingId mappings
|
// 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
|
// Phase 74: Allocate and register new BindingId for this binding
|
||||||
let binding_id = self.allocate_binding_id();
|
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> {
|
fn classify_slots_from_variable_map(builder: &MirBuilder) -> Vec<SlotMetadata> {
|
||||||
let mut slots = Vec::new();
|
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());
|
let ref_kind = classify_slot(builder, vid, name.as_str());
|
||||||
slots.push(SlotMetadata {
|
slots.push(SlotMetadata {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user