Giter Site home page Giter Site logo

epfl-lara / stainless Goto Github PK

View Code? Open in Web Editor NEW
347.0 18.0 48.0 141.73 MB

Verification framework and tool for higher-order Scala programs

Home Page: https://stainless.epfl.ch

License: Apache License 2.0

Scala 38.85% Python 0.02% HTML 59.52% Shell 0.27% Nix 0.01% CSS 0.46% JavaScript 0.50% Dockerfile 0.01% Coq 0.37% Batchfile 0.01%
verification scala formal-methods smt inox leon z3 cvc4

stainless's Introduction

Stainless Release Nightly Build Status Build Status Gitter chat Apache 2.0 License

Verification framework for a subset of the Scala programming language. See the tutorial.

Quick start

We test mostly on Ubuntu; on Windows, you can get sufficient text-based Ubuntu environment by installing Windows Subsystem for Linux (e.g. wsl --install, then wsl --install -d ubuntu). Ensure you have a Java version ready (it can be headless); on Ubuntu sudo apt install openjdk-17-jdk-headless suffices.

Once ready, Download the latest stainless-dotty-standalone release for your platform. Unzip the archive, and run Stainless through the stainless script. Stainless expects a list of space-separated Scala files to verify but also has other Command-line Options.

To check if everything works, you may create a file named HelloStainless.scala next to the stainless script with the following content:

import stainless.collection._
object HelloStainless {
  def myTail(xs: List[BigInt]): BigInt = {
    require(xs.nonEmpty)
    xs match {
      case Cons(h, _) => h
      // Match provably exhaustive
    }
  }
}

and run stainless HelloStainless.scala. If all goes well, Stainless should report something along the lines:

[  Info  ]   ┌───────────────────┐
[  Info  ] ╔═╡ stainless summary ╞════════════════════════════════════════════════════════════════════╗
[  Info  ] ║ └───────────────────┘                                                                    ║
[  Info  ] ║ HelloStainless.scala:6:5:   myTail  body assertion: match exhaustiveness  nativez3   0,0 ║
[  Info  ] ╟┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╢
[  Info  ] ║ total: 1    valid: 1    (0 from cache) invalid: 0    unknown: 0    time:     0,0         ║
[  Info  ] ╚══════════════════════════════════════════════════════════════════════════════════════════╝
[  Info  ] Shutting down executor service.

If you see funny symbols instead of the beautiful ASCII art, run Stainless with --no-colors option for clean ASCII output with standardized error message format.

The release archive of Stainless only requires JDK17. In particular, it needs neither a Scala compiler nor SBT. It is shipped with Z3 4.12.2, cvc5 1.0.8 and Princess. If Z3 API is not found, use option --solvers=smt-z3 to rely on the executable.

SBT Stainless plugin

Alternatively, one may integrate Stainless with SBT. The supported Scala versions are 3.3.0 and 2.13.12 To do so, download sbt-stainless, and move it to the directory of the project. Assuming the project's structure is:

MyProject
├── build.sbt
├── project
│   └── build.properties
├── sbt-stainless.zip
└── src/

Unzipping sbt-stainless.zip should yield the following:

MyProject
├── build.sbt
├── project
│   ├── build.properties
│   └── lib                     <--------
│       └── sbt-stainless.jar   <--------
├── sbt-stainless.zip
├── src/
└── stainless/                  <--------

That is, it should create a stainless/ directory and a lib/ directory with project/. If, instead, the unzipping process creates a sbt-stainless/ directory containing the lib/project/ and stainless/ directories, these should be moved according to the above structure.

Finally, the plugin must be explicitly enabled for projects in build.sbt desiring Stainless with .enablePlugins(StainlessPlugin). For instance:

ThisBuild / version := "0.1.0"

ThisBuild / scalaVersion := "3.3.0"

lazy val myTestProject = (project in file("."))
  .enablePlugins(StainlessPlugin) // <--------
  .settings(
    name := "Test"
  )

Verification occurs with the usual compile command.

Note that this method only ships the Princess SMT solver. Z3 and cvc5 can still be used if their executable can be found in the $PATH.

Build and Use

To start quickly, install a JVM and use a recent release. To build the project, run sbt universal:stage. If all goes well, scripts are generated for Scala 3 and Scala 2 versions of the front end:

  • frontends/scalac/target/universal/stage/bin/stainless-scalac
  • frontends/dotty/target/universal/stage/bin/stainless-dotty

Use one of these scripts as you would use scalac to compile Scala files. The default behavior of Stainless is to formally verify files, instead of generating JVM class files. See frontends/benchmarks/verification/valid/ and related directories for some benchmarks and bolts repository for a larger collection. More information is available in the documentation links.

Further Documentation and Learning Materials

To get started, see videos:

or see local documentation chapters, such as:

There is also a Stainless EPFL Page.

License

Stainless is released under the Apache 2.0 license. See the LICENSE file for more information.

Relation to Inox

Stainless relies on Inox to solve the various queries stemming from program verification. Inox supports model-complete queries in a feature-rich fragment that lets Stainless focus on program transformations and soundness of both contract and termination checking and uses its own reasoning steps, as well as invocations to solvers (theorem provers) z3, cvc5, and Princess.

stainless's People

Contributors

brunnerant avatar colder avatar czipobence avatar dotta avatar dragos avatar drganam avatar erdeszt avatar frostweeds avatar gorzen avatar gsps avatar ikuraj avatar jad-hamza avatar larsrh avatar manoskouk avatar mantognini avatar mario-bucev avatar masseguillaume avatar mikaelmayer avatar olivierblanvillain avatar ostevan avatar psuter avatar ravimad avatar regb avatar romac avatar samarion avatar samuelchassot avatar samuelgruetter avatar vkuncak avatar y-taka-23 avatar yannbolliger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stainless's Issues

Tuple6 exception

There is a crash when using tuples with 6 elements or more:

Exception in thread "main" stainless.extraction.oo.Definitions$ClassLookupException: Lookup failed for class with symbol Tuple6

object Tuples {
  def f() = (0,0,0,0,0,0)
}

Crash when using forall(p)

This file fails with

Exception in thread "main" inox.ast.Definitions$FunctionLookupException: Lookup failed for function with symbol forall

but works well if we replace forall(p) with forall((t: T) => p(t))

import stainless.lang._

object Intro {

  def test[T](p: T => Boolean): Boolean = {
    forall (p)
  } 

}

Preconditions of lambdas

How does Stainless/Inox interpret preconditions of complex terms, such as f(true) in this example?
There seems to be an issue because the precondition of the application Application(f(true), ()) in g should fail to verify.

import stainless.lang._

object LambdaPreconditions {
  def a() = {
    require(false)
    false
  } holds

  def f(b: Boolean): () => Boolean = {
    if (b) a
    else () => true
  }

  def g() = {
    assert(f(true)())
    assert(false)
  }
}

Crash with Inlining and Implicits

Exception in thread "main" inox.ast.Definitions$FunctionLookupException: Lookup failed for function with symbol BD

object ImplicitInline {
  implicit class BD(val underlying: Boolean) {
    def f(): Unit = ()
  }

  @inline
  def inlinedFunction() = true.f()

  def caller() = inlinedFunction()
}

require() on each element of an array?

Assume I have a function which is doing something with positive integers, say

def fn(a:Array[Int]) = {
require(a.length > 1)
require(a.forall(_ > 0))
a(0)
}.ensuring(_ > 0)

gives "[ Fatal ] The extracted program in not well typed."

Without "require(a.forall(_ > 0))" it works (but the function is invalid, obviously).

Any workaround possible?

Lambda crashes

import stainless.collection._
import stainless.lang._
import scala.Any
import stainless.annotation._
import stainless.proof._
import stainless.util.Random

object Scheduler {
   def test1(a:BigInt):Boolean = {
      ((x:BigInt) => a) == ((x:BigInt) => a)
   }.holds;

   case class B(x:BigInt=>BigInt);
   def test2(a:BigInt):Boolean = {
      val b = new B((x:BigInt) => a)
      ((x:BigInt) => a) == b.x
   }.holds;

   def test3(b:B) = {
      require(forall((e:BigInt) => b.x(e) == 0))
      val res = new B(_ => 0)
      res.x == b.x
   }.holds;

   def test4(b:B) = { // crash
      require(forall((e:BigInt) => b.x(e) == 0))
      ((x:BigInt) => 0) == b.x
   }.holds;

   def test5(a:BigInt):Boolean = { //crash
      require(a == 0)
      ((x:BigInt) => a) == ((x:BigInt) => 0)
   }.holds;
}

Weird behaviors and a crash:

  • The warning says that == is always false on lambdas, but test1 hold:
