From 53343bf12f3286f30d36b36752fac39a7326cbde Mon Sep 17 00:00:00 2001 From: Etienne Kneuss <colder@php.net> Date: Sat, 13 Jul 2013 19:03:29 +0200 Subject: [PATCH] Embed information about function closures within trees. Simpler phase. --- .../scala/leon/purescala/Definitions.scala | 4 +++ .../scala/leon/xlang/FunctionClosure.scala | 17 +++++-------- .../scala/leon/xlang/XlangAnalysisPhase.scala | 25 +++++++++++-------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/main/scala/leon/purescala/Definitions.scala b/src/main/scala/leon/purescala/Definitions.scala index ae14f7b62..93a51b9f5 100644 --- a/src/main/scala/leon/purescala/Definitions.scala +++ b/src/main/scala/leon/purescala/Definitions.scala @@ -317,6 +317,10 @@ object Definitions { var precondition: Option[Expr] = None var postcondition: Option[Expr] = None + // Metadata kept here after transformations + var parent: Option[FunDef] = None + var orig: Option[FunDef] = None + def hasImplementation : Boolean = body.isDefined def hasBody = hasImplementation def hasPrecondition : Boolean = precondition.isDefined diff --git a/src/main/scala/leon/xlang/FunctionClosure.scala b/src/main/scala/leon/xlang/FunctionClosure.scala index 8ade819e4..3b6a74394 100644 --- a/src/main/scala/leon/xlang/FunctionClosure.scala +++ b/src/main/scala/leon/xlang/FunctionClosure.scala @@ -13,7 +13,7 @@ import leon.purescala.TreeOps._ import leon.purescala.TypeTrees._ import leon.xlang.Trees._ -object FunctionClosure extends LeonPhase[Program, (Program, Map[FunDef, FunDef], Map[FunDef, FunDef])] { +object FunctionClosure extends TransformationPhase { val name = "Function Closure" val description = "Closing function with its scoping variables" @@ -24,20 +24,14 @@ object FunctionClosure extends LeonPhase[Program, (Program, Map[FunDef, FunDef], private var newFunDefs: Map[FunDef, FunDef] = Map() private var topLevelFuns: Set[FunDef] = Set() private var parent: FunDef = null //refers to the current toplevel parent - private var parents: Map[FunDef, FunDef] = null //each hoisted function mapped to its original parent - private var freshFunDefs: Map[FunDef, FunDef] = null //mapping from original FunDef in LetDef to the fresh ones - /* but notice the private keyword */ - //return modified program, new funDef to their original parents, old FunDef to freshly introduced FunDef - def run(ctx: LeonContext)(program: Program): (Program, Map[FunDef, FunDef], Map[FunDef, FunDef]) = { + def apply(ctx: LeonContext, program: Program): Program = { pathConstraints = Nil enclosingLets = Nil newFunDefs = Map() topLevelFuns = Set() parent = null - parents = Map() - freshFunDefs = Map() val funDefs = program.definedFunctions funDefs.foreach(fd => { @@ -47,7 +41,7 @@ object FunctionClosure extends LeonPhase[Program, (Program, Map[FunDef, FunDef], }) val Program(id, ObjectDef(objId, defs, invariants)) = program val res = Program(id, ObjectDef(objId, defs ++ topLevelFuns, invariants)) - (res, parents, freshFunDefs) + res } private def functionClosure(expr: Expr, bindedVars: Set[Identifier], id2freshId: Map[Identifier, Identifier], fd2FreshFd: Map[FunDef, (FunDef, Seq[Variable])]): Expr = expr match { @@ -68,8 +62,9 @@ object FunctionClosure extends LeonPhase[Program, (Program, Map[FunDef, FunDef], val newFunDef = new FunDef(newFunId, fd.returnType, newVarDecls).setPosInfo(fd) topLevelFuns += newFunDef newFunDef.addAnnotation(fd.annotations.toSeq:_*) //TODO: this is still some dangerous side effects - parents += (newFunDef -> parent) - freshFunDefs += (fd -> newFunDef) + newFunDef.parent = Some(parent) + fd.parent = Some(parent) + newFunDef.orig = Some(fd) def introduceLets(expr: Expr, fd2FreshFd: Map[FunDef, (FunDef, Seq[Variable])]): Expr = { val (newExpr, _) = enclosingLets.foldLeft((expr, Map[Identifier, Identifier]()))((acc, p) => { diff --git a/src/main/scala/leon/xlang/XlangAnalysisPhase.scala b/src/main/scala/leon/xlang/XlangAnalysisPhase.scala index 13c8d619f..4fb3c98bc 100644 --- a/src/main/scala/leon/xlang/XlangAnalysisPhase.scala +++ b/src/main/scala/leon/xlang/XlangAnalysisPhase.scala @@ -16,17 +16,20 @@ object XlangAnalysisPhase extends LeonPhase[Program, VerificationReport] { val pgm1 = ArrayTransformation(ctx, pgm) val pgm2 = EpsilonElimination(ctx, pgm1) val (pgm3, wasLoop) = ImperativeCodeElimination.run(ctx)(pgm2) - val (pgm4, parents, freshFunDefs) = FunctionClosure.run(ctx)(pgm3) + val pgm4 = FunctionClosure.run(ctx)(pgm3) - val originalFunDefs = freshFunDefs.map(x => (x._2, x._1)) - - def functionWasLoop(fd: FunDef): Boolean = originalFunDefs.get(fd) match { + def functionWasLoop(fd: FunDef): Boolean = fd.orig match { case None => false //meaning, this was a top level function case Some(nested) => wasLoop.contains(nested) //could have been a LetDef originally } - def subFunctionsOf(fd: FunDef): Set[FunDef] = parents.flatMap((p: (FunDef, FunDef)) => p match { - case (child, parent) => if(parent == fd) List(child) else List() - }).toSet + + var subFunctionsOf = Map[FunDef, Set[FunDef]]().withDefaultValue(Set()) + pgm4.definedFunctions.foreach { fd => fd.parent match { + case Some(p) => + subFunctionsOf += p -> (subFunctionsOf(p) + fd) + case _ => + }} + val newOptions = ctx.options map { case LeonValueOption("functions", ListValue(fs)) => { @@ -41,17 +44,17 @@ object XlangAnalysisPhase extends LeonPhase[Program, VerificationReport] { case None => } }) - + LeonValueOption("functions", ListValue(freshToAnalyse.toList)) } case opt => opt } val vr = AnalysisPhase.run(ctx.copy(options = newOptions))(pgm4) - completeVerificationReport(vr, parents, functionWasLoop _) + completeVerificationReport(vr, functionWasLoop _) } - def completeVerificationReport(vr: VerificationReport, parents: Map[FunDef, FunDef], functionWasLoop: FunDef => Boolean): VerificationReport = { + def completeVerificationReport(vr: VerificationReport, functionWasLoop: FunDef => Boolean): VerificationReport = { val vcs = vr.conditions //this is enough to convert invariant postcondition and inductive conditions. However the initial validity @@ -66,7 +69,7 @@ object XlangAnalysisPhase extends LeonPhase[Program, VerificationReport] { if(functionWasLoop(funDef)) { val freshVc = new VerificationCondition( vc.condition, - parents(funDef), + funDef.parent.getOrElse(funDef), if(vc.kind == VCKind.Postcondition) VCKind.InvariantPost else if(vc.kind == VCKind.Precondition) VCKind.InvariantInd else vc.kind, vc.tactic, vc.info).setPosInfo(funDef) -- GitLab