diff --git a/src/main/scala/leon/solvers/templates/LambdaManager.scala b/src/main/scala/leon/solvers/templates/LambdaManager.scala index d82a03e5562bba04afe7c6d53f7026318f42a4d0..e7282e4f18b293bc37dd4f560794f3a18ca4e271 100644 --- a/src/main/scala/leon/solvers/templates/LambdaManager.scala +++ b/src/main/scala/leon/solvers/templates/LambdaManager.scala @@ -10,37 +10,50 @@ import purescala.TreeOps._ import purescala.TypeTrees._ class LambdaManager[T](encoder: TemplateEncoder[T]) { - private var byID : Map[T, LambdaTemplate[T]] = Map.empty - private var byType : Map[TypeTree, Set[(T, LambdaTemplate[T])]] = Map.empty.withDefaultValue(Set.empty) - private var quantified : Map[TypeTree, Set[T]] = Map.empty.withDefaultValue(Set.empty) - private var applications : Map[TypeTree, Set[(T, App[T])]] = Map.empty.withDefaultValue(Set.empty) - private var blockedApplications : Map[(T, App[T]), Set[T]] = Map.empty.withDefaultValue(Set.empty) + private type IdMap = Map[T, LambdaTemplate[T]] + private var byIDStack : List[IdMap] = List(Map.empty) + private def byID : IdMap = byIDStack.head + private def byID_=(map: IdMap) : Unit = { + byIDStack = map :: byIDStack.tail + } + + private type TypeMap = Map[TypeTree, Set[(T, LambdaTemplate[T])]] + private var byTypeStack : List[TypeMap] = List(Map.empty.withDefaultValue(Set.empty)) + private def byType : TypeMap = byTypeStack.head + private def byType_=(map: TypeMap) : Unit = { + byTypeStack = map :: byTypeStack.tail + } - private var globalBlocker : Option[T] = None - private var previousGlobals : Set[T] = Set.empty + private type ApplicationMap = Map[TypeTree, Set[(T, App[T])]] + private var applicationsStack : List[ApplicationMap] = List(Map.empty.withDefaultValue(Set.empty)) + private def applications : ApplicationMap = applicationsStack.head + private def applications_=(map: ApplicationMap) : Unit = { + applicationsStack = map :: applicationsStack.tail + } - def quantify(args: Seq[(TypeTree, T)]): Unit = { - args.foreach(p => quantified += p._1 -> (quantified(p._1) + p._2)) + def push(): Unit = { + byIDStack = byID :: byIDStack + byTypeStack = byType :: byTypeStack + applicationsStack = applications :: applicationsStack } - def instantiate(apps: Map[T, Set[App[T]]], lambdas: Map[T, LambdaTemplate[T]]) : (Seq[T], Map[T, Set[TemplateInfo[T]]]) = { + def pop(lvl: Int): Unit = { + byIDStack = byIDStack.drop(lvl) + byTypeStack = byTypeStack.drop(lvl) + applicationsStack = applicationsStack.drop(lvl) + } + + def instantiate(apps: Map[T, Set[App[T]]], lambdas: Map[T, LambdaTemplate[T]]) : (Seq[T], Map[T, Set[TemplateCallInfo[T]]], Map[(T, App[T]), Set[TemplateAppInfo[T]]]) = { var clauses : Seq[T] = Seq.empty - var blockers : Map[T, Set[TemplateInfo[T]]] = Map.empty.withDefaultValue(Set.empty) + var callBlockers : Map[T, Set[TemplateCallInfo[T]]] = Map.empty.withDefaultValue(Set.empty) + var appBlockers : Map[(T, App[T]), Set[TemplateAppInfo[T]]] = Map.empty.withDefaultValue(Set.empty) def mkBlocker(blockedApp: (T, App[T]), lambda: (T, LambdaTemplate[T])) : Unit = { val (_, App(caller, tpe, args)) = blockedApp val (idT, template) = lambda - val unrollingBlocker = encoder.encodeId(FreshIdentifier("unrolled", true).setType(BooleanType)) - - val conj = encoder.mkAnd(encoder.mkEquals(idT, caller), template.start, unrollingBlocker) - - val templateBlocker = encoder.encodeId(FreshIdentifier("b", true).setType(BooleanType)) - val constraint = encoder.mkEquals(templateBlocker, conj) - - clauses :+= constraint - blockedApplications += (blockedApp -> (blockedApplications(blockedApp) + templateBlocker)) - blockers += (unrollingBlocker -> Set(TemplateAppInfo(template, templateBlocker, args))) + val equals = encoder.mkEquals(idT, caller) + appBlockers += (blockedApp -> (appBlockers(blockedApp) + TemplateAppInfo(template, equals, args))) } for (lambda @ (idT, template) <- lambdas) { @@ -54,35 +67,28 @@ class LambdaManager[T](encoder: TemplateEncoder[T]) { for ((b, fas) <- apps; app @ App(caller, tpe, args) <- fas) { if (byID contains caller) { - val (newClauses, newBlockers) = byID(caller).instantiate(b, args) + val (newClauses, newCalls, newApps) = byID(caller).instantiate(b, args) + clauses ++= newClauses - newBlockers.foreach(p => blockers += p._1 -> (blockers(p._1) ++ p._2)) + newCalls.foreach(p => callBlockers += p._1 -> (callBlockers(p._1) ++ p._2)) + newApps.foreach(p => appBlockers += p._1 -> (appBlockers(p._1) ++ p._2)) } else { + val key = b -> app + + // make sure that even if byType(tpe) is empty, app is recorded in blockers + // so that UnrollingBank will generate the initial block! + if (!(appBlockers contains key)) appBlockers += key -> Set.empty + for (lambda <- byType(tpe)) { - mkBlocker(b -> app, lambda) + mkBlocker(key, lambda) } - applications += tpe -> (applications(tpe) + (b -> app)) + applications += tpe -> (applications(tpe) + key) } } - (clauses, blockers) - } - - def guards : Seq[T] = { - previousGlobals ++= globalBlocker - val globalGuard = encoder.encodeId(FreshIdentifier("lambda_phaser", true).setType(BooleanType)) - globalBlocker = Some(globalGuard) - - (for (((b, App(caller, tpe, _)), tbs) <- blockedApplications) yield { - val qbs = quantified(tpe).map(l => encoder.mkEquals(caller, l)) - val or = encoder.mkOr((tbs ++ qbs).toSeq : _*) - // TODO: get global blocker - val guard = encoder.mkAnd(globalGuard, encoder.mkNot(or)) - encoder.mkImplies(guard, encoder.mkNot(b)) - }).toSeq ++ previousGlobals.map(encoder.mkNot(_)) + (clauses, callBlockers, appBlockers) } - def assumption : T = globalBlocker.get } diff --git a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala index 114eafe8d4ceb12a50947605be3a1c16b934c671..75fd757a69704a170e0afd95648a4bfc8648bc80 100644 --- a/src/main/scala/leon/solvers/templates/TemplateGenerator.scala +++ b/src/main/scala/leon/solvers/templates/TemplateGenerator.scala @@ -18,7 +18,7 @@ class TemplateGenerator[T](val encoder: TemplateEncoder[T]) { private var cache = Map[TypedFunDef, FunctionTemplate[T]]() private var cacheExpr = Map[Expr, FunctionTemplate[T]]() - private[templates] val lambdaManager = new LambdaManager[T](encoder) + private val lambdaManager = new LambdaManager[T](encoder) def mkTemplate(body: Expr): FunctionTemplate[T] = { if (cacheExpr contains body) { diff --git a/src/main/scala/leon/solvers/templates/TemplateInfo.scala b/src/main/scala/leon/solvers/templates/TemplateInfo.scala index 80ed670fd0844b673202748227a75b6bfc9b2a30..110e658a301c2805968124905d9137d8e267114c 100644 --- a/src/main/scala/leon/solvers/templates/TemplateInfo.scala +++ b/src/main/scala/leon/solvers/templates/TemplateInfo.scala @@ -7,16 +7,14 @@ package templates import purescala.Definitions.TypedFunDef import purescala.TypeTrees.TypeTree -sealed abstract class TemplateInfo[T] - -case class TemplateCallInfo[T](tfd: TypedFunDef, args: Seq[T]) extends TemplateInfo[T] { +case class TemplateCallInfo[T](tfd: TypedFunDef, args: Seq[T]) { override def toString = { tfd.signature+args.mkString("(", ", ", ")") } } -case class TemplateAppInfo[T](template: LambdaTemplate[T], b: T, args: Seq[T]) extends TemplateInfo[T] { +case class TemplateAppInfo[T](template: LambdaTemplate[T], equals: T, args: Seq[T]) { override def toString = { - template.id + "|" + b + "|" + args.mkString("(", ",", ")") + template.id + "|" + equals + args.mkString("(", ",", ")") } } diff --git a/src/main/scala/leon/solvers/templates/Templates.scala b/src/main/scala/leon/solvers/templates/Templates.scala index 05e7a4c01708938d0066c01bf751ba0170dc1f9d..c9273660c8b99259e72a959b39029987f1401564 100644 --- a/src/main/scala/leon/solvers/templates/Templates.scala +++ b/src/main/scala/leon/solvers/templates/Templates.scala @@ -35,7 +35,7 @@ trait Template[T] { self => private var substCache : Map[Seq[T],Map[T,T]] = Map.empty private var lambdaCache : Map[(T, Map[T,T]), T] = Map.empty - def instantiate(aVar: T, args: Seq[T]): (Seq[T], Map[T, Set[TemplateInfo[T]]]) = { + def instantiate(aVar: T, args: Seq[T]): (Seq[T], Map[T, Set[TemplateCallInfo[T]]], Map[(T, App[T]), Set[TemplateAppInfo[T]]]) = { val baseSubstMap : Map[T,T] = substCache.get(args) match { case Some(subst) => subst @@ -80,14 +80,14 @@ trait Template[T] { self => substituter(idT) -> lambda.substitute(substMap) } - val (appClauses, appBlockers) = lambdaManager.instantiate(newApplications, newLambdas) + val (appClauses, appBlockers, appApps) = lambdaManager.instantiate(newApplications, newLambdas) val allClauses = newClauses ++ appClauses ++ lambdaClauses val allBlockers = (newBlockers.keys ++ appBlockers.keys).map { k => k -> (newBlockers.getOrElse(k, Set.empty) ++ appBlockers.getOrElse(k, Set.empty)) }.toMap - (allClauses, allBlockers) + (allClauses, allBlockers, appApps) } override def toString : String = "Instantiated template" diff --git a/src/main/scala/leon/solvers/templates/UnrollingBank.scala b/src/main/scala/leon/solvers/templates/UnrollingBank.scala index 8d8b604de83a4f31951580761dbf25f52b44a157..fc6782dd1fecc021dcdbaff195b7792a8800359d 100644 --- a/src/main/scala/leon/solvers/templates/UnrollingBank.scala +++ b/src/main/scala/leon/solvers/templates/UnrollingBank.scala @@ -18,58 +18,99 @@ class UnrollingBank[T](reporter: Reporter, templateGenerator: TemplateGenerator[ implicit val debugSection = utils.DebugSectionSolver private val encoder = templateGenerator.encoder - private val lambdaManager = templateGenerator.lambdaManager // Keep which function invocation is guarded by which guard, // also specify the generation of the blocker. - private var blockersInfoStack = List[Map[T, (Int, Int, T, Set[TemplateInfo[T]])]](Map()) + private var callInfoStack = List[Map[T, (Int, Int, T, Set[TemplateCallInfo[T]])]](Map()) + private def callInfo = callInfoStack.head + private def callInfo_= (v: Map[T, (Int, Int, T, Set[TemplateCallInfo[T]])]) = { + callInfoStack = v :: callInfoStack.tail + } // Function instantiations have their own defblocker - private var defBlockers = Map[TemplateInfo[T], T]() + private var defBlockersStack = List[Map[TemplateCallInfo[T], T]](Map.empty) + private def defBlockers = defBlockersStack.head + private def defBlockers_= (v: Map[TemplateCallInfo[T], T]) : Unit = { + defBlockersStack = v :: defBlockersStack.tail + } + + private var appInfoStack = List[Map[(T, App[T]), (Int, Int, T, T, Set[TemplateAppInfo[T]])]](Map()) + private def appInfo = appInfoStack.head + private def appInfo_= (v: Map[(T, App[T]), (Int, Int, T, T, Set[TemplateAppInfo[T]])]) : Unit = { + appInfoStack = v :: appInfoStack.tail + } - def blockersInfo = blockersInfoStack.head + private var appBlockersStack = List[Map[(T, App[T]), T]](Map.empty) + private def appBlockers = appBlockersStack.head + private def appBlockers_= (v: Map[(T, App[T]), T]) : Unit = { + appBlockersStack = v :: appBlockersStack.tail + } + + private var blockerToAppStack = List[Map[T, (T, App[T])]](Map.empty) + private def blockerToApp = blockerToAppStack.head + private def blockerToApp_= (v: Map[T, (T, App[T])]) : Unit = { + blockerToAppStack = v :: blockerToAppStack.tail + } - def blockersInfo_= (v: Map[T, (Int, Int, T, Set[TemplateInfo[T]])]) = { - blockersInfoStack = v :: blockersInfoStack.tail + private var functionVarsStack = List[Map[TypeTree, Set[T]]](Map.empty.withDefaultValue(Set.empty)) + private def functionVars = functionVarsStack.head + private def functionVars_= (v: Map[TypeTree, Set[T]]) : Unit = { + functionVarsStack = v :: functionVarsStack.tail } def push() { - blockersInfoStack = blockersInfo :: blockersInfoStack + appInfoStack = appInfo :: appInfoStack + callInfoStack = callInfo :: callInfoStack + defBlockersStack = defBlockers :: defBlockersStack + blockerToAppStack = blockerToApp :: blockerToAppStack + functionVarsStack = functionVars :: functionVarsStack + appBlockersStack = appBlockers :: appBlockersStack } def pop(lvl: Int) { - blockersInfoStack = blockersInfoStack.drop(lvl) + appInfoStack = appInfoStack.drop(lvl) + callInfoStack = callInfoStack.drop(lvl) + defBlockersStack = defBlockersStack.drop(lvl) + blockerToAppStack = blockerToAppStack.drop(lvl) + functionVarsStack = functionVarsStack.drop(lvl) + appBlockersStack = appBlockersStack.drop(lvl) } def dumpBlockers = { - blockersInfo.groupBy(_._2._1).toSeq.sortBy(_._1).foreach { case (gen, entries) => - reporter.debug("--- "+gen) + val generations = (callInfo.map(_._2._1).toSet ++ appInfo.map(_._2._1).toSet).toSeq.sorted + generations.foreach { generation => + reporter.debug("--- " + generation) - for (((bast), (gen, origGen, ast, fis)) <- entries) { - reporter.debug(f". $bast%15s ~> "+fis.mkString(", ")) + for ((b, (gen, origGen, ast, fis)) <- callInfo if gen == generation) { + reporter.debug(f". $b%15s ~> "+fis.mkString(", ")) + } + + for ((app, (gen, origGen, b, notB, infos)) <- appInfo if gen == generation) { + reporter.debug(f". $b%15s ~> "+infos.mkString(", ")) } } } - def canUnroll = !blockersInfo.isEmpty + def canUnroll = !callInfo.isEmpty || !appInfo.isEmpty - def currentBlockers = blockersInfo.map(_._2._3).toSeq :+ lambdaManager.assumption + def currentBlockers = callInfo.map(_._2._3).toSeq ++ appInfo.map(_._2._4).toSeq def getBlockersToUnlock: Seq[T] = { - if (!blockersInfo.isEmpty) { - val minGeneration = blockersInfo.values.map(_._1).min - - blockersInfo.filter(_._2._1 == minGeneration).toSeq.map(_._1) + if (callInfo.isEmpty && appInfo.isEmpty) { + Seq.empty } else { - Seq() + val minGeneration = (callInfo.values.map(_._1) ++ appInfo.values.map(_._1)).min + val callBlocks = callInfo.filter(_._2._1 == minGeneration).toSeq.map(_._1) + val appBlocks = appInfo.values.filter(_._1 == minGeneration).toSeq.map(_._3) + callBlocks ++ appBlocks } } - private def registerBlocker(gen: Int, id: T, fis: Set[TemplateInfo[T]]) { + private def registerCallBlocker(gen: Int, id: T, fis: Set[TemplateCallInfo[T]]) { val notId = encoder.mkNot(id) - blockersInfo.get(id) match { + callInfo.get(id) match { case Some((exGen, origGen, _, exFis)) => // PS: when recycling `b`s, this assertion becomes dangerous. // It's better to simply take the max of the generations. @@ -77,12 +118,54 @@ class UnrollingBank[T](reporter: Reporter, templateGenerator: TemplateGenerator[ val minGen = gen min exGen - blockersInfo += id -> (minGen, origGen, notId, fis++exFis) + callInfo += id -> (minGen, origGen, notId, fis++exFis) + case None => + callInfo += id -> (gen, gen, notId, fis) + } + } + + private def registerAppBlocker(gen: Int, app: (T, App[T]), info: Set[TemplateAppInfo[T]]) : Unit = { + appInfo.get(app) match { + case Some((exGen, origGen, b, notB, exInfo)) => + val minGen = gen min exGen + appInfo += app -> (minGen, origGen, b, notB, exInfo ++ info) + case None => - blockersInfo += id -> (gen, gen, notId, fis) + val b = appBlockers.get(app) match { + case Some(b) => b + case None => encoder.encodeId(FreshIdentifier("b_lambda", true).setType(BooleanType)) + } + + val notB = encoder.mkNot(b) + appInfo += app -> (gen, gen, b, notB, info) + blockerToApp += b -> app } } + private def freshAppBlocks(apps: Traversable[(T, App[T])]) : Seq[T] = { + apps.filter(!appBlockers.isDefinedAt(_)).toSeq.map { case app @ (blocker, App(caller, tpe, _)) => + + val firstB = encoder.encodeId(FreshIdentifier("b_lambda", true).setType(BooleanType)) + val freeEq = functionVars(tpe).toSeq.map(t => encoder.mkEquals(t, caller)) + val clause = encoder.mkImplies(encoder.mkNot(encoder.mkOr((freeEq :+ firstB) : _*)), encoder.mkNot(blocker)) + + appBlockers += app -> firstB + clause + } + } + + private def extendAppBlock(app: (T, App[T]), infos: Set[TemplateAppInfo[T]]) : T = { + assert(!appInfo.isDefinedAt(app), "appInfo -= app must have been called to ensure blocker freshness") + assert(appBlockers.isDefinedAt(app), "freshAppBlocks must have been called on app before it can be unlocked") + + val nextB = encoder.encodeId(FreshIdentifier("b_lambda", true).setType(BooleanType)) + val extension = encoder.mkOr((infos.map(_.equals).toSeq :+ nextB) : _*) + val clause = encoder.mkEquals(appBlockers(app), extension) + + appBlockers += app -> nextB + clause + } + def getClauses(expr: Expr, bindings: Map[Expr, T]): Seq[T] = { // OK, now this is subtle. This `getTemplate` will return // a template for a "fake" function. Now, this template will @@ -91,110 +174,146 @@ class UnrollingBank[T](reporter: Reporter, templateGenerator: TemplateGenerator[ val trArgs = template.tfd.params.map(vd => bindings(Variable(vd.id))) - lambdaManager.quantify(template.tfd.params.collect { - case vd if vd.tpe.isInstanceOf[FunctionType] => - vd.tpe -> bindings(vd.toVariable) - }) + for (vd <- template.tfd.params if vd.tpe.isInstanceOf[FunctionType]) { + functionVars += vd.tpe -> (functionVars(vd.tpe) + bindings(vd.toVariable)) + } // ...now this template defines clauses that are all guarded // by that activating boolean. If that activating boolean is // undefined (or false) these clauses have no effect... - val (newClauses, newBlocks) = - template.instantiate(template.start, trArgs) + val (newClauses, callBlocks, appBlocks) = template.instantiate(template.start, trArgs) - for((i, fis) <- newBlocks) { - registerBlocker(nextGeneration(0), i, fis) + val blockClauses = freshAppBlocks(appBlocks.keys) + + for((b, infos) <- callBlocks) { + registerCallBlocker(nextGeneration(0), b, infos) + } + + for ((app, infos) <- appBlocks) { + registerAppBlocker(nextGeneration(0), app, infos) } // ...so we must force it to true! - template.start +: (newClauses ++ lambdaManager.guards) + template.start +: (newClauses ++ blockClauses) } def nextGeneration(gen: Int) = gen + 3 def decreaseAllGenerations() = { - for ((block, (gen, origGen, ast, finvs)) <- blockersInfo) { + for ((block, (gen, origGen, ast, infos)) <- callInfo) { // We also decrease the original generation here - blockersInfo += block -> (math.max(1,gen-1), math.max(1,origGen-1), ast, finvs) + callInfo += block -> (math.max(1,gen-1), math.max(1,origGen-1), ast, infos) + } + + for ((app, (gen, origGen, b, notB, infos)) <- appInfo) { + appInfo += app -> (math.max(1,gen-1), math.max(1,origGen-1), b, notB, infos) } } def promoteBlocker(b: T) = { - if (blockersInfo contains b) { - val (gen, origGen, ast, fis) = blockersInfo(b) + if (callInfo contains b) { + val (gen, origGen, ast, fis) = callInfo(b) - blockersInfo += b -> (1, origGen, ast, fis) + callInfo += b -> (1, origGen, ast, fis) + } + + if (blockerToApp contains b) { + val app = blockerToApp(b) + val (gen, origGen, _, notB, infos) = appInfo(app) + + appInfo += app -> (1, origGen, b, notB, infos) } } def unrollBehind(ids: Seq[T]): Seq[T] = { - assert(ids.forall(id => blockersInfo contains id)) + assert(ids.forall(id => (callInfo contains id) || (blockerToApp contains id))) var newClauses : Seq[T] = Seq.empty - for (id <- ids) { - val (gen, _, _, fis) = blockersInfo(id) + val callInfos = ids.flatMap(id => callInfo.get(id).map(id -> _)) + callInfo = callInfo -- ids - blockersInfo = blockersInfo - id + val apps = ids.flatMap(id => blockerToApp.get(id)) + val appInfos = apps.map(app => app -> appInfo(app)) + blockerToApp = blockerToApp -- ids + appInfo = appInfo -- apps - var reintroducedSelf = false + for ((app, (_, _, _, _, infos)) <- appInfos) { + newClauses :+= extendAppBlock(app, infos) + } - for (fi <- fis) { - var newCls = Seq[T]() + for ((id, (gen, _, _, infos)) <- callInfos; info @ TemplateCallInfo(tfd, args) <- infos) { + var newCls = Seq[T]() - fi match { - case TemplateCallInfo(tfd, args) => - val defBlocker = defBlockers.get(fi) match { - case Some(defBlocker) => - // we already have defBlocker => f(args) = body - defBlocker + val defBlocker = defBlockers.get(info) match { + case Some(defBlocker) => + // we already have defBlocker => f(args) = body + defBlocker - case None => - // we need to define this defBlocker and link it to definition - val defBlocker = encoder.encodeId(FreshIdentifier("d").setType(BooleanType)) - defBlockers += fi -> defBlocker + case None => + // we need to define this defBlocker and link it to definition + val defBlocker = encoder.encodeId(FreshIdentifier("d").setType(BooleanType)) + defBlockers += info -> defBlocker - val template = templateGenerator.mkTemplate(tfd) - reporter.debug(template) + val template = templateGenerator.mkTemplate(tfd) + reporter.debug(template) - val (newExprs, newBlocks) = template.instantiate(defBlocker, args) + val (newExprs, callBlocks, appBlocks) = template.instantiate(defBlocker, args) + val blockExprs = freshAppBlocks(appBlocks.keys) - for((i, fis2) <- newBlocks) { - registerBlocker(nextGeneration(gen), i, fis2) - } + for((b, newInfos) <- callBlocks) { + registerCallBlocker(nextGeneration(gen), b, newInfos) + } - newCls ++= newExprs - defBlocker - } + for ((app, newInfos) <- appBlocks) { + registerAppBlocker(nextGeneration(gen), app, newInfos) + } - // We connect it to the defBlocker: blocker => defBlocker - if (defBlocker != id) { - newCls ++= List(encoder.mkImplies(id, defBlocker)) - } + newCls ++= newExprs + newCls ++= blockExprs + defBlocker + } - case TemplateAppInfo(template, b, args) => - reporter.debug(template) - val (newExprs, newBlocks) = template.instantiate(b, args) + // We connect it to the defBlocker: blocker => defBlocker + if (defBlocker != id) { + newCls ++= List(encoder.mkImplies(id, defBlocker)) + } - for((i, fis2) <- newBlocks) { - registerBlocker(nextGeneration(gen), i, fis2) - } + reporter.debug("Unrolling behind "+info+" ("+newCls.size+")") + for (cl <- newCls) { + reporter.debug(" . "+cl) + } - newCls ++= newExprs - newCls :+= id - } + newClauses ++= newCls + } - reporter.debug("Unrolling behind "+fi+" ("+newCls.size+")") - for (cl <- newCls) { - reporter.debug(" . "+cl) - } + for ((app @ (b, _), (gen, _, _, _, infos)) <- appInfos; info @ TemplateAppInfo(template, equals, args) <- infos) { + var newCls = Seq.empty[T] + + val nb = encoder.encodeId(FreshIdentifier("b", true).setType(BooleanType)) + newCls :+= encoder.mkEquals(nb, encoder.mkAnd(equals, b)) + + val (newExprs, callBlocks, appBlocks) = template.instantiate(nb, args) + val blockExprs = freshAppBlocks(appBlocks.keys) - newClauses ++= newCls + for ((b, newInfos) <- callBlocks) { + registerCallBlocker(nextGeneration(gen), b, newInfos) } - } + for ((newApp, newInfos) <- appBlocks) { + registerAppBlocker(nextGeneration(gen), newApp, newInfos) + } + + newCls ++= newExprs + newCls ++= blockExprs - newClauses ++= lambdaManager.guards + reporter.debug("Unrolling behind "+info+" ("+newCls.size+")") + for (cl <- newCls) { + reporter.debug(" . "+cl) + } + + newClauses ++= newCls + } reporter.debug(s" - ${newClauses.size} new clauses") //context.reporter.ifDebug { debug => diff --git a/src/test/resources/regression/verification/purescala/valid/Lambdas.scala b/src/test/resources/regression/verification/purescala/valid/Lambdas.scala new file mode 100644 index 0000000000000000000000000000000000000000..36ae0c7ad7f8a68e36358d9e5adb885e7bb108da --- /dev/null +++ b/src/test/resources/regression/verification/purescala/valid/Lambdas.scala @@ -0,0 +1,15 @@ +import leon.lang._ + +object Lambdas { + def gen(x: Int): (Int) => Int = { + val f = (x: Int) => x + 1 + val g = (x: Int) => x + 2 + if (x > 0) g else f + } + + def test(x: Int): Boolean = { + require(x > 0) + val f = gen(x) + f(x) == x + 2 + }.holds +}