// TypeConversionsCompile.dfy

/*
module _System {
  /* CALL GRAPH for module _System:
   * SCC at height 2:
   *   RotateRight
   * SCC at height 1:
   *   RotateLeft
   * SCC at height 0:
   *   nat
   */
  type string(==) = seq<char>

  type {:axiom} nat(==) = x: int
    | 0 <= x

  trait {:compile false} object { }
  /*-- non-null type
  type {:axiom} object(==) = c: object? | c != null    /*special witness*/
  */

  class {:compile false} array<arg> {
    var Length: int  // immutable
  }
  /*-- non-null type
  type {:axiom} array(==)<arg> = c: array?<arg> | c != null    /*special witness*/
  */

  class {:compile false} /*_#Func0*/ () ~> +R {
    function requires(): bool
      reads reads()

    function reads(): set<object?>
      reads reads()
  }

  type {:compile false} /*_#PartialFunc0*/ () --> +R = f: () ~> R
    | f.reads() == {}
    /*special witness*/

  type {:compile false} /*_#TotalFunc0*/ () -> +R = f: () --> R
    | f.requires()
    /*special witness*/

  datatype {:compile false} /*_tuple#2*/ (+T0, +T1) = _#Make2(0: T0, 1: T1)

  class {:compile false} /*_#Func1*/ -T0 ~> +R {
    function requires(x0: T0): bool
      reads reads(x0)

    function reads(x0: T0): set<object?>
      reads reads(x0)
  }

  type {:compile false} /*_#PartialFunc1*/ -T0 --> +R = f: T0 ~> R
    | forall x0: T0 :: f.reads(x0) == {}
    /*special witness*/

  type {:compile false} /*_#TotalFunc1*/ -T0 -> +R = f: T0 --> R
    | forall x0: T0 :: f.requires(x0)
    /*special witness*/

  type bool { }

  type int { }

  type real {
    var Floor: int  // immutable
  }

  type ORDINAL {
    var IsLimit: bool  // immutable
    var IsSucc: bool  // immutable
    var Offset: int  // immutable
    var IsNat: bool  // immutable
  }

  type bv {
    function method RotateLeft(w: nat): selftype

    function method RotateRight(w: nat): selftype
  }

  type map<T, U> {
    var Keys: set<T>  // immutable
    var Values: set<U>  // immutable
    var Items: set<(T, U)>  // immutable
  }

  type imap<T, U> {
    var Keys: iset<T>  // immutable
    var Values: iset<U>  // immutable
    var Items: iset<(T, U)>  // immutable
  }

  datatype /*_tuple#0*/ () = _#Make0
}
// bitvector types in use: bv67 bv32 bv7 bv0 bv300
*/

/* CALL GRAPH for module _module:
 * SCC at height 11:
 *   Main
 * SCC at height 10:
 *   OrdinalTests
 * SCC at height 9:
 *   array
 * SCC at height 8:
 *   int64
 * SCC at height 7:
 *   Abundance
 * SCC at height 6:
 *   Difficult
 * SCC at height 5:
 *   PrintExpected
 * SCC at height 4:
 *   Print
 * SCC at height 3:
 *   SmallReal
 * SCC at height 2:
 *   EvenInt
 * SCC at height 1:
 *   Handful
 * SCC at height 0:
 *   nat
 */
newtype Handful = x: int
  | 0 <= x < 32768

newtype Abundance = y: int
  | -20 <= y < 2199023255552

newtype int64 = y: int
  | -9223372036854775808 <= y < 9223372036854775808

newtype EvenInt = x: int
  | x % 2 == 0

newtype SmallReal = r: real
  | -4.0 <= r < 300.0

method Print(x: int, n: nat, r: real, handful: Handful, even: EvenInt, small: SmallReal, b67: bv67, w: bv32, seven: bv7, noll: bv0)
  decreases x, n, r, handful, even, small, b67, w, seven, noll
{
  print x, " ", n, " ", r, " ", handful, " ", even, " ", small, " ", b67, " ", w, " ", seven, " ", noll, "\n";
}

method PrintExpected<T>(got: T, expected: T)
{
  print "got ", got, ", expected ", expected, "\n";
}

