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 Err(_): Internal error (malformed AST)
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::ast::{ASTNode, LiteralValue};
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use super::plan::{NormalizationPlan, PlanKind};
|
||||
|
||||
@ -47,9 +47,26 @@ impl NormalizationPlanBox {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// First statement must be a loop
|
||||
let is_loop = matches!(&remaining[0], ASTNode::Loop { .. });
|
||||
if !is_loop {
|
||||
// First statement must be a loop with condition `true`
|
||||
// Phase 131-136 ONLY support loop(true), not loop(i < n) etc.
|
||||
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);
|
||||
}
|
||||
|
||||
@ -363,4 +380,50 @@ mod tests {
|
||||
assert_eq!(plan.consumed, 2); // loop + return
|
||||
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