From 62c98020e9aead3a4cf38914b34c34dccb38e80b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com>
Date: Fri, 15 Apr 2016 01:09:32 +0200
Subject: [PATCH] Function closure makes sure that all ids updated

---
 .../purescala/DefinitionTransformer.scala     |  5 ---
 .../leon/purescala/FunctionClosure.scala      |  3 ++
 .../leon/purescala/TreeTransformer.scala      |  4 +++
 .../purescala/valid/Nested18.scala            | 15 +++++++++
 .../unit/purescala/FunctionClosureSuite.scala | 32 +++++++++++++++++++
 5 files changed, 54 insertions(+), 5 deletions(-)
 create mode 100644 src/test/resources/regression/verification/purescala/valid/Nested18.scala

diff --git a/src/main/scala/leon/purescala/DefinitionTransformer.scala b/src/main/scala/leon/purescala/DefinitionTransformer.scala
index 2588ed8fe..6dfea1dbe 100644
--- a/src/main/scala/leon/purescala/DefinitionTransformer.scala
+++ b/src/main/scala/leon/purescala/DefinitionTransformer.scala
@@ -45,11 +45,6 @@ class DefinitionTransformer(
               idMap += id -> nid
               nid
           })
-        case LetDef(fds, body) =>
-          val rFds = fds map transform
-          val rBody = transform(body)
-          LetDef(rFds, rBody).copiedFrom(e)
-          
         case _ => super.transform(e)
       }
     }
diff --git a/src/main/scala/leon/purescala/FunctionClosure.scala b/src/main/scala/leon/purescala/FunctionClosure.scala
index e69050bf6..98d819eb2 100644
--- a/src/main/scala/leon/purescala/FunctionClosure.scala
+++ b/src/main/scala/leon/purescala/FunctionClosure.scala
@@ -180,6 +180,9 @@ object FunctionClosure extends TransformationPhase {
       case _ => None
     }(instBody)
 
+    //HACK to make sure substitution happened even in nested fundef
+    newFd.fullBody = replaceFromIDs(freeMap.map(p => (p._1, p._2.toVariable)), newFd.fullBody)
+
     FunSubst(newFd, freeMap, tparamsMap.map{ case (from, to) => from.tp -> to})
   }
 
diff --git a/src/main/scala/leon/purescala/TreeTransformer.scala b/src/main/scala/leon/purescala/TreeTransformer.scala
index d74da4f8f..a1f6e2ad6 100644
--- a/src/main/scala/leon/purescala/TreeTransformer.scala
+++ b/src/main/scala/leon/purescala/TreeTransformer.scala
@@ -38,6 +38,10 @@ trait TreeTransformer {
     case LetVar(a, expr, body) =>
       val newA = transform(a)
       LetVar(newA, transform(expr), transform(body)(bindings + (a -> newA))).copiedFrom(e)
+    case LetDef(fds, body) =>
+      val rFds = fds map transform
+      val rBody = transform(body)
+      LetDef(rFds, rBody).copiedFrom(e)
     case CaseClass(cct, args) =>
       CaseClass(transform(cct).asInstanceOf[CaseClassType], args map transform).copiedFrom(e)
     case CaseClassSelector(cct, caseClass, selector) =>
diff --git a/src/test/resources/regression/verification/purescala/valid/Nested18.scala b/src/test/resources/regression/verification/purescala/valid/Nested18.scala
new file mode 100644
index 000000000..a35c2f4b9
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/Nested18.scala
@@ -0,0 +1,15 @@
+object Nested18 {
+
+  def test(a: BigInt): BigInt = {
+    require(a > 0)
+    def f(b: BigInt): BigInt = {
+      def g(c: BigInt): BigInt = {
+        require(a > 0)
+        c
+      }
+      g(b)
+    }
+    f(12)
+  }
+
+}
diff --git a/src/test/scala/leon/unit/purescala/FunctionClosureSuite.scala b/src/test/scala/leon/unit/purescala/FunctionClosureSuite.scala
index faef38195..2019c0452 100644
--- a/src/test/scala/leon/unit/purescala/FunctionClosureSuite.scala
+++ b/src/test/scala/leon/unit/purescala/FunctionClosureSuite.scala
@@ -97,6 +97,38 @@ class FunctionClosureSuite extends FunSuite with helpers.ExpressionsDSL {
         fail("Unexpected fun def: " + cfd)
       }
     })
+
+
+    val deeplyNested2 = new FunDef(FreshIdentifier("deeplyNested"), Seq(), Seq(ValDef(z.id)), IntegerType)
+    deeplyNested2.body = Some(Require(GreaterEquals(x, bi(0)), z))
+
+    val nested2 = new FunDef(FreshIdentifier("nested"), Seq(), Seq(ValDef(y.id)), IntegerType)
+    nested2.body = Some(LetDef(Seq(deeplyNested2), FunctionInvocation(deeplyNested2.typed, Seq(y))))
+
+    val fd2 = new FunDef(FreshIdentifier("f"), Seq(), Seq(ValDef(x.id)), IntegerType)
+    fd2.body = Some(Require(GreaterEquals(x, bi(0)),
+                    LetDef(Seq(nested2), FunctionInvocation(nested2.typed, Seq(x)))))
+
+    val cfds2 = FunctionClosure.close(fd2)
+    assert(cfds2.size === 3)
+
+    cfds2.foreach(cfd => {
+      if(cfd.id.name == "f") {
+        assert(cfd.returnType === fd2.returnType)
+        assert(cfd.params.size === fd2.params.size)
+        assert(freeVars(cfd).isEmpty)
+      } else if(cfd.id.name == "nested") {
+        assert(cfd.returnType === nested2.returnType)
+        assert(cfd.params.size === 2)
+        assert(freeVars(cfd).isEmpty)
+      } else if(cfd.id.name == "deeplyNested") {
+        assert(cfd.returnType === deeplyNested2.returnType)
+        assert(cfd.params.size === 2)
+        assert(freeVars(cfd).isEmpty)
+      } else {
+        fail("Unexpected fun def: " + cfd)
+      }
+    })
   }
 
   private def freeVars(fd: FunDef): Set[Identifier] = variablesOf(fd.fullBody) -- fd.paramIds
-- 
GitLab