Question:

How do I model extern methods that return objects?

Answer:

When modeling extern functions that return objects, it’s usually not good to have specifications that return objects. It’s better to have a predicate that takes the input of a function, an object, and relates the two to each other.

For example:

trait {:extern} {:compile false} Test {
  var i: int
  var y: int
}
trait {:extern} {:compile false} Importer {
  function Import(i: int): (r: Test)
    ensures r.i == i

  method {:extern} {:compile false} DoImport(i: int) returns (r: Test)
    ensures r == Import(i)

  predicate Conditions(i: int) {
     && var r := Import(i);
     && r.y == 2
  }
}

In this case, it’s better to write a predicate, and use existential quantifiers along with the :| operator, and there is no need to prove uniqueness because we are in ghost code!

trait {:extern} {:compile false} Test {
  var i: int
}
trait {:extern} {:compile false} Importer {
  predicate IsImported(i: int, r: Test) {
    r.i == i
  }
  method {:extern} {:compile false} DoImport(i: int) returns (r: Test)
    ensures IsImported(i, r)

  predicate Conditions(i: int) {
     && (exists r: Test :: IsImported(i, r))
     && var r :| IsImported(i, r);   // Note the assignment has changed.
     && r.y == 2
  }
}