epfl-lara / stainless

Verification framework and tool for higher-order Scala programs
https://epfl-lara.github.io/stainless/
Apache License 2.0
349 stars 50 forks source link

`unfolding` should return the return value of the function so that it is a hint for verification, and has the behaviour of the unfolded function at runtime #1550

Open samuelchassot opened 1 month ago

samuelchassot commented 1 month ago

And maybe can be inline def

samuelchassot commented 4 weeks ago

Summary

samuelchassot commented 4 weeks ago

Also, the potential side effects of the unfolded function are visible: Example:

  case class C(var x: BigInt):
    def update(v: BigInt): BigInt = {
      x += v
      x
    }

  def t(): BigInt = {
    val c = C(0)
    unfold(c.update(1))
    assert(c.x == 1)
    42
  }

gives this tree:

[ Debug  ] Symbols after UnfoldOpaque
[ Debug  ] 
[ Debug  ] -------------Functions-------------
[ Debug  ] def update(thiss: C, v: BigInt): (BigInt, C) = {
[ Debug  ]   val thiss: C = thiss
[ Debug  ]   val thiss: C = C(thiss.x + v)
[ Debug  ]   val tmp: Unit = ()
[ Debug  ]   val tmp: Unit = ()
[ Debug  ]   (thiss.x, thiss)
[ Debug  ] }
[ Debug  ] 
[ Debug  ] @library
[ Debug  ] def unfold[T](call: T): Unit = ()
[ Debug  ] 
[ Debug  ] def t: BigInt = {
[ Debug  ]   val c: C = C(0)
[ Debug  ]   val res: (BigInt, C) = update(c, 1)
[ Debug  ]   val c: C = @DropVCs @DropVCs res._2
[ Debug  ]   val tmp: Unit = ()
[ Debug  ]   val c: C = @DropVCs @DropVCs c
[ Debug  ]   val tmp: Unit = ()
[ Debug  ]   val tmp: Unit = {
[ Debug  ]     assume(update(c, 1) == @DropVCs {
[ Debug  ]       val thiss: C = c
[ Debug  ]       val v: BigInt = 1
[ Debug  ]       val thiss: C = thiss
[ Debug  ]       val thiss: C = C(thiss.x + v)
[ Debug  ]       val tmp: Unit = ()
[ Debug  ]       val tmp: Unit = ()
[ Debug  ]       (thiss.x, thiss)
[ Debug  ]     })
[ Debug  ]     ()
[ Debug  ]   }
[ Debug  ]   assert(c.x == 1)
[ Debug  ]   42
[ Debug  ] }
[ Debug  ] 
[ Debug  ] -------------Sorts-------------
[ Debug  ] abstract class C
[ Debug  ] case class C(x: BigInt) extends C
[ Debug  ] 
[ Debug  ] @synthetic
[ Debug  ] abstract class Object
[ Debug  ] case class Open(value: BigInt) extends Object
[ Debug  ] 

And we can see that the assertion is valid, so the side effect is visible

samuelchassot commented 4 weeks ago

So we decided (discussion 14.08.2024):

samuelchassot commented 4 weeks ago

(old issue name: unfold should take ghost parameter to not need to be wrapped in ghostExpr)