From c6ed682f6fa19cf92ca35e882a0e23810ceb3bd0 Mon Sep 17 00:00:00 2001
From: Philippe Suter <philippe.suter@gmail.com>
Date: Wed, 19 Dec 2012 17:59:47 +0100
Subject: [PATCH] Simplifications for LetTuple.

This commit also introduces new runtime checks when contructing
instances of LetTuple or TupleSelect, to ensure that types are correctly
set.
---
 src/main/scala/leon/purescala/TreeOps.scala   | 33 +++++++++++++++++--
 src/main/scala/leon/purescala/Trees.scala     | 11 ++++++-
 .../synthesis/heuristics/ADTInduction.scala   |  2 +-
 3 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala
index ff30df5c9..1b5a4bb9f 100644
--- a/src/main/scala/leon/purescala/TreeOps.scala
+++ b/src/main/scala/leon/purescala/TreeOps.scala
@@ -461,7 +461,9 @@ object TreeOps {
    */
   def simplifyLets(expr: Expr) : Expr = {
     def simplerLet(t: Expr) : Option[Expr] = t match {
+
       case letExpr @ Let(i, t: Terminal, b) => Some(replace(Map((Variable(i) -> t)), b))
+
       case letExpr @ Let(i,e,b) => {
         val occurences = treeCatamorphism[Int]((e:Expr) => e match {
           case Variable(x) if x == i => 1
@@ -475,8 +477,6 @@ object TreeOps {
           None
         }
       }
-      //case letTuple @ LetTuple(ids, expr, body) if ids.size == 1 =>
-      //  simplerLet(Let(ids.head, TupleSelect(expr, 1).setType(ids.head.getType), body))
 
       case letTuple @ LetTuple(ids, Tuple(exprs), body) =>
 
@@ -511,6 +511,35 @@ object TreeOps {
         } else {
           Some(LetTuple(remIds, Tuple(remExprs), newBody))
         }
+
+      case l @ LetTuple(ids, tExpr, body) =>
+        val TupleType(types) = tExpr.getType
+        val arity = ids.size
+        // A map containing vectors of the form (0, ..., 1, ..., 0) where the one corresponds to the index of the identifier in the
+        // LetTuple. The idea is that we can sum such vectors up to compute the occurences of all variables in one traversal of the
+        // expression.
+        val zeroVec = Seq.fill(arity)(0)
+        val idMap   = ids.zipWithIndex.toMap.mapValues(i => zeroVec.updated(i, 1))
+
+        val occurences : Seq[Int] = treeCatamorphism[Seq[Int]]((e : Expr) => e match {
+          case Variable(x) => idMap.getOrElse(x, zeroVec)
+          case _ => zeroVec
+        }, (v1 : Seq[Int], v2 : Seq[Int]) => (v1 zip v2).map(p => p._1  + p._2), body)
+
+        val total = occurences.sum
+
+        if(total == 0) {
+          Some(body)
+        } else if(total == 1) {
+          val substMap : Map[Expr,Expr] = ids.map(Variable(_) : Expr).zipWithIndex.toMap.map {
+            case (v,i) => (v -> TupleSelect(tExpr, i + 1).setType(v.getType))
+          }
+
+          Some(replace(substMap, body))
+        } else {
+          None
+        }
+
       case _ => None 
     }
     searchAndReplaceDFS(simplerLet)(expr)
diff --git a/src/main/scala/leon/purescala/Trees.scala b/src/main/scala/leon/purescala/Trees.scala
index c783bbb04..4f88d3eb8 100644
--- a/src/main/scala/leon/purescala/Trees.scala
+++ b/src/main/scala/leon/purescala/Trees.scala
@@ -37,6 +37,7 @@ object Trees {
 
   case class LetTuple(binders: Seq[Identifier], value: Expr, body: Expr) extends Expr {
     binders.foreach(_.markAsLetBinder)
+    assert(value.getType.isInstanceOf[TupleType])
     val et = body.getType
     if(et != Untyped)
       setType(et)
@@ -58,8 +59,16 @@ object Trees {
   }
 
   // This must be 1-indexed ! (So are methods of Scala Tuples)
-  case class TupleSelect(tuple: Expr, index: Int) extends Expr {
+  case class TupleSelect(tuple: Expr, index: Int) extends Expr with FixedType {
     assert(index >= 1)
+
+    val fixedType : TypeTree = tuple.getType match {
+      case TupleType(ts) => 
+        assert(index <= ts.size)
+        ts(index - 1)
+
+      case _ => assert(false); Untyped
+    }
   }
 
   object MatchExpr {
diff --git a/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala b/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala
index 4cb8f2285..1c50c18c8 100644
--- a/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala
+++ b/src/main/scala/leon/synthesis/heuristics/ADTInduction.scala
@@ -90,7 +90,7 @@ case object ADTInduction extends Rule("ADT Induction") with Heuristic {
             val outerPre = Or(globalPre)
 
             newFun.precondition = Some(funPre)
-            newFun.postcondition = Some(LetTuple(p.xs.toSeq, ResultVariable(), p.phi))
+            newFun.postcondition = Some(LetTuple(p.xs.toSeq, ResultVariable().setType(resType), p.phi))
 
             newFun.body = Some(MatchExpr(Variable(inductOn), cases))
 
-- 
GitLab