# ProofDependencies.dfy, Combined Coverage Report

    // RUN: %diff "%s" "%s"

    module M {
    method {:testEntry} RedundantAssumeMethod(n: int)
    {
        // either one or the other assumption shouldn't be covered
        assume n > 4;
        assume n > 3;
        assert n > 1;
    }

    method {:testEntry} ContradictoryAssumeMethod(n: int)
    {
        assume n > 0;
        assume n < 0;
        assume n == 5; // shouldn't be covered
        assert n < 10; // shouldn't be covered
    }

    method {:testEntry} AssumeFalseMethod(n: int)
    {
        assume n == 15; // shouldn't be covered
        assume false;
        assert n < 10; // shouldn't be covered
    }

    // Obvious contradiction in requires clauses.
    function {:testEntry} ObviouslyContradictoryRequiresFunc(x: nat): (r: nat)
      requires x > 10
      requires x < 10
      ensures r < x // only provable vacuously
    {
      assert x == 10; // contradicts both requires clauses
      x - 1 // not necessarily a valid nat
    }

    method {:testEntry} ObviouslyContradictoryRequiresMethod(x: nat) returns (r: nat)
      requires x > 10
      requires x < 10
      ensures r < x // only provable vacuously
    {
      assert x == 10; // contradicts both requires clauses
      return x - 1; // not necessarily a valid nat
    }

    // Obvious redundancy in requires clauses.
    function {:testEntry} ObviouslyRedundantRequiresFunc(x: nat): (r: nat)
      requires x < 10
      requires x < 100 // implied by previous requires clause
      ensures r < 11 // should cause body and first requires clause to be covered
    {
      x + 1
    }

    method {:testEntry} ObviouslyRedundantRequiresMethod(x: nat) returns (r: nat)
      requires x < 10
      requires x < 100 // implied by previous requires clause
      ensures r < 11 // should cause body and first requires clause to be covered
    {
      return x + 1;
    }

    // Obviously unnecessary requires clauses.
    function {:testEntry} ObviouslyUnnecessaryRequiresFunc(x: nat): (r: nat)
      requires x < 10 // not required for the proof
    {
      // cause at least a little proof work to be necessary, for nat bounds
      if (x > 5) then x + 2 else x + 1
    }

    method {:testEntry} ObviouslyUnnecessaryRequiresMethod(x: nat) returns (r: nat)
      requires x < 10 // not required for the proof
    {
      // cause at least a little proof work to be necessary, for nat bounds
      if (x > 5) { return x + 2; } else { return x + 1; }
    }

    // Code obviously not constrained by ensures clause.
    function {:testEntry} ObviouslyUnconstrainedCodeFunc(x: int): (r: (int, int))
      requires x > 10
      ensures r.0 > 10
    {
      var a := x + 1; // constrained by ensures clause
      var b := x - 1; // not constrained by ensures clause
      (a,
       b)
    }

    method {:testEntry} ObviouslyUnconstrainedCodeMethod(x: int) returns (r: (int, int))
      requires x > 10
      ensures r.0 > 10
    {
      var a := x + 1; // constrained by ensures clause
      var b := x - 1; // not constrained by ensures clause
      return
        (a,
         b);
    }

    // Partial redundancy in requires clauses.
    function {:testEntry} PartiallyRedundantRequiresFunc(x: nat): (r: nat)
      requires x < 100 && x < 10 // LHS implied by RHS
      ensures r < 11 // should cause body and RHS clause to be covered
    {
      x + 1
    }

    // Partly unnecessary requires clause.
    function {:testEntry} PartiallyUnnecessaryRequiresFunc(x: int): (r: nat)
      requires x < 10 && x > 0 // RHS required for proof, but not LHS
    {
      // cause at least a little proof work to be necessary, for nat bounds
      if (x > 5) then x - 1 else x + 1
    }

    // Redundancy of one requires clause due to at least two others, with at least
    // one of the three being partly in a separately-defined function.
    function {:testEntry} MultiPartRedundantRequiresFunc(x: int): (r: int)
      requires x > 10
      requires x < 12
      requires x == 11 // implied by the previous two, but neither individually
      ensures r == 11
    {
      x
    }

    method {:testEntry} MultiPartRedundantRequiresMethod(x: int) returns (r: int)
      requires x > 10
      requires x < 12
      requires x == 11 // implied by the previous two, but neither individually
      ensures r == 11
    {
      return x;
    }

    // Contradiction between three different requires clauses, with at least one of
    // the three being partly in a separately-defined function (function and
    // method).
    function {:testEntry} MultiPartContradictoryRequiresFunc(x: int, y: int): (r: int)
      requires x > 10
      requires x < 12
      requires y != 11 // contradicts the previous two
      ensures r == 11 // provable from first two preconditions, but shouldn't be covered
    {
      x
    }

    method {:testEntry} MultiPartContradictoryRequiresMethod(x: int, y: int) returns (r: int)
      requires x > 10
      requires x < 12
      requires y != 11 // contradicts the previous two
      ensures r == 11 // provable from first two preconditions, but shouldn't be covered
    {
      return x;
    }

    function {:testEntry} ContradictoryEnsuresClauseFunc(x: int): (r: int)
      requires x > 1
      ensures  r > x && r < 0

    method {:testEntry} ContradictoryEnsuresClauseMethod(x: int) returns (r: int)
      requires x > 1
      ensures  r > x && r < 0

    // Call function that has contradictory ensures clauses.
    function {:testEntry} CallContradictoryFunctionFunc(x: int): (r: int)
      requires x > 1
      ensures r < 0
    {
      // TODO: Dafny doesn't generate sufficient Boogie code to make the contradiction detectable
      ContradictoryEnsuresClauseFunc(x) - 1
    }

    method {:testEntry} CallContradictoryMethodMethod(x: int) returns (r: int)
      requires x > 1
      ensures r < 0
    {
      var y := ContradictoryEnsuresClauseMethod(x);
      return y - 1;
    }

    // False antecedent requires clause
    method {:testEntry} FalseAntecedentRequiresClauseMethod(x: int) returns (r: int)
      requires x*x < 0 ==> x == x + 1
      ensures r > x
    {
      return x + 1;
    }

    // False antecedent assert statement.
    method {:testEntry} FalseAntecedentAssertStatementMethod(x: int) {
      var y := x*x;
      assert y < 0 ==> x < 0;
    }

    // False antecedent ensures clause.
    method {:testEntry} FalseAntecedentEnsuresClauseMethod(x: int) returns (r: int)
      ensures r < 0 ==> x < 0
    {
      return x*x;
    }

    function {:testEntry} ObviouslyUnreachableIfExpressionBranchFunc(x: int): (r:int)
      requires x > 0
      ensures r > 0
    {
      if x < 0
      then x - 1 // unreachable
      else x + 1
    }

    method {:testEntry} ObviouslyUnreachableIfStatementBranchMethod(x: int) returns (r:int)
      requires x > 0
      ensures r > 0
    {
      if x < 0 {
        return x - 1; // unreachable
      } else {
        return x + 1;
      }
    }

    datatype T = A | B

    function {:testEntry} ObviouslyUnreachableMatchExpressionCaseFunction(t: T): (r:int)
      requires t != A
      ensures r > 1 // alt: r > 0
    {
      match t {
        case A => 1 // unreachable
        case B => 2
      }
    }

    method {:testEntry} ObviouslyUnreachableMatchStatementCaseMethod(t: T) returns (r:int)
      requires t != A
      ensures r > 1 // alt: r > 0
    {
      match t {
        case A => return 1; // unreachable
        case B => return 2;
      }
    }

    method {:testEntry} ObviouslyUnreachableReturnStatementMethod(t: T) returns (r:int)
      requires t != A
        ensures r > 1 // alt: r > 0
      {
        if !t.A? {
          return 2;
        }

        return 1; // unreachable
      }

    method {:testEntry} CalcStatementWithSideConditions(x: int) {
      calc == {
        x / 2;
        (x*2) / 4;
      }
    }

    method {:testEntry} DontWarnAboutVacuousAssertFalse(x: int) {
      assume x == x + 1;
      assert false;
    }

    class C {
      var x: int
      constructor() {}
    }

    function {:testEntry} GetX(c: C): int
      reads c
    {
      c.x
    }

    method {:testEntry} DontWarnAboutUnusedAssumeTrue(x: int) {
      assume true;
      assert 1 + x == x + 1;
    }

    }