diff --git a/src/main/scala/leon/purescala/Constructors.scala b/src/main/scala/leon/purescala/Constructors.scala index 1be21b20feda7d2fe9fd3af52378c23c32fd3c0b..edcc53db26b9b104071300d216f2a5983d065f3e 100644 --- a/src/main/scala/leon/purescala/Constructors.scala +++ b/src/main/scala/leon/purescala/Constructors.scala @@ -41,6 +41,17 @@ object Constructors { */ def tupleSelect(t: Expr, index: Int, originalSize: Int): Expr = tupleSelect(t, index, originalSize > 1) + /** $encodingof ``def foo(..) {} ...; e``. + * @see [[purescala.Expressions.LetDef]] + */ + def letDef(defs: Seq[FunDef], e: Expr) = { + if (defs.isEmpty) { + e + } else { + LetDef(defs, e) + } + } + /** $encodingof ``val id = e; bd``, and returns `bd` if the identifier is not bound in `bd`. * @see [[purescala.Expressions.Let]] */ diff --git a/src/main/scala/leon/purescala/ExprOps.scala b/src/main/scala/leon/purescala/ExprOps.scala index 27525657e8605ea828607951b2c29a56b1f0fc84..49d945ec6217a42578da7fef97bf572252cb6c26 100644 --- a/src/main/scala/leon/purescala/ExprOps.scala +++ b/src/main/scala/leon/purescala/ExprOps.scala @@ -1148,6 +1148,15 @@ object ExprOps { case _ => throw LeonFatalError("I can't choose simplest value for type " + tpe) } + /* Checks if a given expression is 'real' and does not contain generic + * values. */ + def isRealExpr(v: Expr): Boolean = { + !exists { + case gv: GenericValue => true + case _ => false + }(v) + } + def valuesOf(tp: TypeTree): Stream[Expr] = { import utils.StreamUtils._ tp match { diff --git a/src/main/scala/leon/purescala/Expressions.scala b/src/main/scala/leon/purescala/Expressions.scala index 50efdf4065a005b234b696f0b2589c85855cc13f..bb70a6676923db89648df770318f8c04129bad3e 100644 --- a/src/main/scala/leon/purescala/Expressions.scala +++ b/src/main/scala/leon/purescala/Expressions.scala @@ -165,6 +165,7 @@ object Expressions { * @param body The body of the expression after the function */ case class LetDef(fds: Seq[FunDef], body: Expr) extends Expr { + assert(fds.nonEmpty) val getType = body.getType } diff --git a/src/main/scala/leon/purescala/TypeOps.scala b/src/main/scala/leon/purescala/TypeOps.scala index 84825d29a8ea2a293f04732fab06b2a88a36a4b8..db655365c24a7304831e818849238bba0a849de9 100644 --- a/src/main/scala/leon/purescala/TypeOps.scala +++ b/src/main/scala/leon/purescala/TypeOps.scala @@ -167,6 +167,11 @@ object TypeOps { } } + def isParametricType(tpe: TypeTree): Boolean = tpe match { + case (tp: TypeParameter) => true + case NAryType(tps, builder) => tps.exists(isParametricType) + } + // Helpers for instantiateType private def typeParamSubst(map: Map[TypeParameter, TypeTree])(tpe: TypeTree): TypeTree = tpe match { case (tp: TypeParameter) => map.getOrElse(tp, tp) diff --git a/src/main/scala/leon/synthesis/Solution.scala b/src/main/scala/leon/synthesis/Solution.scala index ea52b9bab1c3e0d2b9be05df1cd2ec1c1f65c23f..dfe90d2f775e8ed3736020cb1e827c75fe602ad9 100644 --- a/src/main/scala/leon/synthesis/Solution.scala +++ b/src/main/scala/leon/synthesis/Solution.scala @@ -31,7 +31,7 @@ class Solution(val pre: Expr, val defs: Set[FunDef], val term: Expr, val isTrust } def toExpr = { - LetDef(defs.toList, guardedTerm) + letDef(defs.toList, guardedTerm) } // Projects a solution (ignore several output variables) diff --git a/src/main/scala/leon/synthesis/rules/Assert.scala b/src/main/scala/leon/synthesis/rules/Assert.scala index 9bba63c87d50b3ca7f1adf7e445a8a0b54172b2f..d2cdb5b69f1f88b847ad91499e3946257ef6c167 100644 --- a/src/main/scala/leon/synthesis/rules/Assert.scala +++ b/src/main/scala/leon/synthesis/rules/Assert.scala @@ -5,7 +5,9 @@ package synthesis package rules import purescala.ExprOps._ +import purescala.TypeOps._ import purescala.Extractors._ +import purescala.Expressions._ import purescala.Constructors._ /** Moves the preconditions without output variables to the precondition. */ @@ -19,7 +21,13 @@ case object Assert extends NormalizingRule("Assert") { if (exprsA.nonEmpty) { // If there is no more postcondition, then output the solution. if (others.isEmpty) { - Some(solve(Solution(pre=andJoin(exprsA), defs=Set(), term=tupleWrap(p.xs.map(id => simplestValue(id.getType)))))) + val simplestOut = simplestValue(tupleTypeWrap(p.xs.map(_.getType))) + + if (!isRealExpr(simplestOut)) { + None + } else { + Some(solve(Solution(pre = andJoin(exprsA), defs = Set(), term = simplestOut))) + } } else { val sub = p.copy(pc = andJoin(p.pc +: exprsA), phi = andJoin(others), eb = p.qeb.filterIns(andJoin(exprsA))) diff --git a/src/main/scala/leon/synthesis/rules/Ground.scala b/src/main/scala/leon/synthesis/rules/Ground.scala index 49663409fab1fb22dc102e35cfcfd3fb0ab5cdb4..d36cb15c0ff6f487d5d7b5e296fda0c406406886 100644 --- a/src/main/scala/leon/synthesis/rules/Ground.scala +++ b/src/main/scala/leon/synthesis/rules/Ground.scala @@ -19,8 +19,14 @@ case object Ground extends Rule("Ground") { val result = solver.solveSAT(p.phi) match { case (Some(true), model) => - val sol = Solution(BooleanLiteral(true), Set(), tupleWrap(p.xs.map(valuateWithModel(model)))) - RuleClosed(sol) + val solExpr = tupleWrap(p.xs.map(valuateWithModel(model))) + + if (!isRealExpr(solExpr)) { + RuleFailed() + } else { + val sol = Solution(BooleanLiteral(true), Set(), solExpr) + RuleClosed(sol) + } case (Some(false), model) => RuleClosed(Solution.UNSAT(p)) case _ => diff --git a/src/main/scala/leon/synthesis/rules/OptimisticGround.scala b/src/main/scala/leon/synthesis/rules/OptimisticGround.scala index 6085ef9eb2067fa092ffacfdefbf27532b02b5d9..679e49e38fb25ce3c4f79a26e1078651eccb69a5 100644 --- a/src/main/scala/leon/synthesis/rules/OptimisticGround.scala +++ b/src/main/scala/leon/synthesis/rules/OptimisticGround.scala @@ -36,7 +36,6 @@ case object OptimisticGround extends Rule("Optimistic Ground") { //println("SOLVING " + phi + " ...") solver.solveSAT(phi) match { case (Some(true), satModel) => - val newNotPhi = valuateWithModelIn(notPhi, xss, satModel) //println("REFUTING " + Not(newNotPhi) + "...") @@ -46,8 +45,15 @@ case object OptimisticGround extends Rule("Optimistic Ground") { predicates = valuateWithModelIn(phi, ass, invalidModel) +: predicates case (Some(false), _) => - result = Some(RuleClosed(Solution(BooleanLiteral(true), Set(), tupleWrap(p.xs.map(valuateWithModel(satModel)))))) - + // Model apprears valid, but it might be a fake expression (generic values) + val outExpr = tupleWrap(p.xs.map(valuateWithModel(satModel))) + + if (!isRealExpr(outExpr)) { + // It does contain a generic value, we skip + predicates = valuateWithModelIn(phi, xss, satModel) +: predicates + } else { + result = Some(RuleClosed(Solution(BooleanLiteral(true), Set(), outExpr))) + } case _ => continue = false result = None diff --git a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala index f753d3884e71e4ba76c84b72985f6401c0666256..eb3d83ed8d13b8235a98b48d4c209a2db5a7f08c 100644 --- a/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala +++ b/src/main/scala/leon/synthesis/rules/UnconstrainedOutput.scala @@ -7,10 +7,13 @@ package rules import purescala.Expressions._ import purescala.ExprOps._ import purescala.Constructors._ +import purescala.TypeOps._ case object UnconstrainedOutput extends NormalizingRule("Unconstr.Output") { def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { - val unconstr = p.xs.toSet -- variablesOf(p.phi) + val unconstr = (p.xs.toSet -- variablesOf(p.phi)).filter { x => + isRealExpr(simplestValue(x.getType)) + } if (unconstr.nonEmpty) { val sub = p.copy(xs = p.xs.filterNot(unconstr), eb = p.qeb.removeOuts(unconstr)) diff --git a/src/main/scala/leon/synthesis/rules/UnusedInput.scala b/src/main/scala/leon/synthesis/rules/UnusedInput.scala index 677c9b852aafeadcfc96bd63f2b98aaaaf289940..4570501d7646b3f8d77d4fb484451ff957ac723f 100644 --- a/src/main/scala/leon/synthesis/rules/UnusedInput.scala +++ b/src/main/scala/leon/synthesis/rules/UnusedInput.scala @@ -5,10 +5,13 @@ package synthesis package rules import purescala.ExprOps._ +import purescala.TypeOps._ case object UnusedInput extends NormalizingRule("UnusedInput") { def instantiateOn(implicit hctx: SearchContext, p: Problem): Traversable[RuleInstantiation] = { - val unused = p.as.toSet -- variablesOf(p.phi) -- variablesOf(p.pc) -- variablesOf(p.ws) + val unused = (p.as.toSet -- variablesOf(p.phi) -- variablesOf(p.pc) -- variablesOf(p.ws)).filter { a => + !isParametricType(a.getType) + } if (unused.nonEmpty) { val sub = p.copy(as = p.as.filterNot(unused), eb = p.qeb.removeIns(unused))