import org.checkerframework.common.value.qual.*;

public class Refinement2 {

  void eq_test(int x, @IntVal({1, 5, 6}) int w) {
    if (x == 1) {
      // :: error: (assignment)
      @BottomVal int q = x;

    } else if (x == 2) {
    } else {
      return;
    }

    if (x != 1) {
      // :: error: (assignment)
      @IntVal({1}) int y = x;
      @IntVal({2}) int z = x;
    }

    if (x == 1) {

      @IntVal({1}) int y = x;

      // :: error: (assignment)
      @IntVal({2}) int z = x;
    } else {
      @IntVal({2}) int y = x;

      // :: error: (assignment)
      @IntVal({1}) int z = x;
    }

    if (x == w) {
      @IntVal({1}) int y = x;
      @IntVal({1}) int z = w;
    } else {
      // These two assignments are illegal because one of x or w could be 1,
      // while the other is not. So no refinement can be applied.

      // :: error: (assignment)
      @IntVal({2}) int y = x;
      // :: error: (assignment)
      @IntVal({5, 6}) int z = w;
    }
  }

  void testDeadCode(int x) {
    if (x == 4 || x == 5) {
      @IntVal({4, 5}) int a = x;
      // :: error: (assignment)
      @BottomVal int a2 = x;
    }
    if (x == 4 && x == 5) {
      // This is dead, so x should be bottom.
      @IntVal({4, 5}) int a = x;
      @BottomVal int a2 = x;
    }
    if (x != 1 || x != 2) {
      return;
    }
    if (x != 2) {
      @IntVal(1) int a = x;
    }

    if (x == 3) {
      // This is actually dead code, so x is treated as bottom.
      @IntVal(3) int y = x;
      @IntVal(33) int v = x;
      @BottomVal int z = x;
    }
  }

  void simpleNull(@IntVal({1, 2, 3}) Integer x) {
    if (x == null) {
      @BottomVal int y = x;
    }
  }

  void moreTests(@IntVal({1, 2, 3}) Integer x, Integer y) {
    if (x == null) {
      if (y == x) {
        // x and y should be @BottomVal
        @BottomVal int z1 = x;
        @BottomVal int z2 = y;
      } else {
        // y should be @UnknownVal here.
        // :: error: (assignment)
        @IntVal({1, 2, 3}) int z = y;
      }
    }

    if (x == null) {
      if (y < x) {
        // x should be @BottomVal
        @BottomVal int z1 = x;
        // This is dead code since the unboxing of x in the if statement
        // will throw a NPE, so the type of y doesn't matter.
        // @BottomVal int z2 = y;
      } else {
        // This is dead code, too.
      }
    }
  }

  void testArrayLen(boolean flag) {
    int[] a;
    if (flag) {
      a = new int[] {1};
    } else {
      a = new int[] {1, 2};
    }

    if (a.length != 1) {
      int @ArrayLen(2) [] b = a;
    }

    if (a.length == 3) {
      // Dead code
      int @ArrayLen(3) [] b = a;
      int @ArrayLen(5) [] c = a;
      int @BottomVal [] bot = a;
    }
  }
}
