diff --git a/src/main/scala/inox/ast/Constructors.scala b/src/main/scala/inox/ast/Constructors.scala index d351540c25e9b02504623e718df4a4bb7391a507..fed2d4ce1723c20f05a622c2bfe236533ae26ad3 100644 --- a/src/main/scala/inox/ast/Constructors.scala +++ b/src/main/scala/inox/ast/Constructors.scala @@ -301,8 +301,8 @@ trait Constructors { case (_, IntegerLiteral(bi)) if bi == 0 => lhs case (IntLiteral(0), _) => rhs case (_, IntLiteral(0)) => lhs - case (FractionalLiteral(n, d), _) if n == 0 => rhs - case (_, FractionalLiteral(n, d)) if n == 0 => lhs + case (FractionLiteral(n, d), _) if n == 0 => rhs + case (_, FractionLiteral(n, d)) if n == 0 => lhs case _ => Plus(lhs, rhs) } diff --git a/src/main/scala/inox/ast/Definitions.scala b/src/main/scala/inox/ast/Definitions.scala index d7fab61eec1a2467e7af1393ee93c41059f3e076..b9b3e20067f53acdedace7eea6b634a3647eb01d 100644 --- a/src/main/scala/inox/ast/Definitions.scala +++ b/src/main/scala/inox/ast/Definitions.scala @@ -418,8 +418,8 @@ trait Definitions { self: Trees => lazy val body = fd.body map translated lazy val precondition = fd.precondition map translated lazy val precOrTrue = translated(fd.precOrTrue) - lazy val postcondition = fd.postcondition map translated - lazy val postOrTrue = translated(fd.postOrTrue) + lazy val postcondition = fd.postcondition map (p => translated(p).asInstanceOf[Lambda]) + lazy val postOrTrue = translated(fd.postOrTrue).asInstanceOf[Lambda] def hasImplementation = body.isDefined def hasBody = hasImplementation diff --git a/src/main/scala/inox/ast/ExprOps.scala b/src/main/scala/inox/ast/ExprOps.scala index 9fdc9329dc280649cfd820d6edfe2f2428c71b23..dd88569e7469f58e288ef066ed009faab0e6fd87 100644 --- a/src/main/scala/inox/ast/ExprOps.scala +++ b/src/main/scala/inox/ast/ExprOps.scala @@ -146,10 +146,10 @@ trait ExprOps extends GenTreeOps { } /** Returns the postcondition of an expression wrapped in Option */ - def postconditionOf(expr: Expr): Option[Expr] = expr match { - case Let(i, e, b) => postconditionOf(b).map(Let(i, e, _).copiedFrom(expr)) - case Ensuring(_, post) => Some(post) - case _ => None + def postconditionOf(expr: Expr): Option[Lambda] = expr match { + case Let(i, e, b) => postconditionOf(b).map(l => l.copy(body = Let(i, e, l.body)).copiedFrom(expr)) + case Ensuring(_, post: Lambda) => Some(post) + case _ => None } /** Returns a tuple of precondition, the raw body and the postcondition of an expression */ diff --git a/src/main/scala/inox/ast/Expressions.scala b/src/main/scala/inox/ast/Expressions.scala index d5d21dfbc6230907f0fbbc1d2adfec9cbb5f5c6c..472d68a17a299fc64c82d69120da0b550a611d84 100644 --- a/src/main/scala/inox/ast/Expressions.scala +++ b/src/main/scala/inox/ast/Expressions.scala @@ -3,6 +3,8 @@ package inox package ast +import scala.collection.BitSet + /** Expression definitions for Pure Scala. * * If you are looking for things such as function or class definitions, @@ -273,12 +275,14 @@ trait Expressions { self: Trees => case class UnapplyPattern(binder: Option[ValDef], id: Identifier, tps: Seq[Type], subPatterns: Seq[Pattern]) extends Pattern { // Hacky, but ok def optionType(implicit s: Symbols) = s.getFunction(id, tps).returnType.asInstanceOf[ClassType] - def someType(implicit s: Symbols): ClassType = { - val optionChildren = optionType.tcd.asInstanceOf[TypedAbstractClassDef].ccDescendants.sortBy(_.fields.size) - val someTcd = optionChildren(1) - ClassType(someTcd.id, someTcd.tps) + def optionChildren(implicit s: Symbols): (ClassType, ClassType) = { + val children = optionType.tcd.asInstanceOf[TypedAbstractClassDef].ccDescendants.sortBy(_.fields.size) + val Seq(noneType, someType) = children.map(_.toType) + (noneType, someType) } + def noneType(implicit s: Symbols): ClassType = optionChildren(s)._1 + def someType(implicit s: Symbols): ClassType = optionChildren(s)._2 def someValue(implicit s: Symbols): ValDef = someType.tcd.asInstanceOf[TypedCaseClassDef].fields.head /** Construct a pattern matching against unapply(scrut) (as an if-expression) @@ -357,14 +361,28 @@ trait Expressions { self: Trees => def getType(implicit s: Symbols): Type = CharType } - /** $encodingof a 32-bit integer literal */ - case class IntLiteral(value: Int) extends Literal[Int] { - def getType(implicit s: Symbols): Type = Int32Type - } - /** $encodingof a n-bit bitvector literal */ - case class BVLiteral(value: BigInt, size: Int) extends Literal[BigInt] { + case class BVLiteral(value: BitSet, size: Int) extends Literal[BitSet] { def getType(implicit s: Symbols): Type = BVType(size) + def toBigInt: BigInt = { + val res = value.foldLeft(BigInt(0))((res, i) => res + BigInt(2).pow(i)) + if (value(size)) BigInt(2).pow(size) - res else res + } + } + + object BVLiteral { + def apply(bi: BigInt, size: Int): BVLiteral = BVLiteral( + (1 to size).foldLeft(BitSet.empty) { case (res, i) => + if ((bi & BigInt(2).pow(i)) > 0) res + i else res + }, size) + } + + object IntLiteral { + def apply(i: Int): BVLiteral = BVLiteral(BigInt(i), 32) + def unapply(e: Expr): Option[Int] = e match { + case b @ BVLiteral(_, 32) => Some(b.toBigInt.toInt) + case _ => None + } } /** $encodingof an infinite precision integer literal */ @@ -373,7 +391,7 @@ trait Expressions { self: Trees => } /** $encodingof a fraction literal */ - case class FractionalLiteral(numerator: BigInt, denominator: BigInt) extends Literal[(BigInt, BigInt)] { + case class FractionLiteral(numerator: BigInt, denominator: BigInt) extends Literal[(BigInt, BigInt)] { val value = (numerator, denominator) def getType(implicit s: Symbols): Type = RealType } diff --git a/src/main/scala/inox/ast/Printers.scala b/src/main/scala/inox/ast/Printers.scala index 39bb9eba37b37a37a3fd9560f26cf40eaf8359bf..979cffc572ec800ba60e138a945bc8ae2c593851 100644 --- a/src/main/scala/inox/ast/Printers.scala +++ b/src/main/scala/inox/ast/Printers.scala @@ -142,8 +142,9 @@ trait Printers { self: Trees => case StringBigLength(expr) => p"$expr.bigLength" case IntLiteral(v) => p"$v" + case BVLiteral(bits, size) => p"x${(size to 1 by -1).map(i => if (bits(i)) "1" else "0")}" case IntegerLiteral(v) => p"$v" - case FractionalLiteral(n, d) => + case FractionLiteral(n, d) => if (d == 1) p"$n" else p"$n/$d" case CharLiteral(v) => p"$v" diff --git a/src/main/scala/inox/ast/SymbolOps.scala b/src/main/scala/inox/ast/SymbolOps.scala index 223d2627e4cd3fa7b7a88a5dae22b1bac6847a5b..19202719bfc7ffb22935d03379a5b7b27a1c2298 100644 --- a/src/main/scala/inox/ast/SymbolOps.scala +++ b/src/main/scala/inox/ast/SymbolOps.scala @@ -460,7 +460,7 @@ trait SymbolOps extends TreeOps { self: TypeOps => def simplestValue(tpe: Type): Expr = tpe match { case StringType => StringLiteral("") case Int32Type => IntLiteral(0) - case RealType => FractionalLiteral(0, 1) + case RealType => FractionLiteral(0, 1) case IntegerType => IntegerLiteral(0) case CharType => CharLiteral('a') case BooleanType => BooleanLiteral(false) @@ -752,36 +752,36 @@ trait SymbolOps extends TreeOps { self: TypeOps => } /** - * Some helper methods for FractionalLiterals + * Some helper methods for FractionLiterals */ - def normalizeFraction(fl: FractionalLiteral) = { - val FractionalLiteral(num, denom) = fl + def normalizeFraction(fl: FractionLiteral) = { + val FractionLiteral(num, denom) = fl val modNum = if (num < 0) -num else num val modDenom = if (denom < 0) -denom else denom val divisor = modNum.gcd(modDenom) val simpNum = num / divisor val simpDenom = denom / divisor if (simpDenom < 0) - FractionalLiteral(-simpNum, -simpDenom) + FractionLiteral(-simpNum, -simpDenom) else - FractionalLiteral(simpNum, simpDenom) + FractionLiteral(simpNum, simpDenom) } - val realzero = FractionalLiteral(0, 1) - def floor(fl: FractionalLiteral): FractionalLiteral = { - val FractionalLiteral(n, d) = normalizeFraction(fl) + val realzero = FractionLiteral(0, 1) + def floor(fl: FractionLiteral): FractionLiteral = { + val FractionLiteral(n, d) = normalizeFraction(fl) if (d == 0) throw new IllegalStateException("denominator zero") if (n == 0) realzero else if (n > 0) { //perform integer division - FractionalLiteral(n / d, 1) + FractionLiteral(n / d, 1) } else { //here the number is negative if (n % d == 0) - FractionalLiteral(n / d, 1) + FractionLiteral(n / d, 1) else { //perform integer division and subtract 1 - FractionalLiteral(n / d - 1, 1) + FractionLiteral(n / d - 1, 1) } } } @@ -991,7 +991,7 @@ trait SymbolOps extends TreeOps { self: TypeOps => case (IntLiteral(_), Int32Type) => true case (IntegerLiteral(_), IntegerType) => true case (CharLiteral(_), CharType) => true - case (FractionalLiteral(_, _), RealType) => true + case (FractionLiteral(_, _), RealType) => true case (BooleanLiteral(_), BooleanType) => true case (UnitLiteral(), UnitType) => true case (GenericValue(t, _), tp) => t == tp diff --git a/src/main/scala/inox/evaluators/ContextualEvaluator.scala b/src/main/scala/inox/evaluators/ContextualEvaluator.scala index 973483cae3813ef596c3a77689e112f3d962bfb9..fba8ac52dfc68456d48d78747636fe849ba2d15c 100644 --- a/src/main/scala/inox/evaluators/ContextualEvaluator.scala +++ b/src/main/scala/inox/evaluators/ContextualEvaluator.scala @@ -1,50 +1,51 @@ /* Copyright 2009-2016 EPFL, Lausanne */ -package leon +package inox package evaluators -import purescala.Common._ -import purescala.Definitions._ -import purescala.Expressions._ -import purescala.Types._ -import solvers.Model -import codegen.runtime.{LeonCodeGenRuntimeException, LeonCodeGenEvaluationException} +trait ContextualEvaluator extends Evaluator { + val maxSteps: Int + import program._ + import program.trees._ -abstract class ContextualEvaluator(ctx: LeonContext, prog: Program, val maxSteps: Int) extends Evaluator(ctx, prog) with CEvalHelpers { + trait RecContext[RC <: RecContext[RC]] { + def mappings: Map[ValDef, Expr] + def newVars(news: Map[ValDef, Expr]): RC + def withNewVar(vd: ValDef, expr: Expr): RC = newVars(mappings + (vd -> expr)) + def withNewVars(news: Map[ValDef, Expr]): RC = newVars(mappings ++ news) + } + + case class DefaultRecContext(mappings: Map[ValDef, Expr]) extends RecContext[DefaultRecContext] { + def newVars(news: Map[ValDef, Expr]) = copy(mappings = news) + } - protected implicit val _ = ctx + class GlobalContext(val maxSteps: Int) { + var stepsLeft = maxSteps + } type RC <: RecContext[RC] type GC <: GlobalContext - def initRC(mappings: Map[Identifier, Expr]): RC - def initGC(model: solvers.Model, check: Boolean): GC + def initRC(mappings: Map[ValDef, Expr]): RC + def initGC: GC - case class EvalError(msg : String) extends Exception { + case class EvalError(msg: String) extends Exception { override def getMessage = msg + Option(super.getMessage).map("\n" + _).getOrElse("") } - case class RuntimeError(msg : String) extends Exception + case class RuntimeError(msg: String) extends Exception case class QuantificationError(msg: String) extends Exception - // Used by leon-web, please do not delete - var lastGC: Option[GC] = None - - def eval(ex: Expr, model: Model) = { + def eval(ex: Expr, model: Map[ValDef, Expr]) = { try { - lastGC = Some(initGC(model, check = true)) ctx.timers.evaluators.recursive.runtime.start() - EvaluationResults.Successful(e(ex)(initRC(model.toMap), lastGC.get)) + EvaluationResults.Successful(e(ex)(initRC(model), initGC)) } catch { case EvalError(msg) => EvaluationResults.EvaluatorError(msg) - case ee: LeonCodeGenEvaluationException => - EvaluationResults.EvaluatorError(ee.getMessage) case so: StackOverflowError => EvaluationResults.RuntimeError("Stack overflow") case e @ RuntimeError(msg) => EvaluationResults.RuntimeError(msg) - case re: LeonCodeGenRuntimeException => - EvaluationResults.RuntimeError(re.getMessage) case jre: java.lang.RuntimeException => EvaluationResults.RuntimeError(jre.getMessage) } finally { @@ -54,68 +55,17 @@ abstract class ContextualEvaluator(ctx: LeonContext, prog: Program, val maxSteps protected def e(expr: Expr)(implicit rctx: RC, gctx: GC): Value - def typeErrorMsg(tree : Expr, expected : TypeTree) : String = s"Type error : expected ${expected.asString}, found ${tree.asString} of type ${tree.getType}." - + def typeErrorMsg(tree: Expr, expected: Type): String = s"Type error : expected ${expected.asString}, found ${tree.asString} of type ${tree.getType}." } -private[evaluators] trait CEvalHelpers { - this: ContextualEvaluator => - - /* This is an effort to generalize forall to non-det. solvers - def forallInstantiations(gctx:GC, fargs: Seq[ValDef], conj: Expr) = { - - val henkinModel: PartialModel = gctx.model match { - case hm: PartialModel => hm - case _ => throw EvalError("Can't evaluate foralls without henkin model") - } - - val vars = variablesOf(conj) - val args = fargs.map(_.id).filter(vars) - val quantified = args.toSet - - val matcherQuorums = extractQuorums(conj, quantified) - - matcherQuorums.flatMap { quorum => - var mappings: Seq[(Identifier, Int, Int)] = Seq.empty - var constraints: Seq[(Expr, Int, Int)] = Seq.empty - - for (((expr, args), qidx) <- quorum.zipWithIndex) { - val (qmappings, qconstraints) = args.zipWithIndex.partition { - case (Variable(id), aidx) => quantified(id) - case _ => false - } - - mappings ++= qmappings.map(p => (p._1.asInstanceOf[Variable].id, qidx, p._2)) - constraints ++= qconstraints.map(p => (p._1, qidx, p._2)) - } - - var equalities: Seq[((Int, Int), (Int, Int))] = Seq.empty - val mapping = for ((id, es) <- mappings.groupBy(_._1)) yield { - val base :: others = es.toList.map(p => (p._2, p._3)) - equalities ++= others.map(p => base -> p) - (id -> base) - } - - val argSets = quorum.foldLeft[List[Seq[Seq[Expr]]]](List(Seq.empty)) { - case (acc, (expr, _)) => acc.flatMap(s => henkinModel.domain(expr).map(d => s :+ d)) - } - - argSets.map { args => - val argMap: Map[(Int, Int), Expr] = args.zipWithIndex.flatMap { - case (a, qidx) => a.zipWithIndex.map { case (e, aidx) => (qidx, aidx) -> e } - }.toMap - - val map = mapping.map { case (id, key) => id -> argMap(key) } - val enabler = andJoin(constraints.map { - case (e, qidx, aidx) => Equals(e, argMap(qidx -> aidx)) - } ++ equalities.map { - case (k1, k2) => Equals(argMap(k1), argMap(k2)) - }) - - (enabler, map) - } - }*/ - - +trait HasDefaultRecContext extends ContextualEvaluator { + import program.trees._ + type RC = DefaultRecContext + def initRC(mappings: Map[ValDef, Expr]) = DefaultRecContext(mappings) +} +trait HasDefaultGlobalContext extends ContextualEvaluator { + type GC = GlobalContext + def initGC = new GlobalContext(maxSteps) } + diff --git a/src/main/scala/inox/evaluators/EvaluatorContexts.scala b/src/main/scala/inox/evaluators/EvaluatorContexts.scala deleted file mode 100644 index 859e960d5d7aadbc63de656fd3c340fbc60b30f1..0000000000000000000000000000000000000000 --- a/src/main/scala/inox/evaluators/EvaluatorContexts.scala +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright 2009-2016 EPFL, Lausanne */ - -package leon -package evaluators - -import purescala.Common.Identifier -import leon.purescala.Expressions.{Lambda, Expr} -import solvers.Model - -import scala.collection.mutable.{Map => MutableMap} - -trait RecContext[RC <: RecContext[RC]] { - def mappings: Map[Identifier, Expr] - - def newVars(news: Map[Identifier, Expr]): RC - - def withNewVar(id: Identifier, v: Expr): RC = { - newVars(mappings + (id -> v)) - } - - def withNewVars(news: Map[Identifier, Expr]): RC = { - newVars(mappings ++ news) - } -} - -case class DefaultRecContext(mappings: Map[Identifier, Expr]) extends RecContext[DefaultRecContext] { - def newVars(news: Map[Identifier, Expr]) = copy(news) -} - -class GlobalContext(val model: Model, val maxSteps: Int, val check: Boolean) { - var stepsLeft = maxSteps - - val lambdas: MutableMap[Lambda, Lambda] = MutableMap.empty -} - -trait HasDefaultRecContext extends ContextualEvaluator { - type RC = DefaultRecContext - def initRC(mappings: Map[Identifier, Expr]) = DefaultRecContext(mappings) -} - -trait HasDefaultGlobalContext extends ContextualEvaluator { - def initGC(model: solvers.Model, check: Boolean) = new GlobalContext(model, this.maxSteps, check) - type GC = GlobalContext -} \ No newline at end of file diff --git a/src/main/scala/inox/evaluators/RecursiveEvaluator.scala b/src/main/scala/inox/evaluators/RecursiveEvaluator.scala index 6838efe26ee3d36b88b8a28cef7d38c3819ce43a..d1eba7f1ed700c4d8c38fee825f566c158f5ee37 100644 --- a/src/main/scala/inox/evaluators/RecursiveEvaluator.scala +++ b/src/main/scala/inox/evaluators/RecursiveEvaluator.scala @@ -1,109 +1,31 @@ /* Copyright 2009-2016 EPFL, Lausanne */ -package leon +package inox package evaluators -import purescala.Quantification._ -import purescala.Constructors._ -import purescala.ExprOps._ -import purescala.Expressions.Pattern -import purescala.Extractors._ -import purescala.TypeOps.isSubtypeOf -import purescala.Types._ -import purescala.Common._ -import purescala.Expressions._ -import purescala.Definitions._ -import solvers.TimeoutableSolverFactory -import solvers.{PartialModel, SolverFactory} -import purescala.DefOps -import solvers.{PartialModel, Model, SolverFactory, SolverContext} -import solvers.unrolling.UnrollingProcedure -import scala.collection.mutable.{Map => MutableMap} -import scala.concurrent.duration._ -import org.apache.commons.lang3.StringEscapeUtils -import leon.purescala.TypeOps - -abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: EvaluationBank, maxSteps: Int) - extends ContextualEvaluator(ctx, prog, maxSteps) - with DeterministicEvaluator { - - def this(ctx: LeonContext, prog: Program, maxSteps: Int) = - this(ctx, prog, new EvaluationBank, maxSteps) +import scala.collection.BitSet + +trait RecursiveEvaluator + extends ContextualEvaluator + with DeterministicEvaluator + with SolvingEvaluator { + + import program._ + import program.trees._ + import program.symbols._ + import program.trees.exprOps._ val name = "evaluator" - val description = "Recursive interpreter for PureScala expressions" - - lazy val scalaEv = new ScalacEvaluator(this, ctx, prog) - - protected val clpCache = MutableMap[(Choose, Seq[Expr]), Expr]() - protected var frlCache = Map[(Forall, Seq[Expr]), Expr]() - - private var evaluationFailsOnChoose = false - /** Sets the flag if when encountering a Choose, it should fail instead of solving it. */ - def setEvaluationFailOnChoose(b: Boolean) = { this.evaluationFailsOnChoose = b; this } - - protected[evaluators] object SpecializedFunctionInvocation { - def unapply(expr: Expr)(implicit rctx: RC, gctx: GC): Option[Expr] = expr match { - case FunctionInvocation(TypedFunDef(fd, Nil), Seq(input)) if fd == program.library.escape.get => - e(input) match { - case StringLiteral(s) => - Some(StringLiteral(StringEscapeUtils.escapeJava(s))) - case _ => throw EvalError(typeErrorMsg(input, StringType)) - } - - case FunctionInvocation(TypedFunDef(fd, Seq(ta, tb)), Seq(mp, inkv, betweenkv, fk, fv)) if fd == program.library.mapMkString.get => - println("invkv") - val inkv_str = e(inkv) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(inkv, StringType)) } - println(s"invkv_str = $inkv_str") - val betweenkv_str = e(betweenkv) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(betweenkv, StringType)) } - println(s"betweenkv_str = $betweenkv_str") - val mp_map = e(mp) match { case FiniteMap(theMap, keyType, valueType) => theMap case _ => throw EvalError(typeErrorMsg(mp, MapType(ta, tb))) } - println(s"mp_map = $mp_map") - - val res = mp_map.map{ case (k, v) => - (e(application(fk, Seq(k))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) + - inkv_str + - (v match { - case CaseClass(some, Seq(v)) if some == program.library.Some.get.typed(Seq(tb)) => - (e(application(fv, Seq(v))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) - case CaseClass(t, _) if TypeOps.isSubtypeOf(t, tb) => - (e(application(fv, Seq(v))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) - case _ => throw EvalError(typeErrorMsg(v, program.library.Some.get.typed(Seq(tb)))) - })}.toList.sorted.mkString(betweenkv_str) - - Some(StringLiteral(res)) - - case FunctionInvocation(TypedFunDef(fd, Seq(ta)), Seq(mp, inf, f)) if fd == program.library.setMkString.get => - val inf_str = e(inf) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(inf, StringType)) } - val mp_set = e(mp) match { case FiniteSet(elems, valueType) => elems case _ => throw EvalError(typeErrorMsg(mp, SetType(ta))) } - - val res = mp_set.map{ case v => - e(application(f, Seq(v))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(v, StringType)) } }.toList.sorted.mkString(inf_str) - - Some(StringLiteral(res)) - - case FunctionInvocation(TypedFunDef(fd, Seq(ta)), Seq(mp, inf, f)) if fd == program.library.bagMkString.get => - val inf_str = e(inf) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(inf, StringType)) } - val mp_bag = e(mp) match { case FiniteBag(elems, valueType) => elems case _ => throw EvalError(typeErrorMsg(mp, SetType(ta))) } - - val res = mp_bag.flatMap{ case (k, v) => - val fk = (e(application(f, Seq(k))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) - val times = (e(v)) match { case InfiniteIntegerLiteral(i) => i case _ => throw EvalError(typeErrorMsg(k, IntegerType)) } - List.range(1, times.toString.toInt).map(_ => fk) - }.toList.sorted.mkString(inf_str) - - Some(StringLiteral(res)) - case _ => None - } - } - + val description = "Recursive interpreter for Inox expressions" + + private def shift(b: BitSet, size: Int, i: Int): BitSet = + b.map(_ + i).filter(bit => bit >= 1 && bit <= size) + protected[evaluators] def e(expr: Expr)(implicit rctx: RC, gctx: GC): Expr = expr match { - case Variable(id) => - rctx.mappings.get(id) match { - case Some(v) => - v - case None => - throw EvalError("No value for identifier " + id.asString + " in mapping " + rctx.mappings) + case v: Variable => + rctx.mappings.get(v.toVal) match { + case Some(v) => v + case None => throw EvalError("No value for variable " + v.asString + " in mapping " + rctx.mappings) } case Application(caller, args) => @@ -112,10 +34,6 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva val newArgs = args.map(e) val mapping = l.paramSubst(newArgs) e(body)(rctx.withNewVars(mapping), gctx) - case FiniteLambda(mapping, dflt, _) => - mapping.find { case (pargs, res) => - (args zip pargs).forall(p => e(Equals(p._1, p._2)) == BooleanLiteral(true)) - }.map(_._2).getOrElse(dflt) case f => throw EvalError("Cannot apply non-lambda function " + f.asString) } @@ -150,32 +68,19 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case _ => throw EvalError(typeErrorMsg(first, BooleanType)) } - case FunctionInvocation(TypedFunDef(fd, Seq(tp)), Seq(set)) if fd == program.library.setToList.get => - val els = e(set) match { - case FiniteSet(els, _) => els - case _ => throw EvalError(typeErrorMsg(set, SetType(tp))) - } - val cons = program.library.Cons.get - val nil = CaseClass(CaseClassType(program.library.Nil.get, Seq(tp)), Seq()) - def mkCons(h: Expr, t: Expr) = CaseClass(CaseClassType(cons, Seq(tp)), Seq(h,t)) - els.foldRight(nil)(mkCons) - - case SpecializedFunctionInvocation(result) => result - - case FunctionInvocation(tfd, args) => + case FunctionInvocation(id, tps, args) => if (gctx.stepsLeft < 0) { throw RuntimeError("Exceeded number of allocated methods calls ("+gctx.maxSteps+")") } gctx.stepsLeft -= 1 + val tfd = getFunction(id, tps) val evArgs = args map e - //println(s"calling ${tfd.id} with $evArgs") - // build a mapping for the function... val frame = rctx.withNewVars(tfd.paramSubst(evArgs)) - if(tfd.hasPrecondition) { + if (tfd.hasPrecondition) { e(tfd.precondition.get)(frame, gctx) match { case BooleanLiteral(true) => case BooleanLiteral(false) => @@ -185,18 +90,18 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva } } - val callResult = if (tfd.fd.annotations("extern") && ctx.classDir.isDefined) { - scalaEv.call(tfd, evArgs) - } else { - if(!tfd.hasBody && !rctx.mappings.isDefinedAt(tfd.id)) { - throw EvalError("Evaluation of function with unknown implementation." + expr) - } + // @nv TODO: choose evaluation - val body = tfd.body.getOrElse(rctx.mappings(tfd.id)) - e(body)(frame, gctx) + /* @nv TODO: should we do this differently?? lambdas?? + if (!tfd.hasBody && !rctx.mappings.isDefinedAt(tfd.id)) { + throw EvalError("Evaluation of function with unknown implementation." + expr) } + */ - //println(s"Gave $callResult") + val callResult: Expr = tfd.body match { + case Some(body) => e(body)(frame, gctx) + case None => onSpecInvocation(tfd.postOrTrue) + } tfd.postcondition match { case Some(post) => @@ -210,25 +115,31 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva callResult - case And(args) if args.isEmpty => BooleanLiteral(true) + case And(Seq(e1, e2)) => + (e(e1), e(e2)) match { + case (BooleanLiteral(b1), BooleanLiteral(b2)) => BooleanLiteral(b1 && b2) + case (BVLiteral(i1, s1), BVLiteral(i2, s2)) if s1 == s2 => BVLiteral(i1 & i2, s1) + case (le, re) => throw EvalError("Unexpected operation: (" + le.asString + ") && (" + re.asString + ")") + } + case And(args) => - e(args.head) match { - case BooleanLiteral(false) => BooleanLiteral(false) - case BooleanLiteral(true) => e(andJoin(args.tail)) - case other => throw EvalError(typeErrorMsg(other, BooleanType)) + e(And(args.head, e(And(args.tail)))) + + case Or(Seq(e1, e2)) => + (e(e1), e(e2)) match { + case (BooleanLiteral(b1), BooleanLiteral(b2)) => BooleanLiteral(b1 || b2) + case (BVLiteral(i1, s1), BVLiteral(i2, s2)) if s1 == s2 => BVLiteral(i1 | i2, s1) + case (le, re) => throw EvalError("Unexpected operation: (" + le.asString + ") || (" + re.asString + ")") } - case Or(args) if args.isEmpty => BooleanLiteral(false) case Or(args) => - e(args.head) match { - case BooleanLiteral(true) => BooleanLiteral(true) - case BooleanLiteral(false) => e(orJoin(args.tail)) - case other => throw EvalError(typeErrorMsg(other, BooleanType)) - } + e(Or(args.head, e(Or(args.tail)))) case Not(arg) => e(arg) match { case BooleanLiteral(v) => BooleanLiteral(!v) + case BVLiteral(bs, s) => + BVLiteral(BitSet.empty ++ (1 to s).flatMap(i => if (bs(i)) None else Some(i)), s) case other => throw EvalError(typeErrorMsg(other, BooleanType)) } @@ -244,24 +155,32 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva val rv = e(re) (lv,rv) match { - case (FiniteSet(el1, _),FiniteSet(el2, _)) => BooleanLiteral(el1 == el2) - case (FiniteBag(el1, _),FiniteBag(el2, _)) => BooleanLiteral(el1 == el2) - case (FiniteMap(el1, _, _),FiniteMap(el2, _, _)) => BooleanLiteral(el1.toSet == el2.toSet) - case (FiniteLambda(m1, d1, _), FiniteLambda(m2, d2, _)) => BooleanLiteral(m1.toSet == m2.toSet && d1 == d2) + case (FiniteSet(el1, _),FiniteSet(el2, _)) => + BooleanLiteral(el1.toSet == el2.toSet) + case (FiniteBag(el1, _),FiniteBag(el2, _)) => + BooleanLiteral(el1.toMap == el2.toMap) + case (FiniteMap(el1, dflt1, _),FiniteMap(el2, dflt2, _)) => + BooleanLiteral(el1.toMap == el2.toMap && dflt1 == dflt2) + case (l1: Lambda, l2: Lambda) => + val (nl1, subst1) = normalizeStructure(l1) + val (nl2, subst2) = normalizeStructure(l2) + BooleanLiteral(nl1 == nl2 && subst1.keys.toSet == subst2.keys.toSet && { + subst1.forall { case (k, v) => e(Equals(v, subst2(k))) match { + case BooleanLiteral(res) => res + case e => throw EvalError(typeErrorMsg(e, BooleanType)) + }} + }) case _ => BooleanLiteral(lv == rv) } case CaseClass(cct, args) => val cc = CaseClass(cct, args.map(e)) - val check = bank.invariantCheck(cc) - if (check.isFailure) { - throw RuntimeError("ADT invariant violation for " + cct.classDef.id.asString + " reached in evaluation.: " + cct.invariant.get.asString) - } else if (check.isRequired) { - e(FunctionInvocation(cct.invariant.get, Seq(cc))) match { - case BooleanLiteral(success) => - bank.invariantResult(cc, success) - if (!success) - throw RuntimeError("ADT invariant violation for " + cct.classDef.id.asString + " reached in evaluation.: " + cct.invariant.get.asString) + cct.tcd.invariant.foreach { tfd => + val v = Variable(FreshIdentifier("x", true), cct) + e(tfd.applied(Seq(v)))(rctx.withNewVar(v.toVal, cc), gctx) match { + case BooleanLiteral(true) => + case BooleanLiteral(false) => + throw RuntimeError("ADT invariant violation for " + cc.asString) case other => throw RuntimeError(typeErrorMsg(other, BooleanType)) } @@ -281,226 +200,197 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva BooleanLiteral(isSubtypeOf(le.getType, ct)) case CaseClassSelector(ct1, expr, sel) => - val le = e(expr) - le match { - case CaseClass(ct2, args) if ct1 == ct2 => args(ct1.classDef.selectorID2Index(sel)) - case _ => throw EvalError(typeErrorMsg(le, ct1)) + e(expr) match { + case CaseClass(ct2, args) if ct1 == ct2 => args(ct1.tcd.cd match { + case ccd: CaseClassDef => ccd.selectorID2Index(sel) + case _ => throw RuntimeError("Unexpected case class type") + }) + case le => throw EvalError(typeErrorMsg(le, ct1)) } case Plus(l,r) => (e(l), e(r)) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => InfiniteIntegerLiteral(i1 + i2) - case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) + case (BVLiteral(i1, s1), BVLiteral(i2, s2)) if s1 == s2 => BVLiteral( + (1 to s1).foldLeft((BitSet.empty, false)) { case ((res, carry), i) => + val (b1, b2) = (i1(i), i2(i)) + val nextCarry = (b1 && b2) || (b1 && carry) || (b2 && carry) + val ri = b1 ^ b2 ^ carry + (if (ri) res + i else res, nextCarry) + }._1, s1) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => IntegerLiteral(i1 + i2) + case (FractionLiteral(ln, ld), FractionLiteral(rn, rd)) => + normalizeFraction(FractionLiteral(ln * rd + rn * ld, ld * rd)) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") + (" + re.asString + ")") } case Minus(l,r) => (e(l), e(r)) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => InfiniteIntegerLiteral(i1 - i2) - case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) - } - - case RealPlus(l, r) => - (e(l), e(r)) match { - case (FractionalLiteral(ln, ld), FractionalLiteral(rn, rd)) => - normalizeFraction(FractionalLiteral(ln * rd + rn * ld, ld * rd)) - case (le, re) => throw EvalError(typeErrorMsg(le, RealType)) + case (b1: BVLiteral, b2: BVLiteral) => e(Plus(b1, UMinus(b2))) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => IntegerLiteral(i1 - i2) + case (FractionLiteral(ln, ld), FractionLiteral(rn, rd)) => + normalizeFraction(FractionLiteral(ln * rd - rn * ld, ld * rd)) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") - (" + re.asString + ")") } - case RealMinus(l,r) => - e(RealPlus(l, RealUMinus(r))) - case StringConcat(l, r) => (e(l), e(r)) match { case (StringLiteral(i1), StringLiteral(i2)) => StringLiteral(i1 + i2) case (le,re) => throw EvalError(typeErrorMsg(le, StringType)) } + case StringLength(a) => e(a) match { case StringLiteral(a) => IntLiteral(a.length) case res => throw EvalError(typeErrorMsg(res, Int32Type)) } + case StringBigLength(a) => e(a) match { - case StringLiteral(a) => InfiniteIntegerLiteral(a.length) + case StringLiteral(a) => IntegerLiteral(a.length) case res => throw EvalError(typeErrorMsg(res, IntegerType)) } + case SubString(a, start, end) => (e(a), e(start), e(end)) match { case (StringLiteral(a), IntLiteral(b), IntLiteral(c)) => StringLiteral(a.substring(b, c)) case res => throw EvalError(typeErrorMsg(res._1, StringType)) } + case BigSubString(a, start, end) => (e(a), e(start), e(end)) match { - case (StringLiteral(a), InfiniteIntegerLiteral(b), InfiniteIntegerLiteral(c)) => + case (StringLiteral(a), IntegerLiteral(b), IntegerLiteral(c)) => StringLiteral(a.substring(b.toInt, c.toInt)) case res => throw EvalError(typeErrorMsg(res._1, StringType)) } + case Int32ToString(a) => e(a) match { case IntLiteral(i) => StringLiteral(i.toString) case res => throw EvalError(typeErrorMsg(res, Int32Type)) } + case CharToString(a) => e(a) match { case CharLiteral(i) => StringLiteral(i.toString) case res => throw EvalError(typeErrorMsg(res, CharType)) } + case IntegerToString(a) => e(a) match { - case InfiniteIntegerLiteral(i) => StringLiteral(i.toString) + case IntegerLiteral(i) => StringLiteral(i.toString) case res => throw EvalError(typeErrorMsg(res, IntegerType)) } + case BooleanToString(a) => e(a) match { case BooleanLiteral(i) => StringLiteral(i.toString) case res => throw EvalError(typeErrorMsg(res, BooleanType)) } + case RealToString(a) => e(a) match { - case FractionalLiteral(n, d) => StringLiteral(n.toString + "/" + d.toString) + case FractionLiteral(n, d) => StringLiteral(n.toString + "/" + d.toString) case res => throw EvalError(typeErrorMsg(res, RealType)) } - case BVPlus(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 + i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) - } - - case BVMinus(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 - i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) - } - case UMinus(ex) => e(ex) match { - case InfiniteIntegerLiteral(i) => InfiniteIntegerLiteral(-i) - case re => throw EvalError(typeErrorMsg(re, IntegerType)) - } - - case BVUMinus(ex) => - e(ex) match { - case IntLiteral(i) => IntLiteral(-i) - case re => throw EvalError(typeErrorMsg(re, Int32Type)) - } - - case RealUMinus(ex) => - e(ex) match { - case FractionalLiteral(n, d) => FractionalLiteral(-n, d) - case re => throw EvalError(typeErrorMsg(re, RealType)) - } - - - case BVNot(ex) => - e(ex) match { - case IntLiteral(i) => IntLiteral(~i) - case re => throw EvalError(typeErrorMsg(re, Int32Type)) + case BVLiteral(b, s) => + BVLiteral((1 to s).foldLeft((BitSet.empty, false)) { case ((res, seen1), i) => + if (b(i) && seen1) (res + i, true) + else if (!seen1) (res, seen1) + else (if (!b(i)) res + i else res, seen1) + }._1, s) + case IntegerLiteral(i) => IntegerLiteral(-i) + case FractionLiteral(n, d) => FractionLiteral(-n, d) + case re => throw EvalError("Unexpected operation: -(" + re.asString + ")") } case Times(l,r) => (e(l), e(r)) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => InfiniteIntegerLiteral(i1 * i2) - case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) + case (BVLiteral(i1, s1), BVLiteral(i2, s2)) if s1 == s2 => + BVLiteral(i1.foldLeft(BitSet.empty) { case (res, i) => + res ++ shift(i2, s2, i) + }, s1) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => IntegerLiteral(i1 * i2) + case (FractionLiteral(ln, ld), FractionLiteral(rn, rd)) => + normalizeFraction(FractionLiteral((ln * rn), (ld * rd))) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") * (" + re.asString + ")") } case Division(l,r) => (e(l), e(r)) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => - if(i2 != BigInt(0)) InfiniteIntegerLiteral(i1 / i2) else throw RuntimeError("Division by 0.") - case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + val bi2 = b2.toBigInt + if (bi2 != 0) BVLiteral(b1.toBigInt / bi2, s1) else throw RuntimeError("Division by 0.") + case (IntegerLiteral(i1), IntegerLiteral(i2)) => + if(i2 != BigInt(0)) IntegerLiteral(i1 / i2) else throw RuntimeError("Division by 0.") + case (FractionLiteral(ln, ld), FractionLiteral(rn, rd)) => + if (rn != 0) + normalizeFraction(FractionLiteral(ln * rd, ld * rn)) + else throw RuntimeError("Division by 0.") + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") / (" + re.asString + ")") } case Remainder(l,r) => (e(l), e(r)) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => - if(i2 != BigInt(0)) InfiniteIntegerLiteral(i1 % i2) else throw RuntimeError("Remainder of division by 0.") - case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + val bi2 = b2.toBigInt + if (bi2 != 0) BVLiteral(b1.toBigInt % bi2, s1) else throw RuntimeError("Division by 0.") + case (IntegerLiteral(i1), IntegerLiteral(i2)) => + if(i2 != BigInt(0)) IntegerLiteral(i1 % i2) else throw RuntimeError("Remainder of division by 0.") + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") rem (" + re.asString + ")") } + case Modulo(l,r) => (e(l), e(r)) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + val bi2 = b2.toBigInt + if (bi2 < 0) + BVLiteral(b1.toBigInt mod (-bi2), s1) + else if (bi2 != 0) + BVLiteral(b1.toBigInt mod bi2, s1) + else + throw RuntimeError("Modulo of division by 0.") + case (IntegerLiteral(i1), IntegerLiteral(i2)) => if(i2 < 0) - InfiniteIntegerLiteral(i1 mod (-i2)) + IntegerLiteral(i1 mod (-i2)) else if(i2 != BigInt(0)) - InfiniteIntegerLiteral(i1 mod i2) + IntegerLiteral(i1 mod i2) else throw RuntimeError("Modulo of division by 0.") - case (le,re) => throw EvalError(typeErrorMsg(le, IntegerType)) - } - - case BVTimes(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 * i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) - } - - case BVDivision(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => - if(i2 != 0) IntLiteral(i1 / i2) else throw RuntimeError("Division by 0.") - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) - } - - case BVRemainder(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => - if(i2 != 0) IntLiteral(i1 % i2) else throw RuntimeError("Remainder of division by 0.") - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) - } - - case RealTimes(l,r) => - (e(l), e(r)) match { - case (FractionalLiteral(ln, ld), FractionalLiteral(rn, rd)) => - normalizeFraction(FractionalLiteral((ln * rn), (ld * rd))) - case (le,re) => throw EvalError(typeErrorMsg(le, RealType)) - } - - case RealDivision(l,r) => - (e(l), e(r)) match { - case (FractionalLiteral(ln, ld), FractionalLiteral(rn, rd)) => - if (rn != 0) - normalizeFraction(FractionalLiteral(ln * rd, ld * rn)) - else throw RuntimeError("Division by 0.") - case (le,re) => throw EvalError(typeErrorMsg(le, RealType)) - } - - - case BVAnd(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 & i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) - } - - case BVOr(l,r) => - (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 | i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") % (" + re.asString + ")") } case BVXOr(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 ^ i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) + case (BVLiteral(i1, s1), BVLiteral(i2, s2)) if s1 == s2 => BVLiteral(i1 ^ i2, s1) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") ^ (" + re.asString + ")") } case BVShiftLeft(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 << i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) + case (BVLiteral(i1, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + BVLiteral(shift(i1, s1, b2.toBigInt.toInt), s1) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") << (" + re.asString + ")") } case BVAShiftRight(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 >> i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) + case (BVLiteral(i1, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + val shiftCount = b2.toBigInt.toInt + val shifted = shift(i1, s1, -shiftCount) + BVLiteral(if (i1(s1)) shifted ++ ((s1 - shiftCount) to s1) else shifted, s1) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") >> (" + re.asString + ")") } case BVLShiftRight(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => IntLiteral(i1 >>> i2) - case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) + case (BVLiteral(i1, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + BVLiteral(shift(i1, s1, -b2.toBigInt.toInt), s1) + case (le,re) => throw EvalError("Unexpected operation: (" + le.asString + ") >>> (" + re.asString + ")") } case LessThan(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 < i2) - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 < i2) - case (a @ FractionalLiteral(_, _), b @ FractionalLiteral(_, _)) => - val FractionalLiteral(n, _) = e(RealMinus(a, b)) + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + BooleanLiteral(b1.toBigInt < b2.toBigInt) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => BooleanLiteral(i1 < i2) + case (a @ FractionLiteral(_, _), b @ FractionLiteral(_, _)) => + val FractionLiteral(n, _) = e(Minus(a, b)) BooleanLiteral(n < 0) case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 < c2) case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) @@ -508,10 +398,11 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case GreaterThan(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 > i2) - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 > i2) - case (a @ FractionalLiteral(_, _), b @ FractionalLiteral(_, _)) => - val FractionalLiteral(n, _) = e(RealMinus(a, b)) + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + BooleanLiteral(b1.toBigInt > b2.toBigInt) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => BooleanLiteral(i1 > i2) + case (a @ FractionLiteral(_, _), b @ FractionLiteral(_, _)) => + val FractionLiteral(n, _) = e(Minus(a, b)) BooleanLiteral(n > 0) case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 > c2) case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) @@ -519,10 +410,11 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case LessEquals(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 <= i2) - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 <= i2) - case (a @ FractionalLiteral(_, _), b @ FractionalLiteral(_, _)) => - val FractionalLiteral(n, _) = e(RealMinus(a, b)) + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + BooleanLiteral(b1.toBigInt <= b2.toBigInt) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => BooleanLiteral(i1 <= i2) + case (a @ FractionLiteral(_, _), b @ FractionLiteral(_, _)) => + val FractionLiteral(n, _) = e(Minus(a, b)) BooleanLiteral(n <= 0) case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 <= c2) case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) @@ -530,10 +422,11 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case GreaterEquals(l,r) => (e(l), e(r)) match { - case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 >= i2) - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 >= i2) - case (a @ FractionalLiteral(_, _), b @ FractionalLiteral(_, _)) => - val FractionalLiteral(n, _) = e(RealMinus(a, b)) + case (b1 @ BVLiteral(_, s1), b2 @ BVLiteral(_, s2)) if s1 == s2 => + BooleanLiteral(b1.toBigInt >= b2.toBigInt) + case (IntegerLiteral(i1), IntegerLiteral(i2)) => BooleanLiteral(i1 >= i2) + case (a @ FractionLiteral(_, _), b @ FractionLiteral(_, _)) => + val FractionLiteral(n, _) = e(Minus(a, b)) BooleanLiteral(n >= 0) case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 >= c2) case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type)) @@ -541,7 +434,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case SetAdd(s1, elem) => (e(s1), e(elem)) match { - case (FiniteSet(els1, tpe), evElem) => FiniteSet(els1 + evElem, tpe) + case (FiniteSet(els1, tpe), evElem) => FiniteSet((els1 :+ evElem).distinct, tpe) case (le, re) => throw EvalError(typeErrorMsg(le, s1.getType)) } @@ -559,7 +452,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case SetDifference(s1,s2) => (e(s1), e(s2)) match { - case (FiniteSet(els1, tpe), FiniteSet(els2, _)) => FiniteSet(els1 -- els2, tpe) + case (FiniteSet(els1, tpe), FiniteSet(els2, _)) => FiniteSet((els1.toSet -- els2).toSeq, tpe) case (le,re) => throw EvalError(typeErrorMsg(le, s1.getType)) } @@ -569,273 +462,101 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva } case SubsetOf(s1,s2) => (e(s1), e(s2)) match { - case (FiniteSet(els1, _),FiniteSet(els2, _)) => BooleanLiteral(els1.subsetOf(els2)) + case (FiniteSet(els1, _),FiniteSet(els2, _)) => BooleanLiteral(els1.toSet.subsetOf(els2.toSet)) case (le,re) => throw EvalError(typeErrorMsg(le, s1.getType)) } case SetCardinality(s) => val sr = e(s) sr match { - case FiniteSet(els, _) => InfiniteIntegerLiteral(els.size) + case FiniteSet(els, _) => IntegerLiteral(els.size) case _ => throw EvalError(typeErrorMsg(sr, SetType(Untyped))) } case f @ FiniteSet(els, base) => - FiniteSet(els.map(e), base) + FiniteSet(els.map(e).distinct, base) case BagAdd(bag, elem) => (e(bag), e(elem)) match { - case (FiniteBag(els, tpe), evElem) => FiniteBag(els + (evElem -> (els.get(evElem) match { - case Some(InfiniteIntegerLiteral(i)) => InfiniteIntegerLiteral(i + 1) - case Some(i) => throw EvalError(typeErrorMsg(i, IntegerType)) - case None => InfiniteIntegerLiteral(1) - })), tpe) + case (FiniteBag(els, tpe), evElem) => + val (matching, rest) = els.partition(_._1 == evElem) + FiniteBag(rest :+ (evElem -> matching.lastOption.map { + case (_, IntegerLiteral(i)) => IntegerLiteral(i + 1) + case (_, e) => throw EvalError(typeErrorMsg(e, IntegerType)) + }.getOrElse(IntegerLiteral(1))), tpe) case (le, re) => throw EvalError(typeErrorMsg(le, bag.getType)) } case MultiplicityInBag(elem, bag) => (e(elem), e(bag)) match { - case (evElem, FiniteBag(els, tpe)) => els.getOrElse(evElem, InfiniteIntegerLiteral(0)) + case (evElem, FiniteBag(els, tpe)) => + els.collect { case (k,v) if k == evElem => v }.lastOption.getOrElse(IntegerLiteral(0)) case (le, re) => throw EvalError(typeErrorMsg(re, bag.getType)) } case BagIntersection(b1, b2) => (e(b1), e(b2)) match { - case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => FiniteBag(els1.flatMap { case (k, v) => - val i = (v, els2.getOrElse(k, InfiniteIntegerLiteral(0))) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => i1 min i2 - case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType)) - } + case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => + val map2 = els2.toMap + FiniteBag(els1.flatMap { case (k, v) => + val i = (v, map2.getOrElse(k, IntegerLiteral(0))) match { + case (IntegerLiteral(i1), IntegerLiteral(i2)) => i1 min i2 + case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType)) + } - if (i <= 0) None else Some(k -> InfiniteIntegerLiteral(i)) - }, tpe) + if (i <= 0) None else Some(k -> IntegerLiteral(i)) + }, tpe) case (le, re) => throw EvalError(typeErrorMsg(le, b1.getType)) } case BagUnion(b1, b2) => (e(b1), e(b2)) match { - case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => FiniteBag((els1.keys ++ els2.keys).toSet.map { (k: Expr) => - k -> ((els1.getOrElse(k, InfiniteIntegerLiteral(0)), els2.getOrElse(k, InfiniteIntegerLiteral(0))) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => InfiniteIntegerLiteral(i1 + i2) - case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType)) - }) - }.toMap, tpe) + case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => + val (map1, map2) = (els1.toMap, els2.toMap) + FiniteBag((map1.keys ++ map2.keys).toSet.map { (k: Expr) => + k -> ((map1.getOrElse(k, IntegerLiteral(0)), map2.getOrElse(k, IntegerLiteral(0))) match { + case (IntegerLiteral(i1), IntegerLiteral(i2)) => IntegerLiteral(i1 + i2) + case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType)) + }) + }.toSeq, tpe) case (le, re) => throw EvalError(typeErrorMsg(le, b1.getType)) } case BagDifference(b1, b2) => (e(b1), e(b2)) match { - case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => FiniteBag(els1.flatMap { case (k, v) => - val i = (v, els2.getOrElse(k, InfiniteIntegerLiteral(0))) match { - case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => i1 - i2 - case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType)) - } + case (FiniteBag(els1, tpe), FiniteBag(els2, _)) => + val map2 = els2.toMap + FiniteBag(els1.flatMap { case (k, v) => + val i = (v, map2.getOrElse(k, IntegerLiteral(0))) match { + case (IntegerLiteral(i1), IntegerLiteral(i2)) => i1 - i2 + case (le, re) => throw EvalError(typeErrorMsg(le, IntegerType)) + } - if (i <= 0) None else Some(k -> InfiniteIntegerLiteral(i)) - }, tpe) + if (i <= 0) None else Some(k -> IntegerLiteral(i)) + }, tpe) case (le, re) => throw EvalError(typeErrorMsg(le, b1.getType)) } case FiniteBag(els, base) => - FiniteBag(els.map{ case (k, v) => (e(k), e(v)) }, base) + // we use toMap.toSeq to reduce dupplicate keys + FiniteBag(els.map { case (k, v) => (e(k), e(v)) }.toMap.toSeq, base) case l @ Lambda(_, _) => - val mapping = variablesOf(l).map(id => id -> e(Variable(id))).toMap - replaceFromIDs(mapping, l).asInstanceOf[Lambda] - - case FiniteLambda(mapping, dflt, tpe) => - FiniteLambda(mapping.map(p => p._1.map(e) -> e(p._2)), e(dflt), tpe) - - case f @ Forall(fargs, body) => + val mapping = variablesOf(l).map(v => v -> e(v)).toMap + replaceFromSymbols(mapping, l).asInstanceOf[Lambda] - implicit val debugSection = utils.DebugSectionVerification + case f: Forall => onForallInvocation(f) - ctx.reporter.debug("Executing forall: " + f.asString) - - val mapping = variablesOf(f).map(id => id -> rctx.mappings(id)).toMap - val context = mapping.toSeq.sortBy(_._1.uniqueName).map(_._2) - - frlCache.getOrElse((f, context), { - val tStart = System.currentTimeMillis - - val newOptions = Seq( - LeonOption(UnrollingProcedure.optFeelingLucky)(false), - LeonOption(UnrollingProcedure.optSilentErrors)(true), - LeonOption(UnrollingProcedure.optCheckModels)(true) - ) - - val newCtx = ctx.copy(options = ctx.options.filterNot { opt => - newOptions.exists(no => opt.optionDef == no.optionDef) - } ++ newOptions) - - val sctx = SolverContext(newCtx, bank) - val solverf = SolverFactory.getFromSettings(sctx, program).withTimeout(1.second) - val solver = solverf.getNewSolver() - - try { - val cnstr = Not(replaceFromIDs(mapping, body)) - solver.assertCnstr(cnstr) - - gctx.model match { - case pm: PartialModel => - val quantifiers = fargs.map(_.id).toSet - val quorums = extractQuorums(body, quantifiers) - - val domainCnstr = orJoin(quorums.map { quorum => - val quantifierDomains = quorum.flatMap { case (path, caller, args) => - val domain = pm.domains.get(e(caller)) - args.zipWithIndex.flatMap { - case (Variable(id),idx) if quantifiers(id) => - Some(id -> domain.map(cargs => path -> cargs(idx))) - case _ => None - } - } - - val domainMap = quantifierDomains.groupBy(_._1).mapValues(_.map(_._2).flatten) - andJoin(domainMap.toSeq.map { case (id, dom) => - orJoin(dom.toSeq.map { case (path, value) => - // @nv: Equality with variable is ok, see [[leon.codegen.runtime.Monitor]] - path and Equals(Variable(id), value) - }) - }) - }) - - solver.assertCnstr(domainCnstr) - - case _ => - } - - solver.check match { - case Some(negRes) => - val total = System.currentTimeMillis-tStart - val res = BooleanLiteral(!negRes) - ctx.reporter.debug("Verification took "+total+"ms") - ctx.reporter.debug("Finished forall evaluation with: "+res) - - frlCache += (f, context) -> res - res - case _ => - throw RuntimeError("Timeout exceeded") - } - } catch { - case e: Throwable => - throw EvalError("Runtime verification of forall failed: "+e.getMessage) - } finally { - solverf.reclaim(solver) - solverf.shutdown() - } - }) - - case ArrayLength(a) => - val FiniteArray(_, _, IntLiteral(length)) = e(a) - IntLiteral(length) - - case ArrayUpdated(a, i, v) => - val ra = e(a) - val ri = e(i) - val rv = e(v) - - val IntLiteral(index) = ri - val FiniteArray(elems, default, length) = ra - val ArrayType(tp) = ra.getType - finiteArray(elems.updated(index, rv), default map { (_, length) }, tp) - - case ArraySelect(a, i) => - val IntLiteral(index) = e(i) - val FiniteArray(elems, default, _) = e(a) - try { - elems.get(index).orElse(default).get - } catch { - case e : IndexOutOfBoundsException => throw RuntimeError(e.getMessage) - } - - case f @ FiniteArray(elems, default, length) => - val ArrayType(tp) = f.getType - finiteArray( - elems.map(el => (el._1, e(el._2))), - default.map{ d => (e(d), e(length)) }, - tp - ) - - case f @ FiniteMap(ss, kT, vT) => - FiniteMap(ss.map{ case (k, v) => (e(k), e(v)) }, kT, vT) + case f @ FiniteMap(ss, dflt, vT) => + // we use toMap.toSeq to reduce dupplicate keys + FiniteMap(ss.map{ case (k, v) => (e(k), e(v)) }.toMap.toSeq, e(dflt), vT) case g @ MapApply(m,k) => (e(m), e(k)) match { case (FiniteMap(ss, _, _), e) => - ss.getOrElse(e, throw RuntimeError("Key not found: " + e.asString)) + ss.toMap.getOrElse(e, throw RuntimeError("Key not found: " + e.asString)) case (l,r) => throw EvalError(typeErrorMsg(l, MapType(r.getType, g.getType))) } - case u @ MapUnion(m1,m2) => (e(m1), e(m2)) match { - case (f1@FiniteMap(ss1, _, _), FiniteMap(ss2, _, _)) => - val newSs = ss1 ++ ss2 - val MapType(kT, vT) = u.getType - FiniteMap(newSs, kT, vT) - case (l, r) => - throw EvalError(typeErrorMsg(l, m1.getType)) - } - - case i @ MapIsDefinedAt(m,k) => (e(m), e(k)) match { - case (FiniteMap(ss, _, _), e) => BooleanLiteral(ss.contains(e)) - case (l, r) => throw EvalError(typeErrorMsg(l, m.getType)) - } - - case p : Passes => - e(p.asConstraint) - - case choose: Choose => - if(evaluationFailsOnChoose) { - throw EvalError("Evaluator set to not solve choose constructs") - } - - implicit val debugSection = utils.DebugSectionSynthesis - - val p = synthesis.Problem.fromSpec(choose.pred) - - ctx.reporter.debug("Executing choose!") - - val ins = p.as.map(rctx.mappings(_)) - - clpCache.getOrElse((choose, ins), { - val tStart = System.currentTimeMillis - - val sctx = SolverContext(ctx, bank) - val solverf = SolverFactory.getFromSettings(sctx, program).withTimeout(1.seconds) - val solver = solverf.getNewSolver() - - try { - val cnstr = p.pc withBindings p.as.map(id => id -> rctx.mappings(id)) and p.phi - solver.assertCnstr(cnstr) - - solver.check match { - case Some(true) => - val model = solver.getModel - - val valModel = valuateWithModel(model) _ - - val res = p.xs.map(valModel) - val leonRes = tupleWrap(res) - val total = System.currentTimeMillis-tStart - - ctx.reporter.debug("Synthesis took "+total+"ms") - ctx.reporter.debug("Finished synthesis with "+leonRes.asString) - - clpCache += (choose, ins) -> leonRes - leonRes - case Some(false) => - throw RuntimeError("Constraint is UNSAT") - case _ => - throw RuntimeError("Timeout exceeded") - } - } catch { - case e: Throwable => - throw EvalError("Runtime synthesis of choose failed: "+e.getMessage) - } finally { - solverf.reclaim(solver) - solverf.shutdown() - } - }) - case MatchExpr(scrut, cases) => val rscrut = e(scrut) cases.toStream.map(c => matchesCase(rscrut, c)).find(_.nonEmpty) match { @@ -845,21 +566,17 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva throw RuntimeError("MatchError: "+rscrut.asString+" did not match any of the cases:\n"+cases) } - case synthesis.utils.MutableExpr(ex) => - e(ex) - case gl: GenericValue => gl - case fl : FractionalLiteral => normalizeFraction(fl) + case fl : FractionLiteral => normalizeFraction(fl) case l : Literal[_] => l case other => throw EvalError("Unhandled case in Evaluator : [" + other.getClass + "] " + other.asString) } - def matchesCase(scrut: Expr, caze: MatchCase)(implicit rctx: RC, gctx: GC): Option[(MatchCase, Map[Identifier, Expr])] = { - import purescala.TypeOps.isSubtypeOf + def matchesCase(scrut: Expr, caze: MatchCase)(implicit rctx: RC, gctx: GC): Option[(MatchCase, Map[ValDef, Expr])] = { - def matchesPattern(pat: Pattern, expr: Expr): Option[Map[Identifier, Expr]] = (pat, expr) match { + def matchesPattern(pat: Pattern, expr: Expr): Option[Map[ValDef, Expr]] = (pat, expr) match { case (InstanceOfPattern(ob, pct), e) => if (isSubtypeOf(e.getType, pct)) { Some(obind(ob, e)) @@ -880,11 +597,14 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva } else { None } - case (up @ UnapplyPattern(ob, _, subs), scrut) => - e(functionInvocation(up.unapplyFun.fd, Seq(scrut))) match { - case CaseClass(CaseClassType(cd, _), Seq()) if cd == program.library.None.get => + case (up @ UnapplyPattern(ob, id, tps, subs), scrut) => + val tfd = getFunction(id, tps) + val (noneType, someType) = up.optionChildren + + e(FunctionInvocation(id, tps, Seq(scrut))) match { + case CaseClass(`noneType`, Seq()) => None - case CaseClass(CaseClassType(cd, _), Seq(arg)) if cd == program.library.Some.get => + case CaseClass(`someType`, Seq(arg)) => val res = subs zip unwrapTuple(arg, subs.size) map { case (s,a) => matchesPattern(s,a) } @@ -894,7 +614,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva None } case other => - throw EvalError(typeErrorMsg(other, up.unapplyFun.returnType)) + throw EvalError(typeErrorMsg(other, tfd.returnType)) } case (TuplePattern(ob, subs), Tuple(args)) => if (subs.size == args.size) { @@ -912,8 +632,8 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case _ => None } - def obind(ob: Option[Identifier], e: Expr): Map[Identifier, Expr] = { - Map[Identifier, Expr]() ++ ob.map(id => id -> e) + def obind(ovd: Option[ValDef], e: Expr): Map[ValDef, Expr] = { + ovd.map(vd => vd -> e).toMap } caze match { diff --git a/src/main/scala/inox/evaluators/SolvingEvaluator.scala b/src/main/scala/inox/evaluators/SolvingEvaluator.scala index 9b5aee6aeb2cd97ce74c1f7f0439ccec02b0a124..267328f68f2a14e886d11f8071889840f7821d30 100644 --- a/src/main/scala/inox/evaluators/SolvingEvaluator.scala +++ b/src/main/scala/inox/evaluators/SolvingEvaluator.scala @@ -8,6 +8,9 @@ import solvers._ import scala.collection.mutable.{Map => MutableMap} trait SolvingEvaluator extends Evaluator { + import program._ + import program.trees._ + import program.symbols._ object optForallCache extends InoxOptionDef[MutableMap[program.trees.Forall, Boolean]] { val parser = { (_: String) => throw FatalError("Unparsable option \"bankOption\"") } @@ -18,34 +21,25 @@ trait SolvingEvaluator extends Evaluator { } def getSolver(opts: InoxOption[Any]*): Solver { val program: SolvingEvaluator.this.program.type } -} - -trait SolvingEvalInterface { - val program: Program - import program._ - import program.trees._ - import program.symbols._ - - val evaluator: DeterministicEvaluator with SolvingEvaluator { val program: SolvingEvalInterface.this.program.type } private val specCache: MutableMap[Expr, Expr] = MutableMap.empty private val forallCache: MutableMap[Forall, Expr] = MutableMap.empty - def onSpecInvocation(specs: Expr): Expr = specCache.getOrElseUpdate(specs, { - val Seq(free) = exprOps.variablesOf(specs).toSeq + def onSpecInvocation(specs: Lambda): Expr = specCache.getOrElseUpdate(specs, { + val Lambda(Seq(vd), body) = specs val timer = ctx.timers.evaluators.specs.start() - val solver = evaluator.getSolver(evaluator.options.options.collect { - case o @ InoxOption(opt, _) if opt == evaluator.optForallCache => o + val solver = getSolver(options.options.collect { + case o @ InoxOption(opt, _) if opt == optForallCache => o }.toSeq : _*) - solver.assertCnstr(specs) + solver.assertCnstr(body) val res = solver.check(model = true) timer.stop() res match { case solver.Model(model) => - valuateWithModel(model)(free.toVal) + valuateWithModel(model)(vd) case _ => throw new RuntimeException("Failed to evaluate specs " + specs.asString) @@ -53,17 +47,17 @@ trait SolvingEvalInterface { }) def onForallInvocation(forall: Forall): Expr = { - val cache = evaluator.options.findOption(evaluator.optForallCache).getOrElse { + val cache = options.findOption(optForallCache).getOrElse { throw new RuntimeException("Couldn't find evaluator's forall cache") } BooleanLiteral(cache.getOrElse(forall, { val timer = ctx.timers.evaluators.forall.start() - val solver = evaluator.getSolver( + val solver = getSolver( InoxOption(optSilentErrors)(true), InoxOption(optCheckModels)(false), - InoxOption(evaluator.optForallCache)(cache) + InoxOption(optForallCache)(cache) ) solver.assertCnstr(Not(forall.body)) @@ -77,7 +71,7 @@ trait SolvingEvalInterface { case solver.Model(model) => cache(forall) = false - evaluator.eval(Not(forall.body), model) match { + eval(Not(forall.body), model) match { case EvaluationResults.Successful(BooleanLiteral(true)) => false case _ => throw new RuntimeException("Forall model check failed") } @@ -88,3 +82,4 @@ trait SolvingEvalInterface { })) } } +