[Warning ] ./bug3.scala:10:25: warning: comparing a fresh object using `==' will always yield false
                 ((x:BigInt) => a) == ((x:BigInt) => a)
[  Info  ] ║ test1     postcondition                    10:7       valid        nativez3       0.051    ║
  • test1 and test2 hold, but not test3. I understand that in test1 and test2 the lambdas are exactly the same, but it seems a bit counter intuitive to me that they would hold while test3 wouldn't?

  • test4 and test5 crash
    Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.RuntimeException: inox.ast.TypeOps$TypeErrorException: Type error: ...

Exception in SMTLIBParser

This file produces an exception when run with stainless-scalac (corresponding tip-session attached)

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

object Crash {
  
  @induct
  def falseTheorem(k: BigInt, domain: List[BigInt]) = {
    require(domain.contains(k))
       
    false
  
  } holds
}

crash.txt

Abstract class constructor arguments

import stainless.lang._
import stainless.util.Random
import stainless.collection._
import stainless.lang._
import scala.Any
import stainless.annotation._
import stainless.proof._

object DataRacing {
   abstract class SchedEntity(val id:BigInt);
   case class Process(val _id:BigInt, val state: BigInt, val rq: List[BigInt], val task: BigInt,
      val quanta: BigInt, val load: BigInt) extends SchedEntity(_id) {
         require(load >= 1 && load <= 1024)
      }
   case class Runqueue(val _id:BigInt, val content:List[BigInt]) extends SchedEntity(_id);
}

Crashes: "Exception in thread "main" inox.ast.TypeOps$TypeErrorException: Type error ..."

Is there a proper/better way to do inheritance in stainless?

--help doesn't work

$ ./stainless --help
[ Fatal  ] Unknown option: help
[ Fatal  ] Try the --help option for more information.

Support identity function

The following example using the identity function fails. even when using the complete prefix. This is surprising given that the two other identity function, implicitly and locally, are working just fine.

object Test {
  def one: Int =
    scala.Predef.identity[Int](1)
}
[error] Exception in thread "main" java.util.NoSuchElementException: key not found: identity
[error]         at scala.collection.MapLike$class.default(MapLike.scala:228)
[error]         at scala.collection.AbstractMap.default(Map.scala:59)
[error]         at scala.collection.MapLike$class.apply(MapLike.scala:141)
[error]         at scala.collection.AbstractMap.apply(Map.scala:59)
[error]         at stainless.extraction.oo.TypeEncoding$Scope$2.rewrite(TypeEncoding.scala:692)
[error]         at stainless.extraction.oo.TypeEncoding$Scope$2.transform(TypeEncoding.scala:814)
[error]         at inox.ast.TreeTransformer$$anonfun$3.apply(TreeOps.scala:133)
[error]         at inox.ast.TreeTransformer$$anonfun$3.apply(TreeOps.scala:132)
[error]         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[error]         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[error]         at scala.collection.immutable.List.foreach(List.scala:381)
[error]         at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
[error]         at scala.collection.immutable.List.map(List.scala:285)
[error]         at inox.ast.TreeTransformer$class.transform(TreeOps.scala:132)
[error]         at stainless.extraction.oo.TypeEncoding$TypeScope$2.stainless$ast$TreeTransformer$$super$transform(TypeEncoding.scala:191)
[error]         at stainless.ast.TreeTransformer$class.transform(TreeOps.scala:63)
[error]         at stainless.extraction.oo.TypeEncoding$Scope$2.transform(TypeEncoding.scala:871)
[error]         at stainless.extraction.oo.TypeEncoding$class.transformFunction$1(TypeEncoding.scala:978)
[error]         at stainless.extraction.oo.TypeEncoding$$anonfun$91.apply(TypeEncoding.scala:1044)
[error]         at stainless.extraction.oo.TypeEncoding$$anonfun$91.apply(TypeEncoding.scala:1044)
[error]         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[error]         at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[error]         at scala.collection.immutable.List.foreach(List.scala:381)
[error]         at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
[error]         at scala.collection.immutable.List.map(List.scala:285)
[error]         at stainless.extraction.oo.TypeEncoding$class.transform(TypeEncoding.scala:1044)
[error]         at stainless.extraction.oo.package$encoding$.transform(package.scala:30)
[error]         at stainless.extraction.oo.package$encoding$.transform(package.scala:30)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.ast.SymbolTransformer$$anon$3.transform(TreeOps.scala:278)
[error]         at inox.Program$$anon$2.<init>(Program.scala:78)
[error]         at inox.Program$class.transform(Program.scala:76)
[error]         at stainless.frontends.scalac.CodeExtraction$Extraction$$anon$1.transform(CodeExtraction.scala:153)
[error]         at stainless.SimpleComponent$class.extract(Component.scala:46)
[error]         at stainless.verification.VerificationComponent$.extract(VerificationComponent.scala:9)
[error]         at stainless.SimpleComponent$class.apply(Component.scala:50)
[error]         at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:9)
[error]         at stainless.MainHelpers$$anonfun$main$1.apply(MainHelpers.scala:76)
[error]         at stainless.MainHelpers$$anonfun$main$1.apply(MainHelpers.scala:76)
[error]         at scala.collection.immutable.List.foreach(List.scala:381)
[error]         at stainless.MainHelpers$class.main(MainHelpers.scala:76)
[error]         at stainless.Main$.main(Main.scala:5)
[error]         at stainless.Main.main(Main.scala)

Issue with quantifier instantiation

Stainless/Inox report "UNKOWN" for the post-condition of "instantiate".

import stainless.lang._

object Forall {
    
  def isZero(a: BigInt) = a == 0
    
  def instantiate(a: BigInt) = {
    require(forall { (x: BigInt) => isZero(x) })
    
    isZero(a)
  } holds

}

I attached the tip file, also pasted here with renamed variables.
Forall.scala-0.txt

(define-fun isZero ((a Int)) Bool (= a 0))

(declare-const b Int)

(assert (not (=> (forall ((x Int)) (isZero x)) (isZero b))))

(check-sat)

RuntimeException with implicit class

I've tried adding a forall on Set using the following:

implicit class setForall[T](s: Set[T]) {
  def forall(p: T => Boolean): Boolean =
    stainless.lang.forall[T](e => s.contains(e) ==> p(e))
}

This leads to the following stack trace:

Exception in thread "main" java.lang.RuntimeException: Could not find 's' (s$0) within 
        at scala.sys.package$.error(package.scala:27)
        at inox.ast.Definitions$ADTConstructor.selectorID2Index(Definitions.scala:347)
        at inox.ast.Expressions$ADTSelector$$anonfun$selectorIndex$1.apply(Expressions.scala:269)
        at inox.ast.Expressions$ADTSelector$$anonfun$selectorIndex$1.apply(Expressions.scala:269)
        at scala.Option.map(Option.scala:146)
        at inox.ast.Expressions$ADTSelector.selectorIndex(Expressions.scala:269)
        at inox.solvers.z3.AbstractZ3Solver$class.rec$1(AbstractZ3Solver.scala:389)
        at inox.solvers.z3.AbstractZ3Solver$class.toZ3Formula(AbstractZ3Solver.scala:500)
        at inox.solvers.z3.NativeZ3Solver$underlying$.toZ3Formula(NativeZ3Solver.scala:23)
        at inox.solvers.z3.NativeZ3Solver$templates$.mkEncoder(NativeZ3Solver.scala:46)
        at inox.solvers.z3.NativeZ3Solver$templates$.mkEncoder(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.Templates$Template$$anonfun$15.apply(Templates.scala:542)
        at inox.solvers.unrolling.Templates$Template$$anonfun$15.apply(Templates.scala:542)
        at inox.solvers.unrolling.Templates$Template$$anonfun$16.apply(Templates.scala:559)
        at inox.solvers.unrolling.Templates$Template$$anonfun$16.apply(Templates.scala:546)
        at inox.ast.GenTreeOps$class.fold(GenTreeOps.scala:69)
        at inox.ast.Trees$$anon$1.fold(Trees.scala:32)
        at inox.ast.GenTreeOps$$anonfun$1.apply(GenTreeOps.scala:64)
        at inox.ast.GenTreeOps$$anonfun$1.apply(GenTreeOps.scala:64)
        at scala.collection.TraversableViewLike$Mapped$$anonfun$foreach$2.apply(TraversableViewLike.scala:169)
        at scala.collection.Iterator$class.foreach(Iterator.scala:893)
        at scala.collection.AbstractIterator.foreach(Iterator.scala:1336)
        at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
        at scala.collection.SeqLike$$anon$2.foreach(SeqLike.scala:671)
        at scala.collection.TraversableViewLike$Mapped$class.foreach(TraversableViewLike.scala:168)
        at scala.collection.SeqViewLike$$anon$3.foreach(SeqViewLike.scala:197)
        at scala.collection.TraversableViewLike$FlatMapped$class.foreach(TraversableViewLike.scala:177)
        at scala.collection.SeqViewLike$$anon$4.foreach(SeqViewLike.scala:198)
        at scala.collection.TraversableOnce$class.toMap(TraversableOnce.scala:316)
        at scala.collection.SeqViewLike$AbstractTransformed.toMap(SeqViewLike.scala:37)
        at inox.solvers.unrolling.Templates$Template$$anonfun$16.apply(Templates.scala:547)
        at inox.solvers.unrolling.Templates$Template$$anonfun$16.apply(Templates.scala:546)
        at inox.ast.GenTreeOps$class.fold(GenTreeOps.scala:69)
        at inox.ast.Trees$$anon$1.fold(Trees.scala:32)
        at inox.solvers.unrolling.Templates$Template$.extractCalls(Templates.scala:570)
        at inox.solvers.unrolling.Templates$Template$$anonfun$34$$anonfun$apply$23.apply(Templates.scala:635)
        at inox.solvers.unrolling.Templates$Template$$anonfun$34$$anonfun$apply$23.apply(Templates.scala:634)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at inox.solvers.unrolling.Templates$Template$$anonfun$34.apply(Templates.scala:634)
        at inox.solvers.unrolling.Templates$Template$$anonfun$34.apply(Templates.scala:628)
        at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:733)
        at scala.collection.immutable.Map$Map3.foreach(Map.scala:161)
        at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:732)
        at inox.solvers.unrolling.Templates$Template$.encode(Templates.scala:628)
        at inox.solvers.unrolling.Templates$class.instantiateExpr(Templates.scala:816)
        at inox.solvers.z3.NativeZ3Solver$templates$.instantiateExpr(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.AbstractUnrollingSolver$class.assertCnstr(UnrollingSolver.scala:144)
        at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.inox$tip$TipDebugger$$super$assertCnstr(SolverFactory.scala:115)
        at inox.tip.TipDebugger$class.assertCnstr(TipDebugger.scala:52)
        at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.assertCnstr(SolverFactory.scala:115)
        at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.assertCnstr(SolverFactory.scala:115)
        at stainless.verification.VerificationChecker$class.stainless$verification$VerificationChecker$$checkVC(VerificationChecker.scala:122)
        at stainless.verification.VerificationChecker$$anonfun$6.apply(VerificationChecker.scala:97)
        at stainless.verification.VerificationChecker$$anonfun$6.apply(VerificationChecker.scala:96)
        at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:683)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:682)
        at stainless.verification.VerificationChecker$class.checkVCs(VerificationChecker.scala:96)
        at stainless.verification.VerificationChecker$checker$2$.checkVCs(VerificationChecker.scala:185)
        at stainless.verification.VerificationChecker$class.verify(VerificationChecker.scala:54)
        at stainless.verification.VerificationChecker$checker$2$.verify(VerificationChecker.scala:185)
        at stainless.verification.VerificationChecker$.verify(VerificationChecker.scala:202)
        at stainless.verification.VerificationChecker$.verify(VerificationChecker.scala:206)
        at stainless.verification.VerificationComponent$.check(VerificationComponent.scala:84)
        at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:92)
        at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:9)
        at stainless.SimpleComponent$class.apply(Component.scala:59)
        at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:9)
        at stainless.MainHelpers$$anonfun$main$1.apply(MainHelpers.scala:76)
        at stainless.MainHelpers$$anonfun$main$1.apply(MainHelpers.scala:76)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at stainless.MainHelpers$class.main(MainHelpers.scala:76)
        at stainless.Main$.main(Main.scala:5)
        at stainless.Main.main(Main.scala)

Extraction troubles with `equals` methods

object Test {

  case class A()
  def equals(a1: A, a2: A): Boolean = true // extracted as equals$0

  case class B()

  // def foo(a: A, b: B) = equals(a, b) // doesn't compile, good!

  case class Table() {
    def foo(a: A, b: B) = equals(a, b) // there's a typo but it still compiles. :(
    // The compiler understand this statement as:
    //    this.equals( (a, b) )
    // which is legal (although always false), instead of this:
    //    Test.equals(a, b)
    // which doesn't compile, as expected.
    //
    // Also, equals(a, a) yields the same error from stainless.
  }

}

At the moment (*), stainless yields the following error:

[ Error  ] foo$0 depends on missing dependencies: equals$1.
[ Debug  ] @method(Table$0)
[ Debug  ] def foo$0(a$16: A$30, b$13: B$20): Boolean = this.equals$1((a$16, b$13))
[Internal] Missing some nodes in Registry: equals$1

We should probably do something about this. The simplest solution would be to forbid having any function called equals. It's not the best but definitely the cheapest one to implement.

(*) using persistent_cache & options branches.

Crash when using & instead of && for Booleans

The & operator produces a crash with an exception

Exception in thread "main" inox.ast.TypeOps$TypeErrorException: Type error

object Untyped {
  def untyped(a: Boolean) = {
    require(a & a)    
    assert(true)
  }
}

Missfomed TIP source output?

When generating .tip files for debug, I've noticed that some of them don't parse in Inox. For example this one:

(declare-const i!20 (_ BitVec 32))

(declare-datatypes (A!251) ((array!160 (array!161 (arr!81 (Array (_ BitVec 32) A!251)) (size!120 (_ BitVec 32))))))

(define-fun foo!3 ((i!19 (_ BitVec 32))) (array!160 (_ BitVec 32)) (assume (bvsgt i!19 #b00000000000000000000000000000000) (let ((res!38 (array!161 ((as const (Array (_ BitVec 32) (_ BitVec 32))) #b00000000000000000000000000000000) i!19))) (assume (= (size!120 res!38) i!19) res!38))))

(datatype-invariant (par (A!250) array!141 (array!160 A!250) (bvsge (size!120 array!141) #b00000000000000000000000000000000)))

(assert (not (=> (bvsgt i!20 #b00000000000000000000000000000000) (let ((b!352 (foo!3 i!20))) (and (bvsge #b00000000000000000000000000000000 #b00000000000000000000000000000000) (bvslt #b00000000000000000000000000000000 (size!120 b!352)))))))

(check-sat)

; check-assumptions required here, but not part of tip standard

gives the following error:

[info] [Warning ] Failed to parse ../stainless/tip-sessions/AbstractRefinementMap.scala-65.tip: inox.tip.MissformedTIPException: Missfomed TIP source @?:?:
[info] [Warning ] could not instantiate List(TypeParameterDef(A!251)) in List(Map[Int, A!251], Int32Type) given List(Map[Map[Int, Int], Int], Int32Type)

Now, I don't know much about tip and the assumptions behind it so I don't know if this is a bug in:

  1. (hopefully unlikely) a bug in stainless internal representation of programs,
  2. stainless' TIP output,
  3. inox's TIP parser.

Here is a zip archive of a bunch of tip files, some of them being rejected by inox.

NoSuchElementException with nested foralls

While trying to prove properties on sorted lists, I used nested forall to express the fact that one list is smaller than the other:

def isSorted(list: List[BigInt]): Boolean = list match {
  case Cons(x, xs @ Cons(y, _)) => x <= y && isSorted(xs)
  case _ => true
}

def plusplus(l: List[BigInt], r: List[BigInt]) : List[BigInt] = {
  require(isSorted(l) && isSorted(r) && l.forall(e => r.forall(e.<=)))
  l ++ r
} ensuring(res => isSorted(res))

This leads to the stack trace below. Note that using stainless.lang.forall expression instead works as expected.

Exception in thread "main" java.util.NoSuchElementException: key not found: e
        at scala.collection.MapLike$class.default(MapLike.scala:228)
        at scala.collection.AbstractMap.default(Map.scala:59)
        at scala.collection.MapLike$class.apply(MapLike.scala:141)
        at scala.collection.AbstractMap.apply(Map.scala:59)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$6.apply(TemplateGenerator.scala:149)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$6.apply(TemplateGenerator.scala:149)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.immutable.Set$Set2.foreach(Set.scala:128)
        at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
        at scala.collection.AbstractSet.scala$collection$SetLike$$super$map(Set.scala:47)
        at scala.collection.SetLike$class.map(SetLike.scala:92)
        at scala.collection.AbstractSet.map(Set.scala:47)
        at inox.solvers.unrolling.TemplateGenerator$class.mkExprStructure(TemplateGenerator.scala:149)
        at inox.solvers.z3.NativeZ3Solver$templates$.mkExprStructure(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.LambdaTemplates$LambdaTemplate$.apply(LambdaTemplates.scala:62)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:350)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
        at scala.collection.immutable.List.map(List.scala:285)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
        at scala.collection.immutable.List.map(List.scala:285)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$class.mkExprClauses(TemplateGenerator.scala:393)
        at inox.solvers.z3.NativeZ3Solver$templates$.mkExprClauses(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.LambdaTemplates$LambdaTemplate$$anonfun$3.apply(LambdaTemplates.scala:71)
        at inox.solvers.unrolling.LambdaTemplates$LambdaTemplate$$anonfun$3.apply(LambdaTemplates.scala:70)
        at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:124)
        at scala.collection.immutable.List.foldLeft(List.scala:84)
        at inox.solvers.unrolling.LambdaTemplates$LambdaTemplate$.apply(LambdaTemplates.scala:70)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:350)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
        at scala.collection.immutable.List.map(List.scala:285)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$$anonfun$rec$1$4.apply(TemplateGenerator.scala:390)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
        at scala.collection.immutable.List.map(List.scala:285)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:390)
        at inox.solvers.unrolling.TemplateGenerator$class.recAnd$1(TemplateGenerator.scala:263)
        at inox.solvers.unrolling.TemplateGenerator$class.rec$1(TemplateGenerator.scala:277)
        at inox.solvers.unrolling.TemplateGenerator$class.mkExprClauses(TemplateGenerator.scala:393)
        at inox.solvers.z3.NativeZ3Solver$templates$.mkExprClauses(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.TemplateGenerator$class.mkClauses(TemplateGenerator.scala:67)
        at inox.solvers.z3.NativeZ3Solver$templates$.mkClauses(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.Templates$class.instantiateExpr(Templates.scala:813)
        at inox.solvers.z3.NativeZ3Solver$templates$.instantiateExpr(NativeZ3Solver.scala:32)
        at inox.solvers.unrolling.AbstractUnrollingSolver$class.assertCnstr(UnrollingSolver.scala:144)
        at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.inox$tip$TipDebugger$$super$assertCnstr(SolverFactory.scala:115)
        at inox.tip.TipDebugger$class.assertCnstr(TipDebugger.scala:52)
        at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.assertCnstr(SolverFactory.scala:115)
        at inox.solvers.SolverFactory$$anonfun$getFromName$1$$anon$1.assertCnstr(SolverFactory.scala:115)
        at stainless.verification.VerificationChecker$class.stainless$verification$VerificationChecker$$checkVC(VerificationChecker.scala:122)
        at stainless.verification.VerificationChecker$$anonfun$6.apply(VerificationChecker.scala:97)
        at stainless.verification.VerificationChecker$$anonfun$6.apply(VerificationChecker.scala:96)
        at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:683)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:682)
        at stainless.verification.VerificationChecker$class.checkVCs(VerificationChecker.scala:96)
        at stainless.verification.VerificationChecker$checker$2$.checkVCs(VerificationChecker.scala:185)
        at stainless.verification.VerificationChecker$class.verify(VerificationChecker.scala:54)
        at stainless.verification.VerificationChecker$checker$2$.verify(VerificationChecker.scala:185)
        at stainless.verification.VerificationChecker$.verify(VerificationChecker.scala:202)
        at stainless.verification.VerificationChecker$.verify(VerificationChecker.scala:206)
        at stainless.verification.VerificationComponent$.check(VerificationComponent.scala:84)
        at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:92)
        at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:9)
        at stainless.SimpleComponent$class.apply(Component.scala:59)
        at stainless.verification.VerificationComponent$.apply(VerificationComponent.scala:9)
        at stainless.MainHelpers$$anonfun$main$1.apply(MainHelpers.scala:76)
        at stainless.MainHelpers$$anonfun$main$1.apply(MainHelpers.scala:76)
        at scala.collection.immutable.List.foreach(List.scala:381)
        at stainless.MainHelpers$class.main(MainHelpers.scala:76)
        at stainless.Main$.main(Main.scala:5)
        at stainless.Main.main(Main.scala)

Semantic of decreases()?

import stainless.lang._
import stainless.util.Random
import stainless.collection._
import stainless.lang._
import scala.Any
import stainless.annotation._
import stainless.proof._

object DataRacing {
   case class SharedState(val rqs:BigInt => List[BigInt]) {
      require(forall((id:BigInt) => rqs(id).forall(e => e < id && e >= 0)))
   }

   @induct
   def isTree(s:SharedState, content:List[BigInt], id:BigInt):Boolean = {
      require(content.forall(e => e < id && e >= 0) && id >= 0)
      decreases(id, content.size)


      content match {
         case Nil() => true
         case Cons(t, ts) =>
            isTree(s, ts, id) && isTree(s, s.rqs(t), t)
      }
   }
}

Not really an issue, but I was wondering if I understood correctly how "decreases" work. Does decreases(a, b) means that either a, or b decreases? (As in the previous example, either id or the size decreases.)

Also, is there a page, or a document somewhere that contains a list of "helpers" that can be used to reduce the proving effort, such as forall, choose, decreases? (Am I missing any other tool/quantifier/...?)

Thanks :)

Invalid overflow check?

This code:

def addManyLongs(amounts: Array[Long]): Long = {
    require(amounts.length > 1 && amounts.length < 10  &&
      forall((i: Int) => (i >= 0 && i < amounts.length) ==>
        (amounts(i) >= 0 && amounts(i) <= 1000)))

    var sum = 0L
    var i = 0

    (while (i < amounts.length) {
      sum = sum + amounts(i)
      i = i + 1
    }) invariant(i >= 0)

    sum
}.ensuring(_ >= 0)

fails overflow validation:

[ Info ] - Result for 'integer overflow' VC for addManyLongsWhile @63:13:
[Warning ] => INVALID
[Warning ] Found counter-example:
[Warning ] sum: Long -> 9223372036854775553
[Warning ] i: Int -> 0
[Warning ] amounts: Array[Long] -> Array(489, 489, 489, 489, 489, 489, 489, 489, 489)

Why such a counter-example is generated, if sum = 0 in the code?

Support for anonymous class

I believe this could be part for the supported subset of Scala. Here is a minimised example that doesn't pass extraction:

object Test {
  val o = new Object {}
  println(o)
}

Scalac will desugar that code into a local class definition and an instantiation. It looks like nested class definition are at fault; the following also fails to pass extraction:

object Test {
  class C {
    def f: Unit = {
      class D
      ()
    }
  }
}

Typing issue with sets

Because of the minus (-) operator, Stainless/Inox crashes on the following file with the exception:

Exception in thread "main" inox.ast.TypeOps$TypeErrorException: Type error

The crash disappears when replacing "- x" with "-- Set(x)"

import stainless.collection._
import stainless.lang._

object Content {

  def wrongTheorem[A](l: List[A], x: A): Boolean = {
    l.content == l.content - x
  
  } holds
  
}

Soundness issue when quantifying over tuples

On this file, Stainless/Inox returns a wrong counter-example to lemma. The problem disappears if we replace
forall( (t: (A,A,A)) =>
with
forall( (x: A, y: A, z: A) =>

import stainless.lang._

object Associativity {
 
  def isAssociative[A](f: (A,A) => A): Boolean = {
    forall( (t: (A,A,A)) => {
      val (x,y,z) = t
      f(x,f(y,z)) == f(f(x,y),z)
    })
  }
  
  def lemma[A](f: (A,A) => A, x: A): Boolean = {
    require(isAssociative(f))
    
    f(f(x,x),x) == f(x,f(x,x))
  } holds
  
}

How to run a single test?

I think it would be useful to add a paragraph to installation#running-tests explaining how to run tests individually.

In my case I'm adding new entries in frontends/benchmarks/extraction, is it sufficient to run the following:?

$ sbt 'stainless-scalac/run frontends/benchmarks/extraction/new-test.scala'
$ sbt 'stainless-dotty/run frontends/benchmarks/extraction/new-test.scala'

Higher-order contracts

No verification condition is generated for the holds in the lambda defined in f. This allows us to prove false in g.

import stainless.lang._

object Post {
  def f(): () => Boolean = {
    () => {
      false 
    } holds
  }
  
  def g() = {
    assert(f()())
    assert(false)
  }
}

Unexpected effect of inheritance on verification

I have minimised an example where slightly changing inheritance affect verification in unexpected ways. I'm using 3 level of inheritance:

trait A            { def f(i: Int): Int }
class B extends A  { def f(i: Int): Int = i + 1 }
class C extends B  { def proof: Boolean = ... }

The proof I wrote is class C is able to verify when I change class B extends A {...} to trait B {...}. There might be two issues in one, because the verification also fails if using class C {...} instead of trait B {...}. This is the complete example:

trait Monad[F[_]] {
  def pure[A](x: A): F[A]
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}
import stainless.collection._

// Doesn't work with:
// class ListMonadInstance extends Monad[List] {

// Neither with
// class ListMonadInstance {

// But it does this way:
trait ListMonadInstance {
  def pure[A](x: A): List[A] = List(x)

  def flatMap[A, B](fa: List[A])(f: A => List[B]): List[B] =
    fa match {
      case Cons(x, xs) => combine(f(x), flatMap(xs)(f))
      case Nil() => Nil()
    }

  def combine[A](l1: List[A], l2: List[A]): List[A] =
    l1 match {
      case Cons(x, xs) => Cons(x, combine(xs, l2))
      case Nil() => l2
    }
}
import stainless.collection._
import stainless.lang._
import stainless.proof._

class ListMonadProofs extends ListMonadInstance {
  def monadAssociativity[A, B, C](fa: List[A], f: A => List[B], g: B => List[C]) =
    (flatMap(flatMap(fa)(f))(g) == flatMap(fa)(x => flatMap(f(x))(g)))

  def monadAssociativityProof[A, B, C](
    fa: List[A],
    fb: List[B],
    fc: List[C],
    f: A => List[B],
    g: B => List[C]
  ): Boolean = {
    monadAssociativity(fa, f, g) because {
      (  combine(combine(fc, flatMap(fb)(g)), flatMap(fa)(x => flatMap(f(x))(g)))
      == combine(fc, flatMap(combine(fb, flatMap(fa)(f)))(g))) because {
        fc match {
          case Cons(_, xs) =>
            monadAssociativityProof(fa, fb, xs, f, g)
          case Nil() => fb match {
            case Cons(x, xs) =>
              monadAssociativityProof(fa, xs, g(x), f, g)
            case Nil() => fa match {
              case Cons(x, xs) => monadAssociativityProof(xs, f(x), Nil(), f, g)
              case Nil() => true
            }
          }
        }
      }
    }
  }.holds
}

list.forall and proofs

@induct
def updateProcLemma(s:SharedState, c:BigInt, u:BigInt, p:Process, l:List[BigInt]):Boolean = {
   l.forall(e => if(e != u) updateProc(s, c, u, p)(e) == s.procs(e) else true);
}.holds;

In another proof:
updateProcLemma(s, c, s.states(c).current_0.get, res.procs(old_current), s.states(c).ready) && // ok
s.states(c).ready.forall(e => if(e != s.states(c).current_0.get) updateProc(s, c, s.states(c).current_0.get, res.procs(old_current))(e) == s.procs(e) else true) // unable to verify, but why?

Stainless is not able to prove the last line. It seems to me that this is a direct search & replace of the content of updateProcLemma. Is there any reason for that?

Sorry if this has been mentioned somewhere else. I remember having read somewhere that the forall() quantifier was treated as a black box, but is list.forall the same?

Z3 exception with higher order function

I get an exception with this file with Z3 native, but --solvers=smt-z3 works well

com.microsoft.z3.Z3Exception: Sorts (BigInt) => BigInt and (BigInt) => fun1[BigInt, BigInt] are incompatible

import stainless.lang._

object Incompatible {

  def false_theorem(f: BigInt => (BigInt => BigInt)) = {
    false
  } holds
  
}

Stainless yields lambdas with unsatisfiable preconditions (ie. an invalid model)

@jad-hamza and I ran into the following issue today:

The following testcase yields a counter-example with an unsatisfiable precondition, which is catched by --check-models as an invalid model.

import stainless.lang._

object util {
  @inline
  def total[A, B](f: A => B): Boolean = forall { (a: A) =>
    f.pre(a)
  }
}

case class Cont[R, A](run: (A => R) => R) {

  import util._

  require(total(run))

  def map[B](f: A => B): Cont[R, B] = {
    require(total(f))

    Cont { (k: B => R) =>
      // require(true) // TODO: Report issue
      this.run(x => k(f(x)))
    }
  }
}
(snip...)

[  Info  ]  - Now solving 'lambda precondition' VC for map @24:21...
[ Debug  ] @unchecked ∀a: A. f.pre(a) ==> k.pre(f(x))
[ Debug  ] Solving with: nativez3
[  Info  ]  - Result for 'lambda precondition' VC for map @24:21:
[Warning ]  => INVALID
[Warning ] Found counter-example:
[Warning ]   x: A        -> A#0
[Warning ]   k: (B) => R -> (x$524: B) => {
[Warning ]     require(if (x$524 == B#0) {
[Warning ]       false
[Warning ]     } else {
[Warning ]       false
[Warning ]     })
[Warning ]     R#0
[Warning ]   }
[Warning ]   f: (A) => B -> (x$541: A) => if (x$541 == A#0) {
[Warning ]     B#0
[Warning ]   } else {
[Warning ]     B#0
[Warning ]   }

(snip...)

On the other hand, explicitly specifying require(true) as a precondition inside of the lambda makes the testcase validates.

import stainless.lang._

object util {
  @inline
  def total[A, B](f: A => B): Boolean = forall { (a: A) =>
    f.pre(a)
  }
}

case class Cont[R, A](run: (A => R) => R) {

  import util._

  require(total(run))

  def map[B](f: A => B): Cont[R, B] = {
    require(total(f))

    Cont { (k: B => R) =>
      require(true)
      this.run(x => k(f(x)))
    }
  }
}
(snip...)

[  Info  ]  - Now solving 'lambda precondition' VC for map @24:23...
[ Debug  ] @unchecked ∀a: A. f.pre(a) ==> f.pre.pre(x)
[ Debug  ] Solving with: nativez3
[  Info  ]  - Result for 'lambda precondition' VC for map @24:23:
[  Info  ]  => VALID

(snip...)

Is is not clear to me:

a) why such a precondition should be considered
b) why explicitly adding require(true) makes the issue go away. Shouldn't it be the default for a lambda with no explicit precondition?

CC: @vkuncak @samarion

@induct breaks proofs?

import stainless.collection._
import stainless.annotation._

object DataRacing {
   case class SharedState(val rqs:BigInt => List[BigInt]);

   @induct
   def isTree(s:SharedState, content:List[BigInt], id:BigInt):Boolean = {
      require(content.forall(e => e < id && e >= 0))
      content match {
         case Nil() => true
         case Cons(t, ts) =>
            isTree(s, ts, id) && isTree(s, s.rqs(t), t)
      }
   }
}

This function verifies, but shouldn't (nothing says that s.rqs(...) matches the requirements).
When the @Induct is removed stainless finds a counter example.

Is that an expected behaviour?

Clarify relationship with Leon for newbies

Hi,

I'm a newbie to Stainless and Leon - neither README for Stainless or Leon seems to mention the other, but the READMEs clearly have some relationship. I assume Stainless is the newer system, so it would be helpful if there was at least some explanation on a comparison between the two (features, reasons for divergence, maturity, etc).

Thanks!

List.sorted doesn't behave as expected

In List.scala:

  def sorted(ls: List[BigInt]): List[BigInt] = { ls match {
    case Cons(h, t) => sortedIns(sorted(t), h)
    case Nil() => Nil[BigInt]()
  }} ensuring { isSorted _ }

  private def sortedIns(ls: List[BigInt], v: BigInt): List[BigInt] = {
    require(isSorted(ls))
    ls match {
      case Nil() => Cons(v, Nil())
      case Cons(h, t) =>
        if (v <= h) {
          Cons(v, t)  //wrong!
        } else {
          Cons(h, sortedIns(t, v))
        }
    }
  } ensuring { isSorted _ }

should be

       if (v <= h) {
          Cons(v, ls) // ls not t

otherwise the list loses elements during the sort. ;)

I suggest changing the ensuring statement to:

ensuring { res => isSorted(res) && res.content == ls.content ++ Set(v) }

Release page?

Where can I watch for releases? I am watching the project on GitHub but that tends to be too noisy for me, since I am nowhere in the league of contributing to it.

I don't see any milestones defined either. Can I just track point releases here: https://github.com/epfl-lara/stainless/releases
(via the RSS feed of that page)?

Thanks!

Weird forall behavior

import stainless.lang._
import stainless.util.Random
import stainless.collection._
import stainless.lang._
import scala.Any
import stainless.annotation._
import stainless.proof._

object DataRacing {
   case class SchedEntity(val id:BigInt, val state: BigInt, val quanta: BigInt, val core:BigInt, val load: BigInt, val rq:List[BigInt]);

   case class Core(val current: Option[BigInt], val ready: BigInt);
   case class SharedState(
      val progress:BigInt,
      val cores:List[BigInt],
      val states:BigInt => Core,
      val entities:BigInt => SchedEntity) {
         require(forall((id:BigInt) => entities(id).rq.forall(e => entities(e).id < id && entities(e).id >= 0)))
   }

   def test(s:SharedState, id:BigInt):Boolean = {
      s.entities(id).rq.forall(e => s.entities(e).id < s.entities(id).id && s.entities(e).id >= 0)
   }.holds;

Stainless is not able to verify the function "test". Is there any reason for that? (It looks like the property of the forall should trivially apply there?)

Error is:

[  Info  ]  - Now considering 'postcondition' VC for test @22:7...
[ Error  ] Quantification forall[BigInt](x$246.entities.f(x$201).rq, fun1[BigInt, Boolean]((x$205: BigInt) => x$245.entities.f(x$205).id < x$201 && x$247.entities.f(x$205).id >= x$249, x$248)) does not fit in supported fragment.
[ Error  ]   Reason: Unandled implications from operation x$246.entities.f(x$201).rq
[ Error  ] Model obtained was:
[ Error  ]   id: BigInt     -> 14133
[ Error  ]   s: SharedState -> SharedState(8, Nil[BigInt](), (x$201: BigInt) => Core(None[BigInt](), 0), (x$331: BigInt) => if (x$331 == 14131) {
[ Error  ]     SchedEntity(7145, 21, 22, 23, 24, Nil[BigInt]())
[ Error  ]   } else if (x$331 == 14139) {
[ Error  ]     SchedEntity(14137, 39, 40, 41, 42, Nil[BigInt]())
[ Error  ]   } else if (x$331 == 5874) {
[ Error  ]     SchedEntity(-1, 33, 34, 35, 36, Nil[BigInt]())
[ Error  ]   } else if (x$331 == 14130) {
[ Error  ]     SchedEntity(14466, 28, 29, 30, 31, Nil[BigInt]())
[ Error  ]   } else if (x$331 == 14138) {
[ Error  ]     SchedEntity(14137, 15, 16, 17, 18, Cons[BigInt](14139, Nil[BigInt]()))
[ Error  ]   } else if (x$331 == 14133) {
[ Error  ]     SchedEntity(5875, 78, 79, 80, 81, Cons[BigInt](14131, Nil[BigInt]()))
[ Error  ]   } else if (true) {
[ Error  ]     SchedEntity(14137, 15, 16, 17, 18, Cons[BigInt](14139, Nil[BigInt]()))
[ Error  ]   } else {
[ Error  ]     SchedEntity(14137, 15, 16, 17, 18, Cons[BigInt](14139, Nil[BigInt]()))
[ Error  ]   })
[Warning ]  => UNKNOWN

Extraction test suite and verification pipeline yield different results

With my branch in #78, the following benchmark yields different results with the extraction test suite and the verification pipeline that runs when invoking stainless on its own (either from the command-line or through sbt runMain.

object ConstructorArgsBoxing2 {
  case class A()
  case class B()

  sealed abstract class AnyFoo
  case class Foo[T](x: T) extends AnyFoo

  val a: AnyFoo = Foo(A())
  val b: AnyFoo = Foo(B())

  val list0: List[AnyFoo] = List(a, b)
}

I tried performing the extraction in the test suite using VerificationComponent.extract, but am still getting the same error.

Any idea what could be going wrong there?

Extraction test suite

stainless-scala/it:testOnly stainless.ExtractionSuite

(…snip…)

[info]   Extraction of 'extraction/ConstructorArgsBoxing2.scala'
[info]   - should be successful (0 milliseconds)
[info]   - should typecheck (12 milliseconds)
[info]     and transformation
====== ERROR ======
java.util.NoSuchElementException: key not found: apply
	at scala.collection.MapLike$class.default(MapLike.scala:228)
	at scala.collection.AbstractMap.default(Map.scala:59)
	at scala.collection.MapLike$class.apply(MapLike.scala:141)
	at scala.collection.AbstractMap.apply(Map.scala:59)
	at stainless.extraction.oo.TypeEncoding$Scope$2.rewrite(TypeEncoding.scala:724)
	at stainless.extraction.oo.TypeEncoding$Scope$2.transform(TypeEncoding.scala:849)
	at stainless.extraction.oo.TypeEncoding$$anonfun$96.apply(TypeEncoding.scala:1074)
	at stainless.extraction.oo.TypeEncoding$$anonfun$96.apply(TypeEncoding.scala:1074)
	at scala.Option.map(Option.scala:146)
	at stainless.extraction.oo.TypeEncoding$class.transformFunction$1(TypeEncoding.scala:1074)
	at stainless.extraction.oo.TypeEncoding$$anonfun$98.apply(TypeEncoding.scala:1090)
	at stainless.extraction.oo.TypeEncoding$$anonfun$98.apply(TypeEncoding.scala:1090)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
	at scala.collection.immutable.List.foreach(List.scala:381)
	at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
	at scala.collection.immutable.List.map(List.scala:285)
	at stainless.extraction.oo.TypeEncoding$class.transform(TypeEncoding.scala:1090)
	at stainless.extraction.oo.package$encoding$.transform(package.scala:30)
	at stainless.extraction.oo.package$encoding$.transform(package.scala:30)
	at inox.ast.SymbolTransformerComposition$class.transform(TreeOps.scala:307)
	at inox.ast.SymbolTransformer$$anon$2.transform(TreeOps.scala:327)
	at inox.ast.SymbolTransformerComposition$class.transform(TreeOps.scala:307)
	at inox.ast.SymbolTransformer$$anon$2.transform(TreeOps.scala:327)
	at inox.ast.SymbolTransformerComposition$class.transform(TreeOps.scala:307)
	at inox.ast.SymbolTransformer$$anon$2.transform(TreeOps.scala:327)
	at inox.ast.SymbolTransformerComposition$class.transform(TreeOps.scala:307)
	at inox.ast.SymbolTransformer$$anon$2.transform(TreeOps.scala:327)
	at inox.ast.SymbolTransformerComposition$class.transform(TreeOps.scala:307)
	at inox.ast.SymbolTransformer$$anon$2.transform(TreeOps.scala:327)
	at inox.ast.SymbolTransformerComposition$class.transform(TreeOps.scala:307)
	at inox.ast.SymbolTransformer$$anon$2.transform(TreeOps.scala:327)
	at inox.Program$class.transform(Program.scala:77)
	at inox.Program$$anon$1.transform(Program.scala:90)
	at stainless.extraction.package$.extract(package.scala:77)
	at stainless.SimpleComponent$class.extract(Component.scala:41)
	at stainless.verification.VerificationComponent$.extract(VerificationComponent.scala:22)
	at stainless.ExtractionSuite$$anonfun$2.apply(ExtractionSuite.scala:44)
	at stainless.ExtractionSuite$$anonfun$2.apply(ExtractionSuite.scala:44)
	at scala.util.Try$.apply(Try.scala:192)
	at stainless.ExtractionSuite.stainless$ExtractionSuite$$extractOne(ExtractionSuite.scala:44)
	at stainless.ExtractionSuite$$anonfun$testAll$1$$anonfun$apply$mcV$sp$8$$anonfun$apply$1.apply$mcV$sp(ExtractionSuite.scala:78)
	at org.scalatest.SuperEngine.registerNestedBranch(Engine.scala:595)
	at org.scalatest.FunSpecLike$class.describe(FunSpecLike.scala:382)
	at org.scalatest.FunSpec.describe(FunSpec.scala:1630)
	at stainless.ExtractionSuite$$anonfun$testAll$1$$anonfun$apply$mcV$sp$8.apply(ExtractionSuite.scala:77)
	at stainless.ExtractionSuite$$anonfun$testAll$1$$anonfun$apply$mcV$sp$8.apply(ExtractionSuite.scala:76)
	at scala.collection.immutable.List.foreach(List.scala:381)
	at stainless.ExtractionSuite$$anonfun$testAll$1.apply$mcV$sp(ExtractionSuite.scala:76)
	at org.scalatest.SuperEngine.registerNestedBranch(Engine.scala:595)
	at org.scalatest.FunSpecLike$class.describe(FunSpecLike.scala:382)
	at org.scalatest.FunSpec.describe(FunSpec.scala:1630)
	at stainless.ExtractionSuite.testAll(ExtractionSuite.scala:75)
	at stainless.ExtractionSuite.<init>(ExtractionSuite.scala:84)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:435)
	at sbt.TestRunner.runTest$1(TestFramework.scala:76)
	at sbt.TestRunner.run(TestFramework.scala:85)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
	at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:185)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
	at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
	at sbt.TestFunction.apply(TestFramework.scala:207)
	at sbt.Tests$.sbt$Tests$$processRunnable$1(Tests.scala:239)
	at sbt.Tests$$anonfun$makeSerial$1.apply(Tests.scala:245)
	at sbt.Tests$$anonfun$makeSerial$1.apply(Tests.scala:245)
	at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
	at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
	at sbt.std.Transform$$anon$4.work(System.scala:63)
	at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
	at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
	at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
	at sbt.Execute.work(Execute.scala:237)
	at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
	at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
	at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
	at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
[info]     - should be successful *** FAILED *** (55 milliseconds)
[info]       org.scalatest.exceptions.TestFailedException was thrown. (ExtractionSuite.scala:19)
[info]       org.scalatest.exceptions.TestFailedException:
[info]       at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:528)
[info]       at org.scalatest.FunSpec.newAssertionFailedException(FunSpec.scala:1630)
[info]       at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:501)
[info]       at stainless.ExtractionSuite.stainless$ExtractionSuite$$assertSuccess(ExtractionSuite.scala:19)

(…snip…)

Verification pipeline

runMain ConstructorArgsBoxing2.scala

[  Info  ]  - Now solving 'postcondition' VC for a @?:?...
[  Info  ]  - Result for 'postcondition' VC for a @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'cast correctness' VC for a @?:?...
[  Info  ]  - Result for 'cast correctness' VC for a @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'cast correctness' VC for a @?:?...
[  Info  ]  - Result for 'cast correctness' VC for a @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'cast correctness' VC for a @?:?...
[  Info  ]  - Result for 'cast correctness' VC for a @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'postcondition' VC for b @?:?...
[  Info  ]  - Result for 'postcondition' VC for b @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'cast correctness' VC for b @?:?...
[  Info  ]  - Result for 'cast correctness' VC for b @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'cast correctness' VC for b @?:?...
[  Info  ]  - Result for 'cast correctness' VC for b @?:?:
[  Info  ]  => VALID
[  Info  ]  - Now solving 'cast correctness' VC for b @?:?...
[  Info  ]  - Result for 'cast correctness' VC for b @?:?:
[  Info  ]  => VALID
[  Info  ]   ┌──────────────────────┐
[  Info  ] ╔═╡ verification summary ╞══════════════════════════════════════════════════════════════════════════╗
[  Info  ] ║ └──────────────────────┘                                                                          ║
[  Info  ] ║ a   cast correctness                     ?:?:?        valid        U:smt-z3           0.027       ║
[  Info  ] ║ a   cast correctness                     ?:?:?        valid        U:smt-z3           0.020       ║
[  Info  ] ║ a   cast correctness                     ?:?:?        valid        U:smt-z3           0.031       ║
[  Info  ] ║ a   postcondition                        ?:?:?        valid        U:smt-z3           0.352       ║
[  Info  ] ║ b   cast correctness                     ?:?:?        valid        U:smt-z3           0.034       ║
[  Info  ] ║ b   cast correctness                     ?:?:?        valid        U:smt-z3           0.023       ║
[  Info  ] ║ b   cast correctness                     ?:?:?        valid        U:smt-z3           0.033       ║
[  Info  ] ║ b   postcondition                        ?:?:?        valid        U:smt-z3           0.056       ║
[  Info  ] ╟┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╢
[  Info  ] ║ total: 8      valid: 8    (0 from cache)   invalid: 0      unknown: 0     time:   0.576           ║
[  Info  ] ╚═══════════════════════════════════════════════════════════════════════════════════════════════════╝
[  Info  ] Shutting down executor service.

Unsound result with quantifiers

Stainless/Inox sometimes (about once every two runs) returns "valid" for the assert(false).

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

import scala.language.postfixOps

object SometimesUnsound {

  def largerThan2(rs: Mapping[BigInt,R], i: BigInt, n: BigInt) = {
    (0 <= i && i < n) ==> {
      rs(i).x >= 2
    }
  }
  
  case class R(x: BigInt, m: Mapping[BigInt,Boolean])

  case class C(var rs: Mapping[BigInt, R], var n: BigInt) {
  
    def addR_aux(b: BigInt) {
      val r = R(b, Mapping.constantMapping(false))
      
      rs = rs.updated(n,r)
      n = n + 1
    }

    def addR(b: BigInt) = {
      require(n >= 0 && forall { (i: BigInt) => largerThan2(rs,i,n) })
      
      addR_aux(b)
      
      assert(forall { (i: BigInt) => largerThan2(rs,i,n) })
      assert(largerThan2(rs,n-1,n))
      assert(false)
    }
  }
  
}

case class Mapping[A,B](f: A => B) {
  def apply(k: A): B = {
    f(k)
  }
  
  def updated(k: A, v: B) = {
    Mapping((x: A) => if (x == k) v else f(x))
  }
}

object Mapping {
  def constantMapping[A,B](b: B): Mapping[A,B] = Mapping((x: A) => b)
}

(Inox Related) Soundness issue with quantifiers

In this file, stainless/inox reports that the post-condition of euclid_onestep is valid.
This says that if r2 divides b, then r2 is smaller than r (where r is the gcd of a and b).
(A counter-example is a = 2, b = 3, r = 1, r2 = 3)

I perhaps made a mistake in some of the conditions?

import stainless.lang._
import stainless.lang.synthesis._

object Soundness2 {

  @inline
  def exists[T](p: T => Boolean) = ! forall((x: T) => !p(x))

  def divides(x: BigInt, y: BigInt) = {
    exists ((k: BigInt) => y == k*x)
  }
  
  def elimination_exists[T](p: T => Boolean): T = {
    require(exists ((e: T) => p(e)))
    
    choose((e: T) => p(e))
  } ensuring(p)
  
  
  def smallerDivider(r2: BigInt, r: BigInt, a: BigInt, b: BigInt) = {
    (divides(r2,a) && divides(r2,b)) ==> r2 <= r
  }
  
  def gcd(a: BigInt, b: BigInt, r: BigInt) = {
    divides(r,a) && divides(r,b) && forall ((r2: BigInt) => smallerDivider(r2,r,a,b))
  }
  
  def euclid_onestep(a: BigInt, b: BigInt, r: BigInt, r2: BigInt) = {
    require(b > 0 && gcd(a,b,r))
    
    val ka = elimination_exists((k: BigInt) => a == k*r)
    val kb = elimination_exists((k: BigInt) => b == k*r)
    
    smallerDivider(r2,r,b,b)
    
  } holds
  
}

Error underlines wrong line

The file Test.scala has an error on line 4 (i * "12"), but stainless displays line 5 when reporting the error.

object Test {

  def f(i: Int) = {
    i * "12"
  } // error is not here
}
$ stainless Test.scala 
[ Error  ] Test.scala:4:7: error: overloaded method value * with alternatives:
[ Error  ]   (x: Double)Double <and>
[ Error  ]   (x: Float)Float <and>
[ Error  ]   (x: Long)Long <and>
[ Error  ]   (x: Int)Int <and>
[ Error  ]   (x: Char)Int <and>
[ Error  ]   (x: Short)Int <and>
[ Error  ]   (x: Byte)Int
[ Error  ]  cannot be applied to (String)
             } // error is not here
                 ^                  

Strange behavior of lambda equality

f1 and f2 should be equal here. It looks like that the imperative cleanup transformation replaces plus(Zero(), Zero()) by u in f2. For Stainless, u and plus(Zero(), Zero()) don't have the same structure so the assertion that f1 is different than f2 succeeds.

Also, in general, don't we want (x: Nat) => plus(Zero(),Zero()) and (x: Nat) => u to be considered as the same function?

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

object Equality {
  sealed abstract class Nat
  case class Zero() extends Nat 
  case class Succ(n: Nat) extends Nat

  def plus(a: Nat, b: Nat): Nat = a match {
    case Zero() => b
    case Succ(a2) => Succ(plus(a2,b))
  }

  def theorem(a: Nat) = {
    val f1 = (x: Nat) => plus(Zero(), Zero())
    val u = plus(Zero(), Zero())
    val f2 = (x: Nat) => plus(Zero(), Zero())
    assert(f1 != f2) // VALID
  }
}

Result after transformation by imperative.cleanup, probably due to the call to simplifyLets.

def theorem(a: Nat): Unit = {
  val f1: (Nat) => Nat = (x: Nat) => plus(Zero(), Zero())
  val u: Nat = plus(Zero(), Zero())
  val f2: (Nat) => Nat = (x: Nat) => u
  assert(f1 ≠ f2)
  ()
}

Support for generic copy() method

I tried to compile Leon/Stainless code using the generic copy() method for generic case classes (see here), but it seems that it is not yet in the Stainless library. Is it possible to provide support for this construct?

Inconsistency with lambda equality

It seems there is a consistency issue with the equality used for terms, and the ones used for lambdas. In theorems, f1 and f2 are constant functions that return equal constants, so we can prove they are equal, using equalFunctions. But they are also structurally different, allowing us to assert(false).

Does Stainless use structural equality to compare lambdas? Could we use the same kind of equality across all types? Not sure what is the most appropriate definition for equality here. Do we want something extensional?

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

object Equality {
  sealed abstract class Nat
  case class Zero() extends Nat 
  case class Succ(n: Nat) extends Nat

  def plus(a: Nat, b: Nat): Nat = a match {
    case Zero() => b
    case Succ(a2) => Succ(plus(a2,b))
  }

  @induct
  def plusZero(a: Nat) = {
    plus(a, Zero()) == a
  } holds

  def equalFunctions[X,Y](y1: Y, y2: Y) = {
    require(y1 == y2)

    val f1 = (x: X) => y1
    val f2 = (x: X) => y2

    f1 == f2
  } holds

  def theorem(a: Nat) = {
    val p = plus(a, Zero())
    val f1 = (x: Nat) => a
    val f2 = (x: Nat) => p
    assert(f1 != f2)
    assert(plusZero(a))
    assert(equalFunctions(a, p))
    assert(f1 == f2)
    assert(false)
  }
}

Typing error with partial if statements

This works fine when f has type BigInt => BigInt, but doesn't work as is:

@?:? (of class inox.ast.Types$Untyped$) is unsupported by solver z3

object Untyped {

  def untyped(f: Wrap[BigInt,BigInt])  {
    if (f(0) < 0) {
      f(0)
    } 

    f(0)
  } 
}

case class Wrap[A,B](f: A => B) {
  def apply(k: A): B = {
    f(k)
  }
}

Documentation link style

As mentioned in #76 (comment)

:doc:`title <target>`

are not properly supported by GitHub. An alternative style would be welcome to make the doc easily browsable directly from this repo.

Type parameter and inheritance generate incorrect preconditions

The addition of an UNUSED type parameter in the following creates a suspicious precondition:

import stainless.collection._
import stainless.lang._

trait T[UNUSED]  {
  def pure[A](x: A): List[A]
}

class C extends T[Int] {
  def pure[A](x: A): List[A] = List(x)

  def doublePure[A](x: A) = pure(x)
}

This fails to verify with the following output:

[info] [  Info  ]  - Now considering precond. (call pure(thiss, x, A)) VC for doublePure @?:?...
[info] [ Debug  ] ({
[info] [ Debug  ]   val tp1: Type = getType(thiss)
[info] [ Debug  ]   tp1.isInstanceOf[Class]
[info] [ Debug  ] } && {
[info] [ Debug  ]   val tp1: Type = getType(thiss)
[info] [ Debug  ]   tp1.asInstanceOf[Class].id ≠ 1
[info] [ Debug  ] } && {
[info] [ Debug  ]   val tp1: Type = getType(thiss)
[info] [ Debug  ]   tp1.isInstanceOf[Bot] || (if (tp1.isInstanceOf[Class]) {
[info] [ Debug  ]     tp1.asInstanceOf[Class].id ≠ 1 && (tp1.asInstanceOf[Class].id == 7 || choose((res: Boolean) => true))
[info] [ Debug  ]   } else {
[info] [ Debug  ]     ¬tp1.isInstanceOf[Adt] && ¬tp1.isInstanceOf[Tuple] && ¬tp1.isInstanceOf[Function] && tp1 == Class(7, Nil())
[info] [ Debug  ]   })
[info] [ Debug  ] } && isInstanceOf(x, A)) ==> ({
[info] [ Debug  ]   val tp1: Type = getType(thiss)
[info] [ Debug  ]   tp1.isInstanceOf[Class] && tp1.asInstanceOf[Class].id ≠ 1 && (tp1.isInstanceOf[Bot] || (if (tp1.isInstanceOf[Class]) {
[info] [ Debug  ]     tp1.asInstanceOf[Class].id ≠ 1 && (tp1.asInstanceOf[Class].id == 7 || choose((res: Boolean) => true))
[info] [ Debug  ]   } else {
[info] [ Debug  ]     ¬tp1.isInstanceOf[Adt] && ¬tp1.isInstanceOf[Tuple] && ¬tp1.isInstanceOf[Function] && tp1 == Class(7, Nil())
[info] [ Debug  ]   }))
[info] [ Debug  ] } && isInstanceOf(x, A))
[info] [ Debug  ] Solving with: nativez3
[info] [Warning ]  => INVALID
[info] [Warning ] Found counter-example:
[info] [Warning ]   A: Type       -> Top()
[info] [Warning ]   A: Type       -> Class(3, Nil())
[info] [Warning ]   x: Object     -> Object(32)
[info] [Warning ]   thiss: Object -> Object(0)
[info] [Warning ]   
[info] [Warning ]   getType(e: Object) -> if (e == Object(32)) {
[info] [Warning ]     Class(7, Cons(Boolean(), Nil()))
[info] [Warning ]   } else if (e == Object(0)) {
[info] [Warning ]     Class(2, Nil())
[info] [Warning ]   } else {
[info] [Warning ]     choose((res: Type) => true)
[info] [Warning ]   }
...
[info] [  Info  ]   ┌──────────────────────┐
[info] [  Info  ] ╔═╡ Verification Summary ╞═══════════════════════════════════════════════════════════════════╗
[info] [  Info  ] ║ └──────────────────────┘                                                                   ║
[info] [  Info  ] ║ doublePure    choose satisfiability                    ?:?   valid     nativez3   0.012    ║
[info] [  Info  ] ║ doublePure    precond. (call pure(thiss, x, A))        ?:?   invalid   nativez3   2.196    ║
[info] [  Info  ] ║ inv           lambda precondition                      ?:?   valid     nativez3   0.205    ║
[info] [  Info  ] ║ inv           lambda precondition                      ?:?   valid     nativez3   0.015    ║
[info] [  Info  ] ║ inv           lambda precondition                      ?:?   valid     nativez3   0.014    ║
[info] [  Info  ] ║ pure          choose satisfiability                    ?:?   valid     nativez3   0.011    ║
[info] [  Info  ] ╟┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄╢
[info] [  Info  ] ║ total: 6      valid: 5      invalid: 1      unknown: 0                               2.453 ║
[info] [  Info  ] ╚════════════════════════════════════════════════════════════════════════════════════════════╝

Exception when assertion is the last statement

This fails with exception:

Exception in thread "main" inox.ast.Definitions$FunctionLookupException: Lookup failed for function with symbol assert

object Asserting {
  def f() = {
      assert(true)
  }
}

Class invariant not always verified

The class invariant "x >= 0" does not produce a VC for the assignment p.x = -1.

object ClassInvariant {
  case class Positive(var x: BigInt) {
    require(x >= 0)
  }
  
  def decrease(f: BigInt => Positive, i: BigInt) = {
    val p = f(i)
    p.x = -1
  }
}

Imperative code elimination, block lifting

import stainless.lang._

object Test {
  def falseTheorem() = {
    false 
  } holds

  def test() = {
    val x = {
      falseTheorem()
      0
    }
    false 
  } holds
}

The verification condition for the post-condition of test is:

val tmp: Boolean = falseTheorem
val x: Int = 0
false

Would it be possible to just have the last two lines, without val tmp?
This would make the invocation of falseTheorem invisible to the solver for
proving the post-condition of test.
This way, we can have more control of what is visible in the path for the solvers.

I guess this comes from the ImperativeCodeElimination trait, that lifts value outside blocks?
I'll have a look

Constructor arguments are not boxed properly during type encoding

I'm currently trying to model a typed actor system with Stainless which, as it stands now, requires me to do work with what I would express in plain Scala as a List[Foo[_]] (an existential type).

Here's a simple testcase demonstrating the few ways I tried to express it with Stainless, where methods are annotated with the errors being thrown by Stainless:

object existential {
  case class A()
  case class B()

  sealed abstract class AnyFoo
  case class Foo[T](x: T) extends AnyFoo

  def a: Foo[A] = Foo(A())
  def b: Foo[B] = Foo(B())

  def list0: List[Foo[_]] = List(a, b)
  // Exception in thread "main" stainless.frontend.UnsupportedCodeException: Could not extract type: existential.Foo[_ >: existential.B with existential.A <: Product with Serializable] (class scala.reflect.internal.Types$ExistentialType)

  def list1: List[AnyFoo] = List(a, b)
  // Exception in thread "main" stainless.frontend.UnsupportedCodeException: Could not extract type: existential.Foo[_ >: existential.B with existential.A <: Product with Serializable] (class scala.reflect.internal.Types$ExistentialType)

  def list2: List[AnyFoo] = List(a.asInstanceOf[AnyFoo], b.asInstanceOf[AnyFoo])
  // Insert lenghty inox.ast.TypeOps$TypeErrorException here
}

I get why list0 and list1 cannot be extracted successfully as we currently lack support for existential types, but I had expected list2to succeed.

As another datapoint, here's a testcase which does not involve existential types at all, where methods are again annotated with the errors being thrown:

object no_existential {
  sealed abstract class A
  case class B() extends A
  case class C() extends A

  case class Foo[+T](x: T)

  def b: Foo[B] = Foo(B())
  def c: Foo[C] = Foo(C())

  def list0: List[Foo[A]] = List(b, c)
  // Insert lengthy inox.ast.TypeOps$TypeErrorException here

  def list1: List[Foo[Any]] = List(b, c)
  // Insert lengthy inox.ast.TypeOps$TypeErrorException here

  def list3: List[Foo[A]] = List(b.asInstanceOf[Foo[A]], c.asInstanceOf[Foo[A]])
  // Insert lengthy inox.ast.TypeOps$TypeErrorException here

  def list4: List[Foo[Any]] = List(b.asInstanceOf[Foo[Any]], c.asInstanceOf[Foo[Any]])
  // Insert lengthy inox.ast.TypeOps$TypeErrorException here
}

Is there indeed a problem with the type system that makes the second testcase not type-check successfully or is that that scenerio just unsupported at the moment?

Long compilation/extraction time

I'm currently investigating stainless long compilation/extraction time. The file I'm working on is about 150 loc and takes more that 200 seconds to pass stainless' extraction (vs ~4 seconds to compile with scalac), which, due to the lack of incrementally, is currently a blocker issue that prevents me to work on the verification part of my task.

On my way through minimization, I've found something interesting that might help understand the issue. I've managed to split my file into 2 independently compiling files such that the compilation/extraction time do no compose as you would expect:

$ sbt
> stainless-scalac/run --functions=nope 1.scala
[info] Running stainless.Main --functions=nope 1.scala
[info] [  Info  ] No verification conditions were analyzed.
[success] Total time: 15 s, completed May 25, 2017 1:27:24 PM

> stainless-scalac/run --functions=nope 2.scala
[info] Running stainless.Main --functions=nope 2.scala
[info] [  Info  ] No verification conditions were analyzed.
[success] Total time: 125 s, completed May 25, 2017 1:29:39 PM

> stainless-scalac/run --functions=nope 1.scala 2.scala
[info] Running stainless.Main --functions=nope 1.scala 2.scala
[info] [  Info  ] No verification conditions were analyzed.
[success] Total time: 211 s, completed May 25, 2017 1:33:48 PM

I would expect the processing of both files at once to be faster than processing them individually, which is what happens with scalac:

$ time scalac 1.scala
real    0m2.686s
user    0m7.152s
sys     0m0.136s

$ time scalac 2.scala
real    0m3.287s
user    0m9.084s
sys     0m0.180s

$ time scalac 1.scala 2.scala
real    0m3.433s
user    0m9.616s
sys     0m0.236s

Any idea what could be causing this behavior? I've uploaded the two test files in this gist, processing these files requires cherry-picking few commits from my work in progress branch on top of master.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.