// RUN: %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

function SimpleAssert(n: int): int
  ensures n < 100;
{
  assert n == 58;  // error: assert violation
  n  // but postcondition is fine
}

function SimpleAssume(n: int): int
  ensures n < 100;
{
  assume n == 58; n  // all is fine
}

function Subonacci(n: nat): nat
{
  if 2 <= n then
    // proving that this case is a nat requires more information,
    // which is here supplied by an assume expression
    assume Subonacci(n-2) <= Subonacci(n-1);
    Subonacci(n-1) - Subonacci(n-2)
  else
    n
}

function F(n: int): nat
{
  Subonacci(assume 0 <= n; n) -
  Subonacci(n)
}

function G(n: int, b: bool): nat
{
  if b then
    Subonacci(assume 0 <= n; n) + n  // the last n is also affected by the assume
  else
    Subonacci(n)  // error: n may not be a nat
}

ghost method M(m: nat, n: int)
{
  var k := F(m);
  assert k == 0;
  k := F(n);
  assert k == 0;  // this is still known
}

method M0(j: int) returns (n: nat)
{
  n := assert 0 <= j; j;  // error: j may be negative
}

method M1(j: int) returns (n: nat)
{
  n := (assume 0 <= j; j) + (assert 0 <= j; j);
  assert n == 2*j;
}

function SpecOnly(): bool { true }

function method FuncMeth(): int {
  assert SpecOnly();  // this call is allowed, because the .Guard of a
                      // PredicateExpr is not included in compilation
  15
}

method M5(a: int, b: int)
{
  var k := if a < 0 then
             assume b < 0; 5
           else
             5;
  if (*) {
    assert a == -7 ==> b < 0;
    assert b < 0;  // error: this condition does not hold on every path here
  } else {
    assert assume a == -7; b < 0;  // note, this is different than the ==> above
    assert b < 0;  // this condition does hold on all paths to here
  }
}
