import org.checkerframework.checker.signedness.qual.*;

public class CastedShifts {

  public void CastedIntShifts(@Unsigned int unsigned, @Signed int signed) {
    // Cast to byte.
    @UnknownSignedness byte byteRes;

    // Shifting right by 23, the introduced bits are cast away
    byteRes = (@Unsigned byte) (unsigned >>> 23);
    byteRes = (@Unsigned byte) (unsigned >> 23);
    byteRes = (@Signed byte) (signed >>> 23);
    byteRes = (@Signed byte) (signed >> 23);
    byteRes = (byte) (signed >> 23);

    // Shifting right by 24, the introduced bits are still cast away.
    byteRes = (@Unsigned byte) (unsigned >>> 24);
    byteRes = (@Unsigned byte) (unsigned >> 24);
    byteRes = (@Signed byte) (signed >>> 24);
    byteRes = (@Signed byte) (signed >> 24);

    // Shifting right by 25, now the MSB matters.
    byteRes = (@Unsigned byte) (unsigned >>> 25);

    // :: error: (shift.signed)
    byteRes = (@Unsigned byte) (unsigned >> 25);

    // :: error: (shift.unsigned)
    byteRes = (@Signed byte) (signed >>> 25);
    byteRes = (@Signed byte) (signed >> 25);

    // Shifting right by zero should behave as assignment
    byteRes = (@Unsigned byte) (unsigned >>> 0);
    byteRes = (@Unsigned byte) (unsigned >> 0);
    byteRes = (@Signed byte) (signed >>> 0);
    byteRes = (@Signed byte) (signed >> 0);

    // Cast to short.
    @UnknownSignedness short shortRes;

    // Shifting right by 15, the introduced bits are cast away
    shortRes = (@Unsigned short) (unsigned >>> 15);
    shortRes = (@Unsigned short) (unsigned >> 15);
    shortRes = (@Signed short) (signed >>> 15);
    shortRes = (@Signed short) (signed >> 15);

    // Shifting right by 16, the introduced bits are still cast away.
    shortRes = (@Unsigned short) (unsigned >>> 16);
    shortRes = (@Unsigned short) (unsigned >> 16);
    shortRes = (@Signed short) (signed >>> 16);
    shortRes = (@Signed short) (signed >> 16);

    // Shifting right by 17, now the MSB matters.
    shortRes = (@Unsigned short) (unsigned >>> 17);

    // :: error: (shift.signed)
    shortRes = (@Unsigned short) (unsigned >> 17);

    // :: error: (shift.unsigned)
    shortRes = (@Signed short) (signed >>> 17);
    shortRes = (@Signed short) (signed >> 17);

    // Shifting right by zero should behave as assignment
    shortRes = (@Unsigned short) (unsigned >>> 0);
    shortRes = (@Unsigned short) (unsigned >> 0);
    shortRes = (@Signed short) (signed >>> 0);
    shortRes = (@Signed short) (signed >> 0);

    // Cast to int.
    @UnknownSignedness int intRes;

    // Now shift signedness matters again
    intRes = (@Unsigned int) (unsigned >>> 1);

    // :: error: (shift.signed)
    intRes = (@Unsigned int) (unsigned >> 1);

    // :: error: (shift.unsigned)
    intRes = (@Signed int) (signed >>> 1);
    intRes = (@Signed int) (signed >> 1);

    // Shifting right by zero should behave as assignment
    intRes = (@Unsigned int) (unsigned >>> 0);
    intRes = (@Unsigned int) (unsigned >> 0);
    intRes = (@Signed int) (signed >>> 0);
    intRes = (@Signed int) (signed >> 0);

    // Cast to long.
    @UnknownSignedness long longRes;

    // Now shift signedness matters again
    longRes = (@Unsigned long) (unsigned >>> 1);

    // :: error: (shift.signed)
    longRes = (@Unsigned long) (unsigned >> 1);

    // :: error: (shift.unsigned)
    longRes = (@Signed long) (signed >>> 1);
    longRes = (@Signed long) (signed >> 1);

    // Shifting right by zero should behave as assignment
    longRes = (@Unsigned long) (unsigned >>> 0);
    longRes = (@Unsigned long) (unsigned >> 0);
    longRes = (@Signed long) (signed >>> 0);
    longRes = (@Signed long) (signed >> 0);

    // Tests with double parenthesis (only byte and int)

    // Cast to byte.
    // Shifting right by 23, the introduced bits are cast away
    byteRes = (@Unsigned byte) ((unsigned >>> 23));
    byteRes = (@Unsigned byte) ((unsigned >> 23));
    byteRes = (@Signed byte) ((signed >>> 23));
    byteRes = (@Signed byte) ((signed >> 23));

    // Shifting right by 24, the introduced bits are still cast away.
    byteRes = (@Unsigned byte) ((unsigned >>> 24));
    byteRes = (@Unsigned byte) ((unsigned >> 24));
    byteRes = (@Signed byte) ((signed >>> 24));
    byteRes = (@Signed byte) ((signed >> 24));

    // Shifting right by 25, now the MSB matters.
    byteRes = (@Unsigned byte) ((unsigned >>> 25));

    // :: error: (shift.signed)
    byteRes = (@Unsigned byte) ((unsigned >> 25));

    // :: error: (shift.unsigned)
    byteRes = (@Signed byte) ((signed >>> 25));
    byteRes = (@Signed byte) ((signed >> 25));

    // Shifting right by zero should behave as assignment
    byteRes = (@Unsigned byte) ((unsigned >>> 0));
    byteRes = (@Unsigned byte) ((unsigned >> 0));
    byteRes = (@Signed byte) ((signed >>> 0));
    byteRes = (@Signed byte) ((signed >> 0));

    // Cast to int.
    // Now shift signedness matters again
    intRes = (@Unsigned int) ((unsigned >>> 1));

    // :: error: (shift.signed)
    intRes = (@Unsigned int) ((unsigned >> 1));

    // :: error: (shift.unsigned)
    intRes = (@Signed int) ((signed >>> 1));
    intRes = (@Signed int) ((signed >> 1));

    // Shifting right by zero should behave as assignment
    intRes = (@Unsigned int) ((unsigned >>> 0));
    intRes = (@Unsigned int) ((unsigned >> 0));
    intRes = (@Signed int) ((signed >>> 0));
    intRes = (@Signed int) ((signed >> 0));

    // Test outside Java Specification shift ranges
    // Cast to int.
    // Now shift signedness matters again
    intRes = (@Unsigned int) ((unsigned >>> 33));

    // :: error: (shift.signed)
    intRes = (@Unsigned int) ((unsigned >> 33));

    // :: error: (shift.unsigned)
    intRes = (@Signed int) ((signed >>> 33));
    intRes = (@Signed int) ((signed >> 33));

    // Shifting right by zero should behave as assignment
    intRes = (@Unsigned int) ((unsigned >>> 32));
    intRes = (@Unsigned int) ((unsigned >> 32));
    intRes = (@Signed int) ((signed >>> 32));
    intRes = (@Signed int) ((signed >> 32));
  }

