fix(normalization): Tighten loop(true) gate to prevent loop(i<n) mismatch
Problem: - Phase 97 LLVM EXE tests (next_non_ws, json_loader_escape) were failing - NormalizationPlan accepted loop(i < n) but couldn't lower it - Execute stage returned hard error instead of fallback Root Cause: - Plan stage only checked `ASTNode::Loop`, not condition - loop(i < n) got Plan → Execute tried to normalize → error - Should: loop(i < n) returns Ok(None) → fallback to Pattern2 Fix: - Tighten gate in plan_box.rs (lines 50-71) - Only accept loop(true) - literal Bool true - loop(i < n) now returns Ok(None) → clean fallback Added: - Test: test_plan_block_suffix_no_match_loop_not_true() - Verifies loop(i < n) returns None (not Plan) Verification: - Phase 97 next_non_ws LLVM EXE: PASS - Phase 97 json_loader_escape LLVM EXE: PASS - Phase 131/135/136/137 regression: all 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:
@ -12,7 +12,7 @@
|
|||||||
//! - Returns Ok(None): Not a normalized pattern, use legacy fallback
|
//! - Returns Ok(None): Not a normalized pattern, use legacy fallback
|
||||||
//! - Returns Err(_): Internal error (malformed AST)
|
//! - Returns Err(_): Internal error (malformed AST)
|
||||||
|
|
||||||
use crate::ast::ASTNode;
|
use crate::ast::{ASTNode, LiteralValue};
|
||||||
use crate::mir::builder::MirBuilder;
|
use crate::mir::builder::MirBuilder;
|
||||||
use super::plan::{NormalizationPlan, PlanKind};
|
use super::plan::{NormalizationPlan, PlanKind};
|
||||||
|
|
||||||
@ -47,9 +47,26 @@ impl NormalizationPlanBox {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// First statement must be a loop
|
// First statement must be a loop with condition `true`
|
||||||
let is_loop = matches!(&remaining[0], ASTNode::Loop { .. });
|
// Phase 131-136 ONLY support loop(true), not loop(i < n) etc.
|
||||||
if !is_loop {
|
let is_loop_true = match &remaining[0] {
|
||||||
|
ASTNode::Loop { condition, .. } => {
|
||||||
|
// Only accept loop(true) - literal Bool true
|
||||||
|
matches!(
|
||||||
|
condition.as_ref(),
|
||||||
|
ASTNode::Literal { value: LiteralValue::Bool(true), .. }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if !is_loop_true {
|
||||||
|
if debug {
|
||||||
|
trace.routing(
|
||||||
|
"normalization/plan",
|
||||||
|
func_name,
|
||||||
|
"First statement is not loop(true), returning None (not a normalized pattern)",
|
||||||
|
);
|
||||||
|
}
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,4 +380,50 @@ mod tests {
|
|||||||
assert_eq!(plan.consumed, 2); // loop + return
|
assert_eq!(plan.consumed, 2); // loop + return
|
||||||
assert_eq!(plan.kind, PlanKind::LoopWithPost { post_assign_count: 0 });
|
assert_eq!(plan.kind, PlanKind::LoopWithPost { post_assign_count: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_plan_block_suffix_no_match_loop_not_true() {
|
||||||
|
use crate::mir::builder::MirBuilder;
|
||||||
|
|
||||||
|
// Phase 97 regression test: loop(i < n) should NOT match
|
||||||
|
// Normalized shadow only supports loop(true)
|
||||||
|
let loop_conditional = ASTNode::Loop {
|
||||||
|
condition: Box::new(ASTNode::BinaryOp {
|
||||||
|
left: Box::new(ASTNode::Variable {
|
||||||
|
name: "i".to_string(),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
operator: BinaryOperator::Less,
|
||||||
|
right: Box::new(ASTNode::Variable {
|
||||||
|
name: "n".to_string(),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
body: vec![
|
||||||
|
ASTNode::Assignment {
|
||||||
|
target: Box::new(ASTNode::Variable {
|
||||||
|
name: "x".to_string(),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
value: Box::new(ASTNode::Literal {
|
||||||
|
value: LiteralValue::Integer(1),
|
||||||
|
span: make_span(),
|
||||||
|
}),
|
||||||
|
span: make_span(),
|
||||||
|
},
|
||||||
|
ASTNode::Break { span: make_span() },
|
||||||
|
],
|
||||||
|
span: make_span(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let remaining = vec![loop_conditional, make_return("x")];
|
||||||
|
|
||||||
|
let builder = MirBuilder::new();
|
||||||
|
let plan = NormalizationPlanBox::plan_block_suffix(&builder, &remaining, "test", false)
|
||||||
|
.expect("Should not error");
|
||||||
|
|
||||||
|
// loop(i < n) is NOT supported by Normalized - should return None
|
||||||
|
assert!(plan.is_none(), "loop(i < n) should NOT match Normalized pattern");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user