feat(normalized): Phase 141 P1.5 - external env inputs + KnownIntrinsic SSOT
## Task B: External env input bug fix (Priority 1) Fix: Suffix normalization couldn't access prefix-built local variables **Problem**: `s.length()` failed because 's' (from prefix `s = "abc"`) was not in available_inputs during suffix normalization. **Root cause**: `AvailableInputsCollectorBox::collect()` only collected function params and CapturedEnv, missing `builder.variable_map`. **Solution**: Add `prefix_variables` parameter with 3-source merge: 1. Function params (highest priority) 2. Prefix variables (medium priority - NEW) 3. CapturedEnv (lowest priority) **Changed files**: - src/mir/control_tree/normalized_shadow/available_inputs_collector.rs - src/mir/builder/control_flow/normalization/execute_box.rs - src/mir/builder/control_flow/joinir/patterns/policies/normalized_shadow_suffix_router_box.rs - src/mir/builder/control_flow/joinir/routing.rs - src/mir/builder/stmts.rs - src/mir/control_tree/normalized_shadow/dev_pipeline.rs - docs/development/current/main/design/normalized-expr-lowering.md (Available Inputs SSOT section) **Tests**: 3 new unit tests (prefix merge, priority order) ## Task A: KnownIntrinsic SSOT化 (Priority 2) Eliminate string literal scattered matching by centralizing to registry. **Problem**: Adding new intrinsics required editing if/match chains with hard-coded string literals (`if method == KnownIntrinsic::Length0.method_name()`). **Solution**: Create `KnownIntrinsicRegistryBox` as SSOT: - `lookup(method, arity) -> Option<KnownIntrinsic>` - `get_spec(intrinsic) -> KnownIntrinsicSpec` - Adding new intrinsics now requires: (1) enum variant, (2) registry entry only **Changed files**: - src/mir/control_tree/normalized_shadow/common/known_intrinsics.rs (NEW) - src/mir/control_tree/normalized_shadow/common/expr_lowerer_box.rs - src/mir/control_tree/normalized_shadow/common/expr_lowering_contract.rs (deprecated methods removed) - src/mir/control_tree/normalized_shadow/common/mod.rs - docs/development/current/main/design/normalized-expr-lowering.md (Known Intrinsic SSOT section) **Impact**: ~30% code reduction in intrinsic matching logic ## Task C: Better diagnostics (Priority 3) Add `OutOfScopeReason::IntrinsicNotWhitelisted` for precise diagnostics. **Changed files**: - src/mir/control_tree/normalized_shadow/common/expr_lowering_contract.rs (enum variant) - src/mir/control_tree/normalized_shadow/common/expr_lowerer_box.rs (diagnostic logic) ## Verification ✅ Build: `cargo build --release` - PASS ✅ Phase 97 regression: next_non_ws LLVM EXE - PASS ✅ Phase 131: loop(true) break-once VM - PASS ✅ Phase 136: return literal VM - PASS ✅ Phase 137: return x+2 VM - PASS 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -16,6 +16,7 @@ use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::ValueId;
|
||||
use super::plan::{NormalizationPlan, PlanKind};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Box-First: Execute normalization plan
|
||||
pub struct NormalizationExecuteBox;
|
||||
@ -23,6 +24,8 @@ pub struct NormalizationExecuteBox;
|
||||
impl NormalizationExecuteBox {
|
||||
/// Execute a normalization plan
|
||||
///
|
||||
/// ## Phase 141 P1.5: Added prefix_variables parameter
|
||||
///
|
||||
/// Returns:
|
||||
/// - Ok(value_id): Successfully executed, returns result value
|
||||
/// - Err(_): Lowering or merge failed
|
||||
@ -32,6 +35,7 @@ impl NormalizationExecuteBox {
|
||||
remaining: &[ASTNode],
|
||||
func_name: &str,
|
||||
debug: bool,
|
||||
prefix_variables: Option<&BTreeMap<String, ValueId>>,
|
||||
) -> Result<ValueId, String> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
|
||||
@ -57,20 +61,23 @@ impl NormalizationExecuteBox {
|
||||
|
||||
match &plan.kind {
|
||||
PlanKind::LoopOnly => {
|
||||
Self::execute_loop_only(builder, remaining, func_name, debug)
|
||||
Self::execute_loop_only(builder, remaining, func_name, debug, prefix_variables)
|
||||
}
|
||||
PlanKind::LoopWithPost { .. } => {
|
||||
Self::execute_loop_with_post(builder, plan, remaining, func_name, debug)
|
||||
Self::execute_loop_with_post(builder, plan, remaining, func_name, debug, prefix_variables)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute Phase 131: Loop-only pattern
|
||||
///
|
||||
/// ## Phase 141 P1.5: Added prefix_variables parameter
|
||||
fn execute_loop_only(
|
||||
builder: &mut MirBuilder,
|
||||
remaining: &[ASTNode],
|
||||
func_name: &str,
|
||||
debug: bool,
|
||||
prefix_variables: Option<&BTreeMap<String, ValueId>>,
|
||||
) -> Result<ValueId, String> {
|
||||
use crate::ast::Span;
|
||||
use crate::mir::control_tree::normalized_shadow::available_inputs_collector::AvailableInputsCollectorBox;
|
||||
@ -92,8 +99,8 @@ impl NormalizationExecuteBox {
|
||||
|
||||
let tree = StepTreeBuilderBox::build_from_ast(&loop_ast);
|
||||
|
||||
// Collect available inputs
|
||||
let available_inputs = AvailableInputsCollectorBox::collect(builder, None);
|
||||
// Collect available inputs (Phase 141 P1.5: with prefix variables)
|
||||
let available_inputs = AvailableInputsCollectorBox::collect(builder, None, prefix_variables);
|
||||
|
||||
if debug {
|
||||
trace.routing(
|
||||
@ -141,12 +148,15 @@ impl NormalizationExecuteBox {
|
||||
}
|
||||
|
||||
/// Execute Phase 132-133: Loop + post assignments + return
|
||||
///
|
||||
/// ## Phase 141 P1.5: Added prefix_variables parameter
|
||||
fn execute_loop_with_post(
|
||||
builder: &mut MirBuilder,
|
||||
plan: &NormalizationPlan,
|
||||
remaining: &[ASTNode],
|
||||
func_name: &str,
|
||||
debug: bool,
|
||||
prefix_variables: Option<&BTreeMap<String, ValueId>>,
|
||||
) -> Result<ValueId, String> {
|
||||
use crate::mir::control_tree::normalized_shadow::available_inputs_collector::AvailableInputsCollectorBox;
|
||||
use crate::mir::control_tree::normalized_shadow::StepTreeNormalizedShadowLowererBox;
|
||||
@ -158,8 +168,8 @@ impl NormalizationExecuteBox {
|
||||
let suffix = &remaining[..plan.consumed];
|
||||
let step_tree = StepTreeBuilderBox::build_from_block(suffix);
|
||||
|
||||
// Collect available inputs
|
||||
let available_inputs = AvailableInputsCollectorBox::collect(builder, None);
|
||||
// Collect available inputs (Phase 141 P1.5: with prefix variables)
|
||||
let available_inputs = AvailableInputsCollectorBox::collect(builder, None, prefix_variables);
|
||||
|
||||
if debug {
|
||||
trace.routing(
|
||||
|
||||
Reference in New Issue
Block a user