From 32d53a55d219b144c33e7d50b31ea4fea687987c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com>
Date: Tue, 18 Dec 2012 20:05:35 +0100
Subject: [PATCH] Implement a new XlangAnalysisPhase

This commit introduces a new XlangAnalysisPhase that run
all the xlang phase as well as the AnalysisPhase. It updates
the Main accordingly.

The reason for this change is to be able to correctly control
the --functions option as well as transforming each VerificationCondition
about function postcondition into loop invariant.

The previous solution was to use some mutable states inside the FunDef object.
Those are cleaned by this commit. To do so, it was necessary to change the
transformation phases signature in order to return along with the modified
program a Set or Map (depending on which phase) of freshly introduced
functions and their correspondance in the original program.

One small change that was necessary was to not print the verification report
in the analysis phase but only in the Main. This allows the XlangAnalysisPhase
to update correctly the verification conditions in the report before it gets
printed. This is also arguably a better design decision to have it printed
in the Main since it was returned by the AnalysisPhase.
---
 src/main/scala/leon/LeonOption.scala          |  1 +
 src/main/scala/leon/Main.scala                | 21 ++---
 src/main/scala/leon/TypeChecking.scala        |  2 -
 src/main/scala/leon/UnitElimination.scala     |  4 -
 .../scala/leon/purescala/Definitions.scala    |  5 --
 .../leon/verification/AnalysisPhase.scala     |  1 -
 .../leon/verification/DefaultTactic.scala     | 25 +++---
 .../verification/VerificationCondition.scala  |  1 +
 .../leon/xlang/ArrayTransformation.scala      |  4 -
 .../scala/leon/xlang/FunctionClosure.scala    | 27 +++++--
 .../xlang/ImperativeCodeElimination.scala     | 16 ++--
 src/main/scala/leon/xlang/Trees.scala         | 16 ----
 .../scala/leon/xlang/XlangAnalysisPhase.scala | 80 +++++++++++++++++++
 .../XLangVerificationRegression.scala         |  7 +-
 14 files changed, 130 insertions(+), 80 deletions(-)
 create mode 100644 src/main/scala/leon/xlang/XlangAnalysisPhase.scala

diff --git a/src/main/scala/leon/LeonOption.scala b/src/main/scala/leon/LeonOption.scala
index 40cd6c23f..da28a90d5 100644
--- a/src/main/scala/leon/LeonOption.scala
+++ b/src/main/scala/leon/LeonOption.scala
@@ -40,5 +40,6 @@ case class LeonValueOptionDef(name: String, usageOption: String, usageDesc: Stri
 }
 
 object ListValue {
+  def apply(values: Seq[String]) = values.mkString(":")
   def unapply(value: String): Option[Seq[String]] = Some(value.split(':').map(_.trim).filter(!_.isEmpty))
 }
diff --git a/src/main/scala/leon/Main.scala b/src/main/scala/leon/Main.scala
index 26477afd3..56d66e601 100644
--- a/src/main/scala/leon/Main.scala
+++ b/src/main/scala/leon/Main.scala
@@ -9,6 +9,7 @@ object Main {
       xlang.EpsilonElimination,
       xlang.ImperativeCodeElimination,
       xlang.FunctionClosure,
+      xlang.XlangAnalysisPhase,
       synthesis.SynthesisPhase,
       verification.AnalysisPhase
     )
