-
Etienne Kneuss authoredEtienne Kneuss authored
InlineHoles.scala 2.82 KiB
/* Copyright 2009-2014 EPFL, Lausanne */
package leon
package synthesis
package rules
import scala.annotation.tailrec
import leon.utils._
import solvers._
import purescala.Common._
import purescala.Trees._
import purescala.TreeOps._
import purescala.TypeTrees._
import purescala.Extractors._
case object InlineHoles extends Rule("Inline-Holes") {
override val priority = RulePriorityHoles
def instantiateOn(sctx: SynthesisContext, p: Problem): Traversable[RuleInstantiation] = {
@tailrec
def inlineUntilHoles(e: Expr): Expr = {
if (containsHoles(e)) {
// Holes are exposed, no need to inline (yet)
e
} else {
// Inline all functions "once" that contain holes
val newE = postMap {
case fi @ FunctionInvocation(tfd, args) if usesHoles(fi) && tfd.hasBody =>
val inlined = replaceFromIDs((tfd.params.map(_.id) zip args).toMap, tfd.body.get)
Some(inlined)
case _ => None
}(e)
inlineUntilHoles(newE)
}
}
def inlineHoles(phi: Expr): (List[Identifier], Expr) = {
var newXs = List[Identifier]()
val res = preMap {
case h @ Hole(o) =>
val tpe = h.getType
val x = FreshIdentifier("h", true).setType(tpe)
newXs ::= x
Some(x.toVariable)
case _ => None
}(phi)
(newXs.reverse, res)
}
if (usesHoles(p.phi)) {
val pathsToCalls = CollectorWithPaths({
case fi: FunctionInvocation if usesHoles(fi) => fi
}).traverse(p.phi).map(_._2)
val pc = if (pathsToCalls.nonEmpty) {
Not(Or(pathsToCalls))
} else {
BooleanLiteral(false)
}
// Creates two alternative branches:
// 1) a version with holes unreachable, on which this rule won't re-apply
val sfact = new TimeoutSolverFactory(sctx.solverFactory, 500L)
val solver = SimpleSolverAPI(new TimeoutSolverFactory(sctx.solverFactory, 2000L))
val(holesAvoidable, _) = solver.solveSAT(And(p.pc, pc))
val avoid = if (holesAvoidable != Some(false)) {
val newPhi = simplifyPaths(sfact)(And(pc, p.phi))
val newProblem1 = p.copy(phi = newPhi)
Some(RuleInstantiation.immediateDecomp(p, this, List(newProblem1), {
case List(s) if (s.pre != BooleanLiteral(false)) => Some(s)
case _ => None
}, "Avoid Holes"))
} else {
None
}
// 2) a version with holes reachable to continue applying itself
val newPhi = inlineUntilHoles(p.phi)
val (newXs, newPhiInlined) = inlineHoles(newPhi)
val newProblem2 = p.copy(phi = newPhiInlined, xs = p.xs ::: newXs)
val rec = Some(RuleInstantiation.immediateDecomp(p, this, List(newProblem2), project(p.xs.size), "Inline Holes"))
List(rec, avoid).flatten
} else {
Nil
}
}
}