// git-issue-1665.dfy

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

  type {:axiom} nat(==,0) = 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> {
    const Length: int
  }
  /*-- non-null type
  type {:axiom} array(==)<arg> = c: array?<arg> | c != null /*special witness*/
  */

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

    ghost 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 {:compile false} /*_#Func0*/ () ~> +R {
    ghost function requires(): bool
      reads reads()

    ghost 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 /*_tuple#2*/ (+T0, +T1) = _#Make2(0: T0, 1: T1)

  type bool { }

  type char { }

  type int { }

  type real {
    const Floor: int
  }

  type ORDINAL {
    const IsLimit: bool
    const IsSucc: bool
    const Offset: int
    const IsNat: bool
  }

  type _bv {
    function RotateLeft(w: nat): selftype

    function RotateRight(w: nat): selftype
  }

  type set<+T> { }

  type iset<*T> { }

  type seq<+T> { }

  type multiset<+T> { }

  type map<+T, +U> {
    const Keys: set<T>
    const Values: set<U>
    const Items: set<(T, U)>
  }

  type imap<*T, +U> {
    const Keys: iset<T>
    const Values: iset<U>
    const Items: iset<(T, U)>
  }

  datatype /*_tuple#0*/ () = _#Make0
}
// bitvector types in use:
*/

/* CALL GRAPH for module _module:
 */

module ConcreteModule {
  /* CALL GRAPH for module ConcreteModule:
   * SCC at height 2:
   *   execute_external_method
   * SCC at height 1:
   *   Func1
   * SCC at height 1:
   *   Status.PropagateFailure
   * SCC at height 0:
   *   AdditionalWildcardTests
   * SCC at height 0:
   *   Status
   * SCC at height 0:
   *   Status.IsFailure
   */
  method execute_external_method(n: nat, m: nat) returns (r: Status)
    decreases n, m
  {
    
    /*---------- flattened ----------
    if n == 0 {
      :- Func1()
      /*---------- desugared ----------
      var valueOrError0: Status;
      valueOrError0 := Func1();
      if valueOrError0.IsFailure() {
        r := valueOrError0.PropagateFailure();
        return;
      }
      ---------- end desugared ----------*/;
      
      if m == 1 {
        :- Func1()
        /*---------- desugared ----------
        var valueOrError1: Status;
        valueOrError1 := Func1();
        if valueOrError1.IsFailure() {
          r := valueOrError1.PropagateFailure();
          return;
        }
        ---------- end desugared ----------*/;
      } else {
        return Success;
      }
      
    } else {
      return Success;
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} 0 =>
        :- Func1()
        /*---------- desugared ----------
        var valueOrError0: Status;
        valueOrError0 := Func1();
        if valueOrError0.IsFailure() {
          r := valueOrError0.PropagateFailure();
          return;
        }
        ---------- end desugared ----------*/;
        match m {
          case {:split false} 1 =>
            :- Func1()
            /*---------- desugared ----------
            var valueOrError1: Status;
            valueOrError1 := Func1();
            if valueOrError1.IsFailure() {
              r := valueOrError1.PropagateFailure();
              return;
            }
            ---------- end desugared ----------*/;
          case {:split false} _ /* _v0 */: int =>
            return Success;
        }
      case {:split false} _ /* _v1 */: int =>
        return Success;
    }
  }

  method Func1() returns (r: Status)
  {
    return Success;
  }

  method AdditionalWildcardTests(n: nat)
    decreases n
  {
    
    /*---------- flattened ----------
    {
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} _ /* _v2 */: int =>
    }
    
    /*---------- flattened ----------
    {
      var _ /* _v3 */: int := n;
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} _ /* _v3 */: int =>
    }
    
    /*---------- flattened ----------
    {
      var _ /* _v4 */: nat := n;
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} _ /* _v4 */: nat =>
    }
    
    /*---------- flattened ----------
    if n == 3 {
    } else {
      var _ /* _v5 */: int := n;
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} 3 =>
      case {:split false} _ /* _v5 */: int =>
    }
    
    /*---------- flattened ----------
    {
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} x: int =>
    }
    
    /*---------- flattened ----------
    {
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} n: int =>
    }
    
    /*---------- flattened ----------
    {
      var x: int := n;
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} x: int =>
    }
    
    /*---------- flattened ----------
    {
      var n: int := n;
    }
    ---------- end flattened ----------*/
    match n {
      case {:split false} n: int =>
    }
  }

  datatype Status = Success | Failure(error: nat) {
    predicate IsFailure()
      decreases this
    {
      this.Failure?
    }

    function PropagateFailure(): Status
      requires IsFailure()
      decreases this
    {
      Failure(this.error)
    }
  }
}
