@@ -599,6 +599,100 @@ void testNoSimplificationHasNoOrigin() {
599599 assertNull (result .getOrigin (), "No origin should be present when nothing was simplified" );
600600 }
601601
602+ @ Test
603+ void testVarToVarPropagationWithInternalVariable () {
604+ // Given: #x_0 == a && #x_0 > 5
605+ // Expected: a > 5 (internal #x_0 substituted with user-facing a)
606+
607+ Expression varX0 = new Var ("#x_0" );
608+ Expression varA = new Var ("a" );
609+ Expression x0EqualsA = new BinaryExpression (varX0 , "==" , varA );
610+ Expression x0Greater5 = new BinaryExpression (varX0 , ">" , new LiteralInt (5 ));
611+ Expression fullExpression = new BinaryExpression (x0EqualsA , "&&" , x0Greater5 );
612+
613+ // When
614+ ValDerivationNode result = ExpressionSimplifier .simplify (fullExpression );
615+
616+ // Then
617+ assertNotNull (result , "Result should not be null" );
618+ assertEquals ("a > 5" , result .getValue ().toString (),
619+ "Internal variable #x_0 should be substituted with user-facing variable a" );
620+ }
621+
622+ @ Test
623+ void testVarToVarInternalToInternal () {
624+ // Given: #a == #b && #b == 5 && x == #a + 1
625+ // Internal-to-internal var-to-var is resolved across fixed-point passes:
626+ // Pass 1: #b -> 5 => #a == 5 && x == #a + 1
627+ // Pass 2: #a -> 5 => x == 6
628+
629+ Expression varA = new Var ("#a" );
630+ Expression varB = new Var ("#b" );
631+ Expression varX = new Var ("x" );
632+ Expression five = new LiteralInt (5 );
633+ Expression aEqualsB = new BinaryExpression (varA , "==" , varB );
634+ Expression bEquals5 = new BinaryExpression (varB , "==" , five );
635+ Expression aPlus1 = new BinaryExpression (varA , "+" , new LiteralInt (1 ));
636+ Expression xEqualsAPlus1 = new BinaryExpression (varX , "==" , aPlus1 );
637+ Expression firstAnd = new BinaryExpression (aEqualsB , "&&" , bEquals5 );
638+ Expression fullExpression = new BinaryExpression (firstAnd , "&&" , xEqualsAPlus1 );
639+
640+ // When
641+ ValDerivationNode result = ExpressionSimplifier .simplify (fullExpression );
642+
643+ // Then
644+ assertNotNull (result , "Result should not be null" );
645+ assertEquals ("x == 6" , result .getValue ().toString (),
646+ "#a should resolve through #b to 5 across passes, then x == 5 + 1 = x == 6" );
647+ }
648+
649+ @ Test
650+ void testVarToVarDoesNotAffectUserFacingVariables () {
651+ // Given: x == y && x > 5
652+ // Expected: x == y && x > 5 (user-facing var-to-var should not be propagated)
653+
654+ Expression varX = new Var ("x" );
655+ Expression varY = new Var ("y" );
656+ Expression xEqualsY = new BinaryExpression (varX , "==" , varY );
657+ Expression xGreater5 = new BinaryExpression (varX , ">" , new LiteralInt (5 ));
658+ Expression fullExpression = new BinaryExpression (xEqualsY , "&&" , xGreater5 );
659+
660+ // When
661+ ValDerivationNode result = ExpressionSimplifier .simplify (fullExpression );
662+
663+ // Then
664+ assertNotNull (result , "Result should not be null" );
665+ assertEquals ("x == y && x > 5" , result .getValue ().toString (),
666+ "User-facing variable equalities should not trigger var-to-var propagation" );
667+ }
668+
669+ @ Test
670+ void testVarToVarRemovesRedundantEquality () {
671+ // Given: #ret_1 == #b_0 - 100 && #b_0 == b && b >= -128 && b <= 127
672+ // Expected: #ret_1 == b - 100 && b >= -128 && b <= 127 (#b_0 replaced with b, #b_0 == b removed)
673+
674+ Expression ret1 = new Var ("#ret_1" );
675+ Expression b0 = new Var ("#b_0" );
676+ Expression b = new Var ("b" );
677+ Expression ret1EqB0Minus100 = new BinaryExpression (ret1 , "==" ,
678+ new BinaryExpression (b0 , "-" , new LiteralInt (100 )));
679+ Expression b0EqB = new BinaryExpression (b0 , "==" , b );
680+ Expression bGeMinus128 = new BinaryExpression (b , ">=" , new UnaryExpression ("-" , new LiteralInt (128 )));
681+ Expression bLe127 = new BinaryExpression (b , "<=" , new LiteralInt (127 ));
682+ Expression and1 = new BinaryExpression (ret1EqB0Minus100 , "&&" , b0EqB );
683+ Expression and2 = new BinaryExpression (bGeMinus128 , "&&" , bLe127 );
684+ Expression fullExpression = new BinaryExpression (and1 , "&&" , and2 );
685+
686+ // When
687+ ValDerivationNode result = ExpressionSimplifier .simplify (fullExpression );
688+
689+ // Then
690+ assertNotNull (result , "Result should not be null" );
691+ assertEquals ("#ret_1 == b - 100 && b >= -128 && b <= 127" , result .getValue ().toString (),
692+ "Internal variable #b_0 should be replaced with b and redundant equality removed" );
693+ assertNotNull (result .getOrigin (), "Origin should be present showing the var-to-var derivation" );
694+ }
695+
602696 /**
603697 * Helper method to compare two derivation nodes recursively
604698 */
0 commit comments