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

`AntiAliasing` not updating targets for `val` fields #1487

Open mario-bucev opened 9 months ago

mario-bucev commented 9 months ago

The following snippet is marked as invalid even though it is not:

import stainless.lang._
import stainless.annotation._

object VarVarBinks {
  sealed trait OptionMut[@mutable T] {
    def isDefined: Boolean = this match {
      case SomeMut(_) => true
      case NoneMut() => false
    }
    def get: T = {
      require(isDefined)
      this match {
        case SomeMut(v) => v
      }
    }
  }
  // Note: v is not a var!
  case class SomeMut[@mutable T](v: T) extends OptionMut[T]
  case class NoneMut[@mutable T]() extends OptionMut[T]

  case class C1(var f2: OptionMut[C2])
  case class C2(var f3: OptionMut[C3])
  case class C3(var v: BigInt)

  def test(x: BigInt): BigInt = {
    val c1 = C1(NoneMut())
    c1.f2 = SomeMut(C2(NoneMut()))
    c1.f2.get.f3 = SomeMut(C3(x))
    c1.f2.get.f3.get.v // precond to f3.get is invalid
  }
}

This is due to the field of SomeMut (v) being a val (declaring it a var makes the last expression go through as expected). It seems that AntiAliasing is not correctly handling the update for c1.f2.get.f3 due to v not being a var.

vkuncak commented 8 months ago

@mario-bucev How often do we actually want a class parameterized by a mutable type but using val to refer to it?

mario-bucev commented 8 months ago

Not very often but I think this OptionMut/SomeMut is one of the rarest case.