@@ -118,16 +119,6 @@ object Main {
 
     val pipeBegin : Pipeline[List[String],Program] = plugin.ExtractionPhase
 
-    val pipeTransforms: Pipeline[Program, Program] =
-      if (settings.xlang) {
-        xlang.ArrayTransformation andThen
-        xlang.EpsilonElimination andThen
-        xlang.ImperativeCodeElimination andThen
-        xlang.FunctionClosure
-      } else {
-        NoopPhase()
-      }
-
     val pipeSynthesis: Pipeline[Program, Program]=
       if (settings.synthesis) {
         synthesis.SynthesisPhase
@@ -136,14 +127,15 @@ object Main {
       }
 
     val pipeVerify: Pipeline[Program, Any] =
-      if (settings.verify) {
+      if (settings.xlang) {
+        xlang.XlangAnalysisPhase
+      } else if (settings.verify) {
         verification.AnalysisPhase
       } else {
         NoopPhase()
       }
 
     pipeBegin andThen
-    pipeTransforms andThen
     pipeSynthesis andThen
     pipeVerify
   }
@@ -159,7 +151,10 @@ object Main {
 
     try {
       // Run pipeline
-      pipeline.run(ctx)(args.toList)
+      pipeline.run(ctx)(args.toList) match {
+        case (report: verification.VerificationReport) => reporter.info(report.summaryString)
+        case _ =>
+      }
     } catch {
       case LeonFatalError() => sys.exit(1)
     }
diff --git a/src/main/scala/leon/TypeChecking.scala b/src/main/scala/leon/TypeChecking.scala
index 08291badc..41cda6b80 100644
--- a/src/main/scala/leon/TypeChecking.scala
+++ b/src/main/scala/leon/TypeChecking.scala
@@ -87,8 +87,6 @@ object TypeChecking extends UnitPhase[Program] {
     //        val freshFunName = FreshIdentifier(fd.id.name)
     //        val freshFunDef = new FunDef(freshFunName, transform(fd.returnType), newArgs)
     //        fd2fd += (fd -> freshFunDef)
-    //        freshFunDef.fromLoop = fd.fromLoop
-    //        freshFunDef.parent = fd.parent
     //        freshFunDef.precondition = fd.precondition.map(transform)
     //        freshFunDef.postcondition = fd.postcondition.map(transform)
     //        freshFunDef.addAnnotation(fd.annotations.toSeq:_*)
diff --git a/src/main/scala/leon/UnitElimination.scala b/src/main/scala/leon/UnitElimination.scala
index 3d56d5377..dc58a24be 100644
--- a/src/main/scala/leon/UnitElimination.scala
+++ b/src/main/scala/leon/UnitElimination.scala
@@ -23,8 +23,6 @@ object UnitElimination extends TransformationPhase {
     allFuns.foreach(fd => {
       if(fd.returnType != UnitType && fd.args.exists(vd => vd.tpe == UnitType)) {
         val freshFunDef = new FunDef(FreshIdentifier(fd.id.name), fd.returnType, fd.args.filterNot(vd => vd.tpe == UnitType)).setPosInfo(fd)
-        freshFunDef.fromLoop = fd.fromLoop
-        freshFunDef.parent = fd.parent
         freshFunDef.precondition = fd.precondition //TODO: maybe removing unit from the conditions as well..
         freshFunDef.postcondition = fd.postcondition//TODO: maybe removing unit from the conditions as well..
         freshFunDef.addAnnotation(fd.annotations.toSeq:_*)
@@ -102,8 +100,6 @@ object UnitElimination extends TransformationPhase {
           val (newFd, rest) = if(fd.args.exists(vd => vd.tpe == UnitType)) {
             val freshFunDef = new FunDef(FreshIdentifier(fd.id.name), fd.returnType, fd.args.filterNot(vd => vd.tpe == UnitType)).setPosInfo(fd)
             freshFunDef.addAnnotation(fd.annotations.toSeq:_*)
-            freshFunDef.parent = fd.parent
-            freshFunDef.fromLoop = fd.fromLoop
             freshFunDef.precondition = fd.precondition //TODO: maybe removing unit from the conditions as well..
             freshFunDef.postcondition = fd.postcondition//TODO: maybe removing unit from the conditions as well..
             fun2FreshFun += (fd -> freshFunDef)
diff --git a/src/main/scala/leon/purescala/Definitions.scala b/src/main/scala/leon/purescala/Definitions.scala
index 6eee2247c..80f1df984 100644
--- a/src/main/scala/leon/purescala/Definitions.scala
+++ b/src/main/scala/leon/purescala/Definitions.scala
@@ -313,11 +313,6 @@ object Definitions {
     var precondition: Option[Expr] = None
     var postcondition: Option[Expr] = None
 
-    //true if this function has been generated from a while loop
-    var fromLoop = false
-    //the fundef where the loop was defined (if applies)
-    var parent: Option[FunDef] = None
-
     def hasImplementation : Boolean = body.isDefined
     def hasBody = hasImplementation
     def hasPrecondition : Boolean = precondition.isDefined
diff --git a/src/main/scala/leon/verification/AnalysisPhase.scala b/src/main/scala/leon/verification/AnalysisPhase.scala
index 2e340cac1..146f8bb2d 100644
--- a/src/main/scala/leon/verification/AnalysisPhase.scala
+++ b/src/main/scala/leon/verification/AnalysisPhase.scala
@@ -148,7 +148,6 @@ object AnalysisPhase extends LeonPhase[Program,VerificationReport] {
       } 
 
       val report = new VerificationReport(vcs)
-      reporter.info(report.summaryString)
       report
     }
 
diff --git a/src/main/scala/leon/verification/DefaultTactic.scala b/src/main/scala/leon/verification/DefaultTactic.scala
index 47a2af0d2..cdc752a50 100644
--- a/src/main/scala/leon/verification/DefaultTactic.scala
+++ b/src/main/scala/leon/verification/DefaultTactic.scala
@@ -44,10 +44,7 @@ class DefaultTactic(reporter: Reporter) extends Tactic(reporter) {
 
           withPrec
         }
-        if(functionDefinition.fromLoop)
-          Seq(new VerificationCondition(theExpr, functionDefinition.parent.get, VCKind.InvariantPost, this.asInstanceOf[DefaultTactic]).setPosInfo(functionDefinition))
-        else
-          Seq(new VerificationCondition(theExpr, functionDefinition, VCKind.Postcondition, this.asInstanceOf[DefaultTactic]))
+        Seq(new VerificationCondition(theExpr, functionDefinition, VCKind.Postcondition, this.asInstanceOf[DefaultTactic]))
       }
     }
   
@@ -76,13 +73,13 @@ class DefaultTactic(reporter: Reporter) extends Tactic(reporter) {
           val newBody : Expr = replace(substMap, prec)
           val newCall : Expr = (newLetIDs zip args).foldRight(newBody)((iap, e) => Let(iap._1, iap._2, e))
 
-          if(fd.fromLoop)
-            new VerificationCondition(
-              withPrecIfDefined(path, newCall),
-              fd.parent.get,
-              if(fd == function) VCKind.InvariantInd else VCKind.InvariantInit,
-              this.asInstanceOf[DefaultTactic]).setPosInfo(fd)
-          else
+          //if(fd.fromLoop)
+          //  new VerificationCondition(
+          //    withPrecIfDefined(path, newCall),
+          //    fd.parent.get,
+          //    if(fd == function) VCKind.InvariantInd else VCKind.InvariantInit,
+          //    this.asInstanceOf[DefaultTactic]).setPosInfo(fd)
+          //else
             new VerificationCondition(
               withPrecIfDefined(path, newCall),
               function,
@@ -117,7 +114,7 @@ class DefaultTactic(reporter: Reporter) extends Tactic(reporter) {
         allPathConds.map(pc => 
           new VerificationCondition(
             withPrecIfDefined(pc._1),
-            if(function.fromLoop) function.parent.get else function,
+            function,//if(function.fromLoop) function.parent.get else function,
             VCKind.ExhaustiveMatch,
             this.asInstanceOf[DefaultTactic]).setPosInfo(pc._2.asInstanceOf[Error])
         ).toSeq
@@ -149,7 +146,7 @@ class DefaultTactic(reporter: Reporter) extends Tactic(reporter) {
         allPathConds.map(pc =>
           new VerificationCondition(
             withPrecIfDefined(pc._1),
-            if(function.fromLoop) function.parent.get else function,
+            function, //if(function.fromLoop) function.parent.get else function,
             VCKind.MapAccess,
             this.asInstanceOf[DefaultTactic]).setPosInfo(pc._2.asInstanceOf[Error])
         ).toSeq
@@ -178,7 +175,7 @@ class DefaultTactic(reporter: Reporter) extends Tactic(reporter) {
         allPathConds.map(pc =>
           new VerificationCondition(
             withPrecIfDefined(pc._1),
-            if(function.fromLoop) function.parent.get else function,
+            function, //if(function.fromLoop) function.parent.get else function,
             VCKind.ArrayAccess,
             this.asInstanceOf[DefaultTactic]).setPosInfo(pc._2.asInstanceOf[Error])
         ).toSeq
diff --git a/src/main/scala/leon/verification/VerificationCondition.scala b/src/main/scala/leon/verification/VerificationCondition.scala
index 573bcd699..893fb39b3 100644
--- a/src/main/scala/leon/verification/VerificationCondition.scala
+++ b/src/main/scala/leon/verification/VerificationCondition.scala
@@ -42,4 +42,5 @@ object VCKind extends Enumeration {
   val InvariantInit = Value("inv init.")
   val InvariantInd = Value("inv ind.")
   val InvariantPost = Value("inv post.")
+  val InvariantPre = Value("inv pre.")
 }
diff --git a/src/main/scala/leon/xlang/ArrayTransformation.scala b/src/main/scala/leon/xlang/ArrayTransformation.scala
index 880e870f5..4a9017597 100644
--- a/src/main/scala/leon/xlang/ArrayTransformation.scala
+++ b/src/main/scala/leon/xlang/ArrayTransformation.scala
@@ -142,8 +142,6 @@ object ArrayTransformation extends TransformationPhase {
     //      val freshFunName = FreshIdentifier(fd.id.name)
     //      val freshFunDef = new FunDef(freshFunName, transform(fd.returnType), newArgs)
     //      fd2fd += (fd -> freshFunDef)
-    //      freshFunDef.fromLoop = fd.fromLoop
-    //      freshFunDef.parent = fd.parent
     //      freshFunDef.addAnnotation(fd.annotations.toSeq:_*)
     //      freshFunDef
     //    } else fd
@@ -272,8 +270,6 @@ object ArrayTransformation extends TransformationPhase {
   //          val freshFunName = FreshIdentifier(fd.id.name)
   //          val freshFunDef = new FunDef(freshFunName, transform(fd.returnType), newArgs)
   //          fd2fd += (fd -> freshFunDef)
-  //          freshFunDef.fromLoop = fd.fromLoop
-  //          freshFunDef.parent = fd.parent
   //          freshFunDef.precondition = fd.precondition.map(transform)
   //          freshFunDef.postcondition = fd.postcondition.map(transform)
   //          freshFunDef.addAnnotation(fd.annotations.toSeq:_*)
diff --git a/src/main/scala/leon/xlang/FunctionClosure.scala b/src/main/scala/leon/xlang/FunctionClosure.scala
index 47e0cbeed..c6fc16e1f 100644
--- a/src/main/scala/leon/xlang/FunctionClosure.scala
+++ b/src/main/scala/leon/xlang/FunctionClosure.scala
@@ -1,4 +1,5 @@
-package leon.xlang
+package leon
+package xlang
 
 import leon.TransformationPhase
 import leon.LeonContext
@@ -10,31 +11,41 @@ import leon.purescala.TreeOps._
 import leon.purescala.TypeTrees._
 import leon.xlang.Trees._
 
-object FunctionClosure extends TransformationPhase{
+object FunctionClosure extends LeonPhase[Program, (Program, Map[FunDef, FunDef], Map[FunDef, FunDef])] {
 
   val name = "Function Closure"
   val description = "Closing function with its scoping variables"
 
+  /* I know, that's a lot of mutable variables */
   private var pathConstraints: List[Expr] = Nil
   private var enclosingLets: List[(Identifier, Expr)] = Nil
   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 */
 
-  def apply(ctx: LeonContext, program: Program): Program = {
+  //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]) = {
 
     pathConstraints = Nil
     enclosingLets  = Nil
     newFunDefs  = Map()
     topLevelFuns = Set()
+    parent = null
+    parents = Map()
+    freshFunDefs = Map()
 
     val funDefs = program.definedFunctions
     funDefs.foreach(fd => {
+      parent = fd
       pathConstraints = fd.precondition.toList
       fd.body = fd.body.map(b => functionClosure(b, fd.args.map(_.id).toSet, Map(), Map()))
     })
     val Program(id, ObjectDef(objId, defs, invariants)) = program
     val res = Program(id, ObjectDef(objId, defs ++ topLevelFuns, invariants))
-    res
+    (res, parents, freshFunDefs)
   }
 
   private def functionClosure(expr: Expr, bindedVars: Set[Identifier], id2freshId: Map[Identifier, Identifier], fd2FreshFd: Map[FunDef, (FunDef, Seq[Variable])]): Expr = expr match {
@@ -50,13 +61,13 @@ object FunctionClosure extends TransformationPhase{
       val extraVarDecls: Seq[VarDecl] = extraVarDeclFreshIds.map(id =>  VarDecl(id, id.getType))
       val newVarDecls: Seq[VarDecl] = fd.args ++ extraVarDecls
       val newBindedVars: Set[Identifier] = bindedVars ++ fd.args.map(_.id)
-      val newFunId = FreshIdentifier(fd.id.name)
+      val newFunId = FreshIdentifier(fd.id.uniqueName) //since we hoist this at the top level, we need to make it a unique name
 
       val newFunDef = new FunDef(newFunId, fd.returnType, newVarDecls).setPosInfo(fd)
       topLevelFuns += newFunDef
-      newFunDef.fromLoop = fd.fromLoop
-      newFunDef.parent = fd.parent
-      newFunDef.addAnnotation(fd.annotations.toSeq:_*)
+      newFunDef.addAnnotation(fd.annotations.toSeq:_*) //TODO: this is still some dangerous side effects
+      parents += (newFunDef -> parent)
+      freshFunDefs += (fd -> newFunDef)
 
       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/ImperativeCodeElimination.scala b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala
index b926893cd..656104b92 100644
--- a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala
+++ b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala
@@ -1,4 +1,5 @@
-package leon.xlang
+package leon
+package xlang
 
 import leon.TransformationPhase
 import leon.LeonContext
@@ -10,16 +11,18 @@ import leon.purescala.TypeTrees._
 import leon.purescala.TreeOps._
 import leon.xlang.Trees._
 
-object ImperativeCodeElimination extends TransformationPhase {
+object ImperativeCodeElimination extends LeonPhase[Program, (Program, Set[FunDef])] {
 
   val name = "Imperative Code Elimination"
   val description = "Transform imperative constructs into purely functional code"
 
   private var varInScope = Set[Identifier]()
   private var parent: FunDef = null //the enclosing fundef
+  private var wasLoop: Set[FunDef] = null //record FunDef that are the transformation of loops
 
-  def apply(ctx: LeonContext, pgm: Program): Program = {
+  def run(ctx: LeonContext)(pgm: Program): (Program, Set[FunDef]) = {
     varInScope = Set()
+    wasLoop = Set()
     parent = null
 
     val allFuns = pgm.definedFunctions
@@ -28,7 +31,7 @@ object ImperativeCodeElimination extends TransformationPhase {
       val (res, scope, _) = toFunction(body)
       fd.body = Some(scope(res))
     }))
-    pgm
+    (pgm, wasLoop)
   }
 
   //return a "scope" consisting of purely functional code that defines potentially needed 
@@ -150,9 +153,8 @@ object ImperativeCodeElimination extends TransformationPhase {
           val modifiedVars2WhileFunVars = modifiedVars.zip(whileFunVars).toMap
           val whileFunVarDecls = whileFunVars.map(id => VarDecl(id, id.getType))
           val whileFunReturnType = if(whileFunVars.size == 1) whileFunVars.head.getType else TupleType(whileFunVars.map(_.getType))
-          val whileFunDef = new FunDef(FreshIdentifier("while"), whileFunReturnType, whileFunVarDecls).setPosInfo(wh)
-          whileFunDef.fromLoop = true
-          whileFunDef.parent = Some(parent)
+          val whileFunDef = new FunDef(FreshIdentifier(parent.id.name), whileFunReturnType, whileFunVarDecls).setPosInfo(wh)
+          wasLoop += whileFunDef
           
           val whileFunCond = condRes
           val whileFunRecursiveCall = replaceNames(condFun,
diff --git a/src/main/scala/leon/xlang/Trees.scala b/src/main/scala/leon/xlang/Trees.scala
index 31c717784..13fded9dc 100644
--- a/src/main/scala/leon/xlang/Trees.scala
+++ b/src/main/scala/leon/xlang/Trees.scala
@@ -261,8 +261,6 @@ object Trees {
             case (None, None) =>
                 Some((Seq(b, body), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.body = Some(as(0))
                   //LetDef(nfd, as(1))
                   fd.body = Some(as(0))
@@ -271,8 +269,6 @@ object Trees {
             case (Some(pre), None) =>
                 Some((Seq(b, body, pre), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.body = Some(as(0))
                   //nfd.precondition = Some(as(2))
                   //LetDef(nfd, as(1))
@@ -283,8 +279,6 @@ object Trees {
             case (None, Some(post)) =>
                 Some((Seq(b, body, post), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.body = Some(as(0))
                   //nfd.postcondition = Some(as(2))
                   //LetDef(nfd, as(1))
@@ -295,8 +289,6 @@ object Trees {
             case (Some(pre), Some(post)) =>
                 Some((Seq(b, body, pre, post), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.body = Some(as(0))
                   //nfd.precondition = Some(as(2))
                   //nfd.postcondition = Some(as(3))
@@ -313,16 +305,12 @@ object Trees {
             case (None, None) =>
                 Some((Seq(body), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //LetDef(nfd, as(0))
                   LetDef(fd, as(0))
                 }))
             case (Some(pre), None) =>
                 Some((Seq(body, pre), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.precondition = Some(as(1))
                   //LetDef(nfd, as(0))
                   fd.precondition = Some(as(1))
@@ -331,8 +319,6 @@ object Trees {
             case (None, Some(post)) =>
                 Some((Seq(body, post), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.postcondition = Some(as(1))
                   //LetDef(nfd, as(0))
                   fd.postcondition = Some(as(1))
@@ -341,8 +327,6 @@ object Trees {
             case (Some(pre), Some(post)) =>
                 Some((Seq(body, pre, post), (as: Seq[Expr]) => {
                   //val nfd = new FunDef(fd.id, fd.returnType, fd.args)
-                  //nfd.fromLoop = fd.fromLoop
-                  //nfd.parent = fd.parent
                   //nfd.precondition = Some(as(1))
                   //nfd.postcondition = Some(as(2))
                   //LetDef(nfd, as(0))
diff --git a/src/main/scala/leon/xlang/XlangAnalysisPhase.scala b/src/main/scala/leon/xlang/XlangAnalysisPhase.scala
new file mode 100644
index 000000000..4f29e272f
--- /dev/null
+++ b/src/main/scala/leon/xlang/XlangAnalysisPhase.scala
@@ -0,0 +1,80 @@
+package leon
+package xlang
+
+import leon.purescala.Definitions._
+import leon.verification._
+
+object XlangAnalysisPhase extends LeonPhase[Program, VerificationReport] {
+
+  val name = "xlang analysis"
+  val description = "apply analysis on xlang"
+
+  def run(ctx: LeonContext)(pgm: 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 originalFunDefs = freshFunDefs.map(x => (x._2, x._1))
+
+    def functionWasLoop(fd: FunDef): Boolean = originalFunDefs.get(fd) 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
+
+    val newOptions = ctx.options map {
+      case LeonValueOption("functions", ListValue(fs)) => {
+        var freshToAnalyse: Set[String] = Set()
+        fs.foreach((toAnalyse: String) => {
+          pgm.definedFunctions.find(_.id.name == toAnalyse) match {
+            case Some(fd) => {
+              val children = subFunctionsOf(fd)
+              freshToAnalyse ++= children.map(_.id.name)
+              freshToAnalyse += fd.id.name
+            }
+            case None =>
+          }
+        })
+        
+        LeonValueOption("functions", ListValue(freshToAnalyse.toList))
+      }
+      case opt => opt
+    }
+    val vr = AnalysisPhase.run(ctx.copy(options = newOptions))(pgm4)
+    val vcs = vr.conditions
+
+    //this is enough to convert invariant postcondition and inductive conditions. However the initial validity
+    //of the invariant (before entering the loop) will still appear as a regular function precondition
+    //To fix this, we need some information in the VCs about which function the precondtion refers to
+    //although we could arguably say that the term precondition is general enough to refer both to a loop invariant
+    //precondition and a function invocation precondition
+    val freshVcs = vcs.map(vc => {
+      val funDef = vc.funDef
+      if(functionWasLoop(funDef)) {
+        val freshVc = new VerificationCondition(
+          vc.condition, 
+          parents(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)
+        freshVc.value = vc.value
+        freshVc.solvedWith = vc.solvedWith
+        freshVc.time = vc.time
+        freshVc
+      } else vc
+    })
+
+    val sortedFreshVcs = freshVcs.sortWith((vc1, vc2) => {
+      val id1 = vc1.funDef.id.name
+      val id2 = vc2.funDef.id.name
+      if(id1 != id2) id1 < id2 else vc1 < vc2
+    })
+
+    new VerificationReport(sortedFreshVcs)
+  }
+
+}
diff --git a/src/test/scala/leon/test/verification/XLangVerificationRegression.scala b/src/test/scala/leon/test/verification/XLangVerificationRegression.scala
index 4102f5b87..f5b33c3e2 100644
--- a/src/test/scala/leon/test/verification/XLangVerificationRegression.scala
+++ b/src/test/scala/leon/test/verification/XLangVerificationRegression.scala
@@ -19,12 +19,7 @@ class XLangVerificationRegression extends FunSuite {
   private case class Output(report : VerificationReport, reporter : Reporter)
 
   private def mkPipeline : Pipeline[List[String],VerificationReport] =
-    leon.plugin.ExtractionPhase andThen       
-    xlang.ArrayTransformation andThen
-    xlang.EpsilonElimination andThen
-    xlang.ImperativeCodeElimination andThen
-    xlang.FunctionClosure andThen
-    leon.verification.AnalysisPhase
+    leon.plugin.ExtractionPhase andThen xlang.XlangAnalysisPhase
 
   private def mkTest(file : File, forError: Boolean = false)(block: Output=>Unit) = {
     val fullName = file.getPath()
-- 
GitLab