diff --git a/src/purescala/Analysis.scala b/src/purescala/Analysis.scala index 4ebb7c93d233850e28f9db78e8e562b867a23e11..19cc7e932be34bd2fb7a4aa9baa900dba17e6801 100644 --- a/src/purescala/Analysis.scala +++ b/src/purescala/Analysis.scala @@ -68,19 +68,23 @@ class Analysis(val program: Program) { if(vc != BooleanLiteral(true)) { reporter.info("Verification condition (post) for " + funDef.id + ":") reporter.info(vc) - - if(Settings.runDefaultExtensions) { - } + // reporter.info("Negated:") + // reporter.info(negate(vc)) + // reporter.info("Negated, expanded:") + // reporter.info(expandLets(negate(vc))) // try all solvers until one returns a meaningful answer solverExtensions.find(se => { - reporter.info("Trying with solver: " + se.description) + reporter.info("Trying with solver: " + se.shortDescription) se.solve(vc) match { - case None => reporter.warning("UNKNOWN"); false + case None => false case Some(true) => reporter.info("VALID"); true case Some(false) => reporter.error("INVALID"); true } - }) + }) match { + case None => reporter.warning("No solver could prove or disprove the verification condition.") + case _ => + } } } else { if(funDef.postcondition.isDefined) { @@ -107,6 +111,16 @@ class Analysis(val program: Program) { } def rewritePatternMatching(expr: Expr) : Expr = { - expr + def isPMExpr(e: Expr) : Boolean = e match { + case MatchExpr(_, _) => true + case _ => false + } + + def rewritePM(e: Expr) : Expr = e match { + case m @ MatchExpr(_, _) => m + case _ => e + } + + replace(isPMExpr, rewritePM, expr) } } diff --git a/src/purescala/Extensions.scala b/src/purescala/Extensions.scala index b57f61a7b06f5f9add948d50adc8f208c0c36080..21d59ebc110d565bdb529d2ad965d3794b470d65 100644 --- a/src/purescala/Extensions.scala +++ b/src/purescala/Extensions.scala @@ -5,8 +5,8 @@ import purescala.Definitions._ object Extensions { sealed abstract class Extension(reporter: Reporter) { - val description: String - val shortDescription: String = description + def description: String + def shortDescription: String = description } abstract class Solver(reporter: Reporter) extends Extension(reporter) { diff --git a/src/purescala/Trees.scala b/src/purescala/Trees.scala index 63d03f20e623b2bbe0390108ab12862e4c12e802..3dfbd84f8605546c2ee5f9129d5748f75315c291 100644 --- a/src/purescala/Trees.scala +++ b/src/purescala/Trees.scala @@ -125,15 +125,33 @@ object Trees { case class CaseClassSelector(caseClass: Expr, selector: Identifier) extends Expr /* Arithmetic */ - case class Plus(lhs: Expr, rhs: Expr) extends Expr - case class Minus(lhs: Expr, rhs: Expr) extends Expr - case class UMinus(expr: Expr) extends Expr - case class Times(lhs: Expr, rhs: Expr) extends Expr - case class Division(lhs: Expr, rhs: Expr) extends Expr - case class LessThan(lhs: Expr, rhs: Expr) extends Expr - case class GreaterThan(lhs: Expr, rhs: Expr) extends Expr - case class LessEquals(lhs: Expr, rhs: Expr) extends Expr - case class GreaterEquals(lhs: Expr, rhs: Expr) extends Expr + case class Plus(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = Int32Type + } + case class Minus(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = Int32Type + } + case class UMinus(expr: Expr) extends Expr with FixedType { + val fixedType = Int32Type + } + case class Times(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = Int32Type + } + case class Division(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = Int32Type + } + case class LessThan(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = BooleanType + } + case class GreaterThan(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = BooleanType + } + case class LessEquals(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = BooleanType + } + case class GreaterEquals(lhs: Expr, rhs: Expr) extends Expr with FixedType { + val fixedType = BooleanType + } /* Option expressions */ case class OptionSome(value: Expr) extends Expr @@ -225,13 +243,35 @@ object Trees { case _ => None } } + + def negate(expr: Expr) : Expr = expr match { + case Let(i,b,e) => Let(i,b,negate(e)) + case Not(e) => e + case Iff(e1,e2) => Iff(negate(e1),e2) + case Implies(e1,e2) => And(e1, negate(e2)) + case Or(exs) => And(exs.map(negate(_))) + case And(exs) => Or(exs.map(negate(_))) + case LessThan(e1,e2) => GreaterEquals(e1,e2) + case LessEquals(e1,e2) => GreaterThan(e1,e2) + case GreaterThan(e1,e2) => LessEquals(e1,e2) + case GreaterEquals(e1,e2) => LessThan(e1,e2) + case i @ IfExpr(c,e1,e2) => IfExpr(c, negate(e1), negate(e2)).setType(i.getType) + case _ => Not(expr) + } // Warning ! This may loop forever if the substitutions are not // well-formed! def replace(substs: Map[Expr,Expr], expr: Expr) : Expr = { + replace(substs.isDefinedAt(_), substs(_), expr) + } + + // the replacement map should be understood as follows: + // - on each subexpression, checkFun checks whether it should be replaced + // - repFun is applied is checkFun succeeded + def replace(checkFun: Expr=>Boolean, repFun: Expr=>Expr, expr: Expr) : Expr = { def rec(ex: Expr) : Expr = ex match { - case _ if (substs.get(ex).isDefined) => { - val newExpr = substs(ex) + case _ if (checkFun(ex)) => { + val newExpr = repFun(ex) if(newExpr.getType == NoType) { Settings.reporter.warning("REPLACING IN EXPRESSION WITH AN UNTYPED TREE ! " + ex + " --to--> " + newExpr) } diff --git a/src/purescala/Z3Solver.scala b/src/purescala/Z3Solver.scala index 966d9cded788ed48e11e77d015c509596f8d3f10..c151521ba96ee18446034bb37952f52b20ef1407 100644 --- a/src/purescala/Z3Solver.scala +++ b/src/purescala/Z3Solver.scala @@ -15,10 +15,10 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) { z3cfg.setParamValue("MODEL", "true") val z3 = new Z3Context(z3cfg) - val result = toZ3Formula(z3, vc) match { + val result = toZ3Formula(z3, negate(vc)) match { case None => None // means it could not be translated case Some(z3f) => { - z3.assertCnstr(z3.mkNot(z3f)) + z3.assertCnstr(z3f) //z3.print z3.checkAndGetModel() match { case (Some(true),m) => {