stainless icon indicating copy to clipboard operation
stainless copied to clipboard

Problem proving lemma with imperative features

Open jad-hamza opened this issue 6 years ago • 1 comments

Thanks to Romain (J) for reporting

Stainless times out on the assertion arePositive(l).

import stainless.collection._

object Imperative {
  case class Test(var l: List[BigInt]) {

    def lemma(x: BigInt, amount: BigInt) = {
      require(arePositive(x :: l))

      assert(arePositive(x :: l))
      l = x :: l
      assert(arePositive(l))
    }

    def arePositive(l: List[BigInt]): Boolean = {
      l match {
        case Nil() => true
        case p :: ps => p >= 0 && arePositive(ps)
      }
    }
  }
}

The VC which corresponds to this assertion is:

arePositive(thiss, ::[BigInt](thiss.l, x)) ==> (arePositive(thiss, ::[BigInt](thiss.l, x)) ==> {
   val thiss: Test = Test(::[BigInt](thiss.l, x))
  arePositive(thiss, thiss.l)
})

Simplified, this corresponds to:

arePositive(thiss, x :: l) ==> {
   val thiss2: Test = Test(x :: l)
  arePositive(thiss2, x :: l)
})

So the issue comes from the fact that after transformation, arePositive has an extra argument which is the Test class itself. Our workaround for the moment is to pull arePositive out of the class (and then everything works as expected).

jad-hamza avatar Mar 01 '18 13:03 jad-hamza

@jad-hamza : even though I thought that this is something we may not want to fix, I am wondering if it would not be useful for us to implement, for @pure functions, something that does dependency analysis on fields of parameters and the receiver and factors out the function to only take the values that it needs. But the question is how deep such analysis should go in terms of the call graph and in terms of the nesting of fields.

vkuncak avatar May 27 '21 14:05 vkuncak