method Main()
{
  var x: int, n: nat, r: real := 3, 4, 5.0;
  var handful: Handful, even: EvenInt, small: SmallReal := 5, 6, -1.0;
  var b67: bv67, w: bv32, seven: bv7, noll: bv0 := 147573952589676412927, 4294967295, 127, 0;
  Print(x, n, r, handful, even, small, b67, w, seven, noll);
  PrintExpected(x as bv7, 3);
  PrintExpected(0 as bv0, 0);
  PrintExpected(r as int, 5);
  PrintExpected((2.0 * r) as EvenInt, 10);
  PrintExpected(x as real, 3.0);
  PrintExpected(even as real, 6.0);
  PrintExpected((small + 3.0) as Handful, 2);
  PrintExpected(noll as Handful, 0);
  PrintExpected(noll as SmallReal, 0.0);
  PrintExpected(w as real, 4294967295.0);
  PrintExpected(seven as real, 127.0);
  PrintExpected(noll as bv32, 0);
  PrintExpected(noll as bv67, 0);
  PrintExpected(seven as bv32, 127);
  PrintExpected(seven as bv67, 127);
  b67 := 50;
  PrintExpected(r as bv67, 5);
  PrintExpected(r as bv32, 5);
  PrintExpected(w as bv67, 4294967295);
  PrintExpected(r as bv7, 5);
  PrintExpected(0.0 as bv0, 0);
  PrintExpected(handful as bv67, 5);
  PrintExpected(handful as bv32, 5);
  PrintExpected(handful as bv7, 5);
  PrintExpected(handful as int, 5);
  PrintExpected(noll as bv32 as bv0, 0);
  PrintExpected(noll as bv67 as bv0, 0);
  PrintExpected(seven as bv32 as bv7, 127);
  PrintExpected(seven as bv67 as bv7, 127);
  PrintExpected(handful as real, 5.0);
  Difficult();
  var a0: Abundance, a1: Abundance, a2: Abundance, lng: int64;
  var s: set<real> := {4.0, 6.3, r, 1000.2};
  var a: array<char> := new char[68];
  handful := 120 as Handful;
  a0, a1 := -1 as Abundance, 4 as Abundance;
  a2 := 8589934592 as Abundance;
  w, lng := 6345789 as bv32, -9223372036854775808 as int64;
  print handful, " ", a0, " ", a1, " ", a2, " ", w, " ", lng, "\n";
  x, handful, a0, w := |s|, |s| as Handful, |s| as Abundance, |s| as bv32;
  print x, " ", handful, " ", a0, " ", w, "\n";
  x, handful, a0, w := a.Length, a.Length as Handful, a.Length as Abundance, a.Length as bv32;
  print x, " ", handful, " ", a0, " ", w, "\n";
  OrdinalTests();
}

method Difficult()
{
  if 14 as real as int as bv67 == 14 {
    PrintExpected(14 as real as int as bv67 as EvenInt as SmallReal as Handful as bv7 as bv32 as int, 14);
  }
}

method OrdinalTests()
{
  var ord: ORDINAL := 143;
  var iord: int := ord as int;
  var oord: ORDINAL := iord as ORDINAL;
  print "Something about ORDINAL: ", ord, " ", iord, " ", oord, " ", ord + 4, " ", ord - 100, "\n";
  print "ORDINAL and bitvectors: ", 20 as bv32 as ORDINAL, " ", 20 as bv300 as ORDINAL, "\n";
  print ord.IsLimit, " ", ord.Offset, " ", ord.IsNat, "\n";
  ord := 0;
  print ord.IsLimit, " ", ord.Offset, " ", ord.IsNat, "\n";
}

Dafny program verifier finished with 8 verified, 0 errors
3 4 5.0 5 6 -1.0 147573952589676412927 4294967295 127 0
got 3, expected 3
got 0, expected 0
got 5, expected 5
got 10, expected 10
got 3.0, expected 3.0
got 6.0, expected 6.0
got 2, expected 2
got 0, expected 0
got 0.0, expected 0.0
got 4294967295.0, expected 4294967295.0
got 127.0, expected 127.0
got 0, expected 0
got 0, expected 0
got 127, expected 127
got 127, expected 127
got 5, expected 5
got 5, expected 5
got 4294967295, expected 4294967295
got 5, expected 5
got 0, expected 0
got 5, expected 5
got 5, expected 5
got 5, expected 5
got 5, expected 5
got 0, expected 0
got 0, expected 0
got 127, expected 127
got 127, expected 127
got 5.0, expected 5.0
got 14, expected 14
120 -1 4 8589934592 6345789 -9223372036854775808
4 4 4 4
68 68 68 68
Something about ORDINAL: 143 143 143 147 43
ORDINAL and bitvectors: 20 20
false 143 true
true 0 true
