Class LowerBoundTransfer

  • All Implemented Interfaces:
    ForwardTransferFunction<CFValue,​CFStore>, TransferFunction<CFValue,​CFStore>, NodeVisitor<TransferResult<CFValue,​CFStore>,​TransferInput<CFValue,​CFStore>>

    public class LowerBoundTransfer
    extends IndexAbstractTransfer
    Implements dataflow refinement rules based on tests: <, >, ==, and their derivatives.

    Also implements the logic for binary operations: +, -, *, /, and %.

    >, <, ≥, ≤, ==, and != nodes are represented as combinations of > and ≥ (e.g. == is ≥ in both directions in the then branch), and implement refinements based on these decompositions.

     Refinement/transfer rules for conditionals:
    
     There are two "primitives":
    
     x > y, which implies things about x based on y's type:
    
     y has type:    implies x has type:
      gte-1                nn
      nn                   pos
      pos                  pos
    
     and x ≥ y:
    
     y has type:    implies x has type:
      gte-1                gte-1
      nn                   nn
      pos                  pos
    
     These two "building blocks" can be combined to make all
     other conditional expressions:
    
     EXPR             THEN          ELSE
     x > y            x > y         y ≥ x
     x ≥ y           x ≥ y        y > x
     x < y            y > x         x ≥ y
     x ≤ y           y ≥ x        x > y
    
     Or, more formally:
    
     EXPR        THEN                                        ELSE
     x > y       x_refined = GLB(x_orig, promote(y))         y_refined = GLB(y_orig, x)
     x ≥ y      x_refined = GLB(x_orig, y)                  y_refined = GLB(y_orig, promote(x))
     x < y       y_refined = GLB(y_orig, promote(x))         x_refined = GLB(x_orig, y)
     x ≤ y      y_refined = GLB(y_orig, x)                  x_refined = GLB(x_orig, promote(y))
    
     where GLB is the greatest lower bound and promote is the increment
     function on types (or, equivalently, the function specified by the "x
     > y" information above).
    
     There's also ==, which is a special case. Only the THEN
     branch is refined:
    
     EXPR             THEN                   ELSE
     x == y           x ≥ y && y ≥ x       nothing known
    
     or, more formally:
    
     EXPR            THEN                                    ELSE
     x == y          x_refined = GLB(x_orig, y_orig)         nothing known
                    y_refined = GLB(x_orig, y_orig)
    
     finally, not equal:
    
     EXPR             THEN                   ELSE
     x != y           nothing known          x ≥ y && y ≥ x
    
     more formally:
    
     EXPR            THEN               ELSE
     x != y          nothing known      x_refined = GLB(x_orig, y_orig)
                                       y_refined = GLB(x_orig, y_orig)
    
     
    Dividing these rules up by cases, this class implements:
    • 1. The rule described above for >
    • 2. The rule described above for ≥
    • 3. The rule described above for <
    • 4. The rule described above for ≤
    • 5. The rule described above for ==
    • 6. The rule described above for !=
    • 7. A special refinement for != when the value being compared to is a compile-time constant with a value exactly equal to -1 or 0 (i.e. x != -1 and x is GTEN1 implies x is non-negative). Maybe two rules?
    • 8. When a compile-time constant -2 is added to a positive, the result is GTEN1
    • 9. When a compile-time constant 2 is added to a GTEN1, the result is positive
    • 10. When a positive is added to a positive, the result is positive
    • 11. When a non-negative is added to any other type, the result is that other type
    • 12. When a GTEN1 is added to a positive, the result is non-negative
    • 13. When the left side of a subtraction expression is > the right side according to the LessThanChecker, the result of the subtraction expression is positive
    • 14. When the left side of a subtraction expression is ≥ the right side according to the LessThanChecker, the result of the subtraction expression is non-negative
    • 15. special handling for when the left side is the length of an array or String that's stored as a field, and the right side is a compile time constant. Do we need this?
    • 16. Multiplying any value by a compile time constant of 1 preserves its type
    • 17. Multiplying two positives produces a positive
    • 18. Multiplying a positive and a non-negative produces a non-negative
    • 19. Multiplying two non-negatives produces a non-negative
    • 20. When the result of Math.random is multiplied by an array length, the result is NonNegative.
    • 21. literal 0 divided by anything is non-negative
    • 22. anything divided by literal zero is bottom
    • 23. literal 1 divided by a positive or non-negative is non-negative
    • 24. literal 1 divided by anything else is GTEN1
    • 25. anything divided by literal 1 is itself
    • 26. a positive or non-negative divided by a positive or non-negative is non-negative
    • 27. anything modded by literal 1 or -1 is non-negative
    • 28. a positive or non-negative modded by anything is non-negative
    • 29. a GTEN1 modded by anything is GTEN1
    • 30. anything right-shifted by a non-negative is non-negative
    • 31. anything bitwise-anded by a non-negative is non-negative
    • 32. If a and b are non-negative and a <= b and a != b, then b is pos.
    • 33. A char is always non-negative