From 1264b3593d2eada78d01d9d6f4bb0c1d207951fd Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Fri, 19 Dec 2025 00:15:51 +0900 Subject: [PATCH] fix(normalization): Tighten loop(true) gate to prevent loop(i --- .../control_flow/normalization/plan_box.rs | 71 +++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/mir/builder/control_flow/normalization/plan_box.rs b/src/mir/builder/control_flow/normalization/plan_box.rs index 1a24c91e..01ed19ac 100644 --- a/src/mir/builder/control_flow/normalization/plan_box.rs +++ b/src/mir/builder/control_flow/normalization/plan_box.rs @@ -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"); + } }