feat(control_tree): Phase 126 AvailableInputsCollectorBox
- Collect available_inputs from function params + CapturedEnv (SSOT) - BTreeMap for deterministic order - Box-first modularization with unit tests (5 tests PASS) - Source priority: params > CapturedEnv - No AST inference (only pre-computed sources)
This commit is contained in:
@ -0,0 +1,142 @@
|
|||||||
|
//! Phase 126: available_inputs collector (SSOT)
|
||||||
|
//!
|
||||||
|
//! ## Responsibility
|
||||||
|
//!
|
||||||
|
//! - Collect available_inputs from function params + CapturedEnv
|
||||||
|
//! - Returns BTreeMap<String, ValueId> with deterministic order
|
||||||
|
//! - No AST inference (SSOT sources only)
|
||||||
|
//!
|
||||||
|
//! ## Design
|
||||||
|
//!
|
||||||
|
//! - Input sources (priority order):
|
||||||
|
//! 1. Function params (from ScopeContext + VariableContext)
|
||||||
|
//! 2. CapturedEnv (pinned/captured variables from outer scope)
|
||||||
|
//! - Forbidden: AST-based capture inference (Phase 100 CapturedEnv is SSOT)
|
||||||
|
|
||||||
|
// Phase 126: Import contexts from MirBuilder (pub(in crate::mir) visibility)
|
||||||
|
// Since we're in crate::mir::control_tree::normalized_shadow, we can access these
|
||||||
|
use crate::mir::builder::MirBuilder;
|
||||||
|
use crate::mir::loop_pattern_detection::function_scope_capture::CapturedEnv;
|
||||||
|
use crate::mir::ValueId;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
/// Phase 126: Box-First available_inputs collector
|
||||||
|
pub struct AvailableInputsCollectorBox;
|
||||||
|
|
||||||
|
impl AvailableInputsCollectorBox {
|
||||||
|
/// Collect available_inputs from SSOT sources (via MirBuilder)
|
||||||
|
///
|
||||||
|
/// ## Contract
|
||||||
|
///
|
||||||
|
/// - Sources (priority order):
|
||||||
|
/// 1. Function params: builder.scope_ctx.function_param_names + builder.variable_ctx.variable_map
|
||||||
|
/// 2. CapturedEnv: captured_env.vars (pinned/captured from outer scope)
|
||||||
|
/// - Output: BTreeMap<String, ValueId> (deterministic order)
|
||||||
|
/// - No AST inference: only use pre-computed SSOT sources
|
||||||
|
///
|
||||||
|
/// ## Implementation
|
||||||
|
///
|
||||||
|
/// - Collect function params first (higher priority)
|
||||||
|
/// - Collect CapturedEnv vars (lower priority, don't override params)
|
||||||
|
/// - Use BTreeMap for deterministic iteration
|
||||||
|
pub fn collect(
|
||||||
|
builder: &MirBuilder,
|
||||||
|
captured_env: Option<&CapturedEnv>,
|
||||||
|
) -> BTreeMap<String, ValueId> {
|
||||||
|
let mut available_inputs = BTreeMap::new();
|
||||||
|
|
||||||
|
// 1. Function params (SSOT: scope_ctx + variable_ctx)
|
||||||
|
for param_name in &builder.scope_ctx.function_param_names {
|
||||||
|
if let Some(value_id) = builder.variable_ctx.lookup(param_name) {
|
||||||
|
available_inputs.insert(param_name.clone(), value_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. CapturedEnv (SSOT: pinned/captured vars)
|
||||||
|
if let Some(env) = captured_env {
|
||||||
|
for var in &env.vars {
|
||||||
|
// Don't override function params (params have higher priority)
|
||||||
|
if !available_inputs.contains_key(&var.name) {
|
||||||
|
available_inputs.insert(var.name.clone(), var.host_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
available_inputs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::mir::loop_pattern_detection::function_scope_capture::CapturedVar;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_empty() {
|
||||||
|
let builder = MirBuilder::new();
|
||||||
|
let result = AvailableInputsCollectorBox::collect(&builder, None);
|
||||||
|
assert_eq!(result.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_function_params() {
|
||||||
|
let mut builder = MirBuilder::new();
|
||||||
|
|
||||||
|
// Simulate function param: x -> ValueId(1)
|
||||||
|
builder.scope_ctx.function_param_names.insert("x".to_string());
|
||||||
|
builder.variable_ctx.insert("x".to_string(), ValueId(1));
|
||||||
|
|
||||||
|
let result = AvailableInputsCollectorBox::collect(&builder, None);
|
||||||
|
assert_eq!(result.len(), 1);
|
||||||
|
assert_eq!(result.get("x"), Some(&ValueId(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_captured_env() {
|
||||||
|
let builder = MirBuilder::new();
|
||||||
|
|
||||||
|
let mut captured = CapturedEnv::new();
|
||||||
|
captured.insert("outer_x".to_string(), ValueId(42));
|
||||||
|
|
||||||
|
let result = AvailableInputsCollectorBox::collect(&builder, Some(&captured));
|
||||||
|
assert_eq!(result.len(), 1);
|
||||||
|
assert_eq!(result.get("outer_x"), Some(&ValueId(42)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_params_override_captured() {
|
||||||
|
let mut builder = MirBuilder::new();
|
||||||
|
|
||||||
|
// Function param: x -> ValueId(1)
|
||||||
|
builder.scope_ctx.function_param_names.insert("x".to_string());
|
||||||
|
builder.variable_ctx.insert("x".to_string(), ValueId(1));
|
||||||
|
|
||||||
|
// Captured: x -> ValueId(42) (should be ignored)
|
||||||
|
let mut captured = CapturedEnv::new();
|
||||||
|
captured.insert("x".to_string(), ValueId(42));
|
||||||
|
|
||||||
|
let result = AvailableInputsCollectorBox::collect(&builder, Some(&captured));
|
||||||
|
assert_eq!(result.len(), 1);
|
||||||
|
// Function param (ValueId(1)) should win over captured (ValueId(42))
|
||||||
|
assert_eq!(result.get("x"), Some(&ValueId(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collect_deterministic_order() {
|
||||||
|
let mut builder = MirBuilder::new();
|
||||||
|
|
||||||
|
// Add params in non-alphabetical order
|
||||||
|
builder.scope_ctx.function_param_names.insert("z".to_string());
|
||||||
|
builder.scope_ctx.function_param_names.insert("a".to_string());
|
||||||
|
builder.scope_ctx.function_param_names.insert("m".to_string());
|
||||||
|
builder.variable_ctx.insert("z".to_string(), ValueId(3));
|
||||||
|
builder.variable_ctx.insert("a".to_string(), ValueId(1));
|
||||||
|
builder.variable_ctx.insert("m".to_string(), ValueId(2));
|
||||||
|
|
||||||
|
let result = AvailableInputsCollectorBox::collect(&builder, None);
|
||||||
|
let keys: Vec<_> = result.keys().collect();
|
||||||
|
|
||||||
|
// BTreeMap ensures alphabetical order
|
||||||
|
assert_eq!(keys, vec![&"a".to_string(), &"m".to_string(), &"z".to_string()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -32,6 +32,7 @@
|
|||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod contracts;
|
pub mod contracts;
|
||||||
pub mod parity;
|
pub mod parity;
|
||||||
|
pub mod available_inputs_collector; // Phase 126: available_inputs SSOT
|
||||||
|
|
||||||
pub use builder::StepTreeNormalizedShadowLowererBox;
|
pub use builder::StepTreeNormalizedShadowLowererBox;
|
||||||
pub use contracts::{CapabilityCheckResult, UnsupportedCapability};
|
pub use contracts::{CapabilityCheckResult, UnsupportedCapability};
|
||||||
|
|||||||
Reference in New Issue
Block a user