From 7128629fb7a60be900a021d01b8d422cc82e09ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com>
Date: Wed, 9 May 2012 15:40:29 +0200
Subject: [PATCH] introduce let expression in each of postcond, precond and boy

---
 src/main/scala/leon/FunctionClosure.scala | 33 ++++++++++++++---------
 testcases/BubbleSort.scala                |  2 +-
 2 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/src/main/scala/leon/FunctionClosure.scala b/src/main/scala/leon/FunctionClosure.scala
index 49c378d2a..85dbdf003 100644
--- a/src/main/scala/leon/FunctionClosure.scala
+++ b/src/main/scala/leon/FunctionClosure.scala
@@ -12,7 +12,6 @@ object FunctionClosure extends Pass {
   private var pathConstraints: List[Expr] = Nil
   private var enclosingLets: List[(Identifier, Expr)] = Nil
   private var newFunDefs: Map[FunDef, FunDef] = Map()
-  private var originalsIds: Map[Identifier, Identifier] = Map()
   private var topLevelFuns: Set[FunDef] = Set()
 
   def apply(program: Program): Program = {
@@ -32,7 +31,6 @@ object FunctionClosure extends Pass {
       val capturedConstraints: Set[Expr] = pathConstraints.toSet
 
       val freshIds: Map[Identifier, Identifier] = capturedVars.map(id => (id, FreshIdentifier(id.name).setType(id.getType))).toMap
-      freshIds.foreach(p => originalsIds += (p._2 -> p._1))
       val freshVars: Map[Expr, Expr] = freshIds.map(p => (p._1.toVariable, p._2.toVariable))
       
       val extraVarDeclOldIds: Seq[Identifier] = capturedVars.toSeq
@@ -48,17 +46,27 @@ object FunctionClosure extends Pass {
       newFunDef.parent = fd.parent
       newFunDef.addAnnotation(fd.annotations.toSeq:_*)
 
-      val newPrecondition = functionClosure(And((capturedConstraints ++ fd.precondition).toSeq), newBindedVars, freshIds, fd2FreshFd)
+      def introduceLets(expr: Expr, fd2FreshFd: Map[FunDef, (FunDef, Seq[Variable])]): Expr = {
+        val (newExpr, _) = enclosingLets.foldLeft((expr, Map[Identifier, Identifier]()))((acc, p) => {
+          val newId = FreshIdentifier(p._1.name).setType(p._1.getType)
+          val newMap = acc._2 + (p._1 -> newId)
+          val newBody = functionClosure(acc._1, newBindedVars, freshIds ++ newMap, fd2FreshFd)
+          (Let(newId, p._2, newBody), newMap)
+        })
+        functionClosure(newExpr, newBindedVars, freshIds, fd2FreshFd)
+      }
+
+
+      val newPrecondition = simplifyLets(introduceLets(And((capturedConstraints ++ fd.precondition).toSeq), fd2FreshFd))
       newFunDef.precondition = if(newPrecondition == BooleanLiteral(true)) None else Some(newPrecondition)
 
-      val freshPostcondition = fd.postcondition.map(expr => functionClosure(expr, newBindedVars, freshIds, fd2FreshFd))
+      val freshPostcondition = fd.postcondition.map(post => introduceLets(post, fd2FreshFd))
       newFunDef.postcondition = freshPostcondition
       
       pathConstraints = fd.precondition.getOrElse(BooleanLiteral(true)) :: pathConstraints
-      val freshBody = fd.body.map(expr => 
-        functionClosure(expr, newBindedVars, freshIds, fd2FreshFd + (fd -> ((newFunDef, extraVarDeclFreshIds.map(_.toVariable))))))
-      pathConstraints = pathConstraints.tail
+      val freshBody = fd.body.map(body => introduceLets(body, fd2FreshFd + (fd -> ((newFunDef, extraVarDeclFreshIds.map(_.toVariable))))))
       newFunDef.body = freshBody
+      pathConstraints = pathConstraints.tail
 
       val freshRest = functionClosure(rest, bindedVars, id2freshId, fd2FreshFd + (fd -> 
                         ((newFunDef, extraVarDeclOldIds.map(id => id2freshId.get(id).getOrElse(id).toVariable)))))
@@ -67,7 +75,7 @@ object FunctionClosure extends Pass {
     case l @ Let(i,e,b) => {
       val re = functionClosure(e, bindedVars, id2freshId, fd2FreshFd)
       //we need the enclosing lets to always refer to the original ids, because it might be expand later in a highly nested function
-      enclosingLets ::= (i, replace(originalsIds.map(p => (p._1.toVariable, p._2.toVariable)), re)) 
+      enclosingLets ::= (i, replace(id2freshId.map(p => (p._2.toVariable, p._1.toVariable)), re)) 
       //pathConstraints :: Equals(i.toVariable, re)
       val rb = functionClosure(b, bindedVars + i, id2freshId, fd2FreshFd)
       enclosingLets = enclosingLets.tail
@@ -111,13 +119,14 @@ object FunctionClosure extends Pass {
       m
     }
     case v @ Variable(id) => id2freshId.get(id) match {
-      case None => replace(
+      case None => v
+      case Some(nid) => Variable(nid)
+    }
+          /*replace(
                      id2freshId.map(p => (p._1.toVariable, p._2.toVariable)),
                      enclosingLets.foldLeft(v: Expr){ 
                        case (expr, (id, value)) => replace(Map(id.toVariable -> value), expr) 
-                     })
-      case Some(nid) => Variable(nid)
-    }
+                     })*/
     case t if t.isInstanceOf[Terminal] => t
     case unhandled => scala.sys.error("Non-terminal case should be handled in FunctionClosure: " + unhandled)
   }
diff --git a/testcases/BubbleSort.scala b/testcases/BubbleSort.scala
index 46ae7c5e6..39fa6dfb9 100644
--- a/testcases/BubbleSort.scala
+++ b/testcases/BubbleSort.scala
@@ -5,7 +5,7 @@ import leon.Utils._
 object BubbleSort {
 
   def sort(a: Array[Int]): Array[Int] = ({
-    require(a.length >= 5)
+    require(a.length >= 0)
     var i = a.length - 1
     var j = 0
     val sa = a
-- 
GitLab