  public void CastedLongShifts(@Unsigned long unsigned, @Signed long signed) {
    // Cast to byte.
    @UnknownSignedness byte byteRes;

    // Shifting right by 55, the introduced bits are cast away
    byteRes = (@Unsigned byte) (unsigned >>> 55);
    byteRes = (@Unsigned byte) (unsigned >> 55);
    byteRes = (@Signed byte) (signed >>> 55);
    byteRes = (@Signed byte) (signed >> 55);

    // Shifting right by 56, the introduced bits are still cast away.
    byteRes = (@Unsigned byte) (unsigned >>> 56);
    byteRes = (@Unsigned byte) (unsigned >> 56);
    byteRes = (@Signed byte) (signed >>> 56);
    byteRes = (@Signed byte) (signed >> 56);

    // Shifting right by 57, now the MSB matters.
    byteRes = (@Unsigned byte) (unsigned >>> 57);

    // :: error: (shift.signed)
    byteRes = (@Unsigned byte) (unsigned >> 57);

    // :: error: (shift.unsigned)
    byteRes = (@Signed byte) (signed >>> 57);
    byteRes = (@Signed byte) (signed >> 57);

    // Shifting right by zero should behave as assignment
    byteRes = (@Unsigned byte) (unsigned >>> 0);
    byteRes = (@Unsigned byte) (unsigned >> 0);
    byteRes = (@Signed byte) (signed >>> 0);
    byteRes = (@Signed byte) (signed >> 0);

    // Cast to char.
    char charRes;

    // Shifting right by 55, the introduced bits are cast away
    charRes = (char) (unsigned >>> 55);
    charRes = (char) (unsigned >> 55);

    // Shifting right by 56, the introduced bits are still cast away.
    charRes = (char) (unsigned >>> 56);
    charRes = (char) (unsigned >> 56);

    // Shifting right by 57, now the MSB matters.
    charRes = (char) (unsigned >>> 57);

    // :: error: (shift.signed)
    charRes = (char) (unsigned >> 57);

    // Shifting right by zero should behave as assignment
    charRes = (char) (unsigned >>> 0);
    charRes = (char) (unsigned >> 0);

    // Cast to short.
    @UnknownSignedness short shortRes;

    // Shifting right by 47, the introduced bits are cast away
    shortRes = (@Unsigned short) (unsigned >>> 47);
    shortRes = (@Unsigned short) (unsigned >> 47);
    shortRes = (@Signed short) (signed >>> 47);
    shortRes = (@Signed short) (signed >> 47);

    // Shifting right by 48, the introduced bits are still cast away.
    shortRes = (@Unsigned short) (unsigned >>> 48);
    shortRes = (@Unsigned short) (unsigned >> 48);
    shortRes = (@Signed short) (signed >>> 48);
    shortRes = (@Signed short) (signed >> 48);

    // Shifting right by 49, now the MSB matters.
    shortRes = (@Unsigned short) (unsigned >>> 49);

    // :: error: (shift.signed)
    shortRes = (@Unsigned short) (unsigned >> 49);

    // :: error: (shift.unsigned)
    shortRes = (@Signed short) (signed >>> 49);
    shortRes = (@Signed short) (signed >> 49);

    // Shifting right by zero should behave as assignment
    shortRes = (@Unsigned short) (unsigned >>> 0);
    shortRes = (@Unsigned short) (unsigned >> 0);
    shortRes = (@Signed short) (signed >>> 0);
    shortRes = (@Signed short) (signed >> 0);

    // Cast to int.
    @UnknownSignedness int intRes;

    // Shifting right by 31, the introduced bits are cast away
    intRes = (@Unsigned int) (unsigned >>> 31);
    intRes = (@Unsigned int) (unsigned >> 31);
    intRes = (@Signed int) (signed >>> 31);
    intRes = (@Signed int) (signed >> 31);

    // Shifting right by 32, the introduced bits are still cast away.
    intRes = (@Unsigned int) (unsigned >>> 32);
    intRes = (@Unsigned int) (unsigned >> 32);
    intRes = (@Signed int) (signed >>> 32);
    intRes = (@Signed int) (signed >> 32);

    // Shifting right by 33, now the MSB matters.
    intRes = (@Unsigned int) (unsigned >>> 33);

    // :: error: (shift.signed)
    intRes = (@Unsigned int) (unsigned >> 33);

    // :: error: (shift.unsigned)
    intRes = (@Signed int) (signed >>> 33);
    intRes = (@Signed int) (signed >> 33);

    // Shifting right by zero should behave as assignment
    intRes = (@Unsigned int) (unsigned >>> 0);
    intRes = (@Unsigned int) (unsigned >> 0);
    intRes = (@Signed int) (signed >>> 0);
    intRes = (@Signed int) (signed >> 0);

    // Cast to long.
    @UnknownSignedness long longRes;

    // Now shift signedness matters again
    longRes = (@Unsigned long) (unsigned >>> 1);

    // :: error: (shift.signed)
    longRes = (@Unsigned long) (unsigned >> 1);

    // :: error: (shift.unsigned)
    longRes = (@Signed long) (signed >>> 1);
    longRes = (@Signed long) (signed >> 1);

    // Shifting right by zero should behave as assignment
    longRes = (@Unsigned long) (unsigned >>> 0);
    longRes = (@Unsigned long) (unsigned >> 0);
    longRes = (@Signed long) (signed >>> 0);
    longRes = (@Signed long) (signed >> 0);

    // Tests with double parenthesis (only byte and long)

    // Cast to byte.
    // Shifting right by 55, the introduced bits are cast away
    byteRes = (@Unsigned byte) ((unsigned >>> 55));
    byteRes = (@Unsigned byte) ((unsigned >> 55));
    byteRes = (@Signed byte) ((signed >>> 55));
    byteRes = (@Signed byte) ((signed >> 55));

    // Shifting right by 56, the introduced bits are still cast away.
    byteRes = (@Unsigned byte) ((unsigned >>> 56));
    byteRes = (@Unsigned byte) ((unsigned >> 56));
    byteRes = (@Signed byte) ((signed >>> 56));
    byteRes = (@Signed byte) ((signed >> 56));

    // Shifting right by 9, now the MSB matters.
    byteRes = (@Unsigned byte) ((unsigned >>> 57));

    // :: error: (shift.signed)
    byteRes = (@Unsigned byte) ((unsigned >> 57));

    // :: error: (shift.unsigned)
    byteRes = (@Signed byte) ((signed >>> 57));
    byteRes = (@Signed byte) ((signed >> 57));

    // Shifting right by zero should behave as assignment
    byteRes = (@Unsigned byte) ((unsigned >>> 0));
    byteRes = (@Unsigned byte) ((unsigned >> 0));
    byteRes = (@Signed byte) ((signed >>> 0));
    byteRes = (@Signed byte) ((signed >> 0));

    // Cast to long.
    // Now shift signedness matters again
    longRes = (@Unsigned long) ((unsigned >>> 1));

    // :: error: (shift.signed)
    longRes = (@Unsigned long) ((unsigned >> 1));

    // :: error: (shift.unsigned)
    longRes = (@Signed long) ((signed >>> 1));
    longRes = (@Signed long) ((signed >> 1));

    // Shifting right by zero should behave as assignment
    longRes = (@Unsigned long) ((unsigned >>> 0));
    longRes = (@Unsigned long) ((unsigned >> 0));
    longRes = (@Signed long) ((signed >>> 0));
    longRes = (@Signed long) ((signed >> 0));

    // Test outside Java Specification shift ranges
    // Cast to long.
    // Now shift signedness matters again
    longRes = (@Unsigned long) ((unsigned >>> 65));

    // :: error: (shift.signed)
    longRes = (@Unsigned long) ((unsigned >> 65));

    // :: error: (shift.unsigned)
    longRes = (@Signed long) ((signed >>> 65));
    longRes = (@Signed long) ((signed >> 65));

    // Shifting right by zero should behave as assignment
    longRes = (@Unsigned long) ((unsigned >>> 64));
    longRes = (@Unsigned long) ((unsigned >> 64));
    longRes = (@Signed long) ((signed >>> 64));
    longRes = (@Signed long) ((signed >> 64));
    longRes = (long) ((signed >> 64));
  }
}
