From aab8c54abe5c228255fd7f6e4fe82c35f2236859 Mon Sep 17 00:00:00 2001
From: Manos Koukoutos <emmanouil.koukoutos@epfl.ch>
Date: Fri, 8 Apr 2016 12:02:59 +0200
Subject: [PATCH] Improve simplifiers

---
 src/main/scala/leon/purescala/ExprOps.scala   | 57 ++++++++++++++-----
 .../scala/leon/purescala/GenTreeOps.scala     |  2 +-
 2 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/src/main/scala/leon/purescala/ExprOps.scala b/src/main/scala/leon/purescala/ExprOps.scala
index bc926449c..b7c6dab20 100644
--- a/src/main/scala/leon/purescala/ExprOps.scala
+++ b/src/main/scala/leon/purescala/ExprOps.scala
@@ -187,7 +187,7 @@ object ExprOps extends GenTreeOps[Expr] {
 
       case l @ Let(i,e,b) =>
         val newID = FreshIdentifier(i.name, i.getType, alwaysShowUniqueID = true).copiedFrom(i)
-        Some(Let(newID, e, replaceFromIDs(Map(i -> Variable(newID)), b)))
+        Some(Let(newID, e, replaceFromIDs(Map(i -> Variable(newID)), b)).copiedFrom(l))
 
       case _ => None
     }(expr)
@@ -196,14 +196,14 @@ object ExprOps extends GenTreeOps[Expr] {
   /** Applies the function to the I/O constraint and simplifies the resulting constraint */
   def applyAsMatches(p : Passes, f : Expr => Expr) = {
     f(p.asConstraint) match {
-      case Equals(newOut, MatchExpr(newIn, newCases)) => {
+      case Equals(newOut, MatchExpr(newIn, newCases)) =>
         val filtered = newCases flatMap {
           case MatchCase(p, g, `newOut`) => None
           case other => Some(other)
         }
         Passes(newIn, newOut, filtered)
-      }
-      case other => other
+      case other =>
+        other
     }
   }
 
@@ -217,7 +217,7 @@ object ExprOps extends GenTreeOps[Expr] {
         Some(letTuple(ids, v, tupleSelect(b, ts, true)))
 
       case CaseClassSelector(cct, cc: CaseClass, id) =>
-        Some(caseClassSelector(cct, cc, id))
+        Some(caseClassSelector(cct, cc, id).copiedFrom(e))
 
       case IfExpr(c, thenn, elze) if (thenn == elze) && isPurelyFunctional(c) =>
         Some(thenn)
@@ -229,10 +229,10 @@ object ExprOps extends GenTreeOps[Expr] {
         Some(IfExpr(c, elze, thenn).copiedFrom(e))
 
       case IfExpr(c, BooleanLiteral(false), BooleanLiteral(true)) =>
-        Some(Not(c))
+        Some(Not(c).copiedFrom(e))
 
       case FunctionInvocation(tfd, List(IfExpr(c, thenn, elze))) =>
-        Some(IfExpr(c, FunctionInvocation(tfd, List(thenn)), FunctionInvocation(tfd, List(elze))))
+        Some(IfExpr(c, FunctionInvocation(tfd, List(thenn)), FunctionInvocation(tfd, List(elze))).copiedFrom(e))
 
       case _ =>
         None
@@ -331,12 +331,24 @@ object ExprOps extends GenTreeOps[Expr] {
     * @note the code is simple but far from optimal (many traversals...)
     */
   def simplifyLets(expr: Expr) : Expr = {
-    def simplerLet(t: Expr) : Option[Expr] = t match {
 
-      case letExpr @ Let(i, t: Terminal, b) if isPurelyFunctional(t) =>
-        Some(replaceFromIDs(Map(i -> t), b))
+    def freeComputable(e: Expr) = e match {
+      case TupleSelect(Variable(_), _) => true
+      case CaseClassSelector(_, Variable(_), _) => true
+      case FiniteSet(els, _) => els.isEmpty
+      case FiniteMap(els, _, _) => els.isEmpty
+      case _: Terminal => true
+      case _ => false
+    }
+
+    def simplerLet(t: Expr): Option[Expr] = t match {
 
-      case letExpr @ Let(i,e,b) if isPurelyFunctional(e) =>
+      case Let(i, e, b) if freeComputable(e) && isPurelyFunctional(e) =>
+        // computation is very quick and code easy to read, always inline
+        Some(replaceFromIDs(Map(i -> e), b))
+
+      case Let(i,e,b) if isPurelyFunctional(e) =>
+        // computation may be slow, or code complicated to read, inline at most once
         val occurrences = count {
           case Variable(`i`) => 1
           case _ => 0
@@ -350,8 +362,9 @@ object ExprOps extends GenTreeOps[Expr] {
           None
         }
 
-      case LetPattern(patt, e0, body) if isPurelyFunctional(e0) =>
+      /*case LetPattern(patt, e0, body) if isPurelyFunctional(e0) =>
         // Will turn the match-expression with a single case into a list of lets.
+        // @mk it is not clear at all that we want this
 
         // Just extra safety...
         val e = (e0.getType, patt) match {
@@ -364,13 +377,29 @@ object ExprOps extends GenTreeOps[Expr] {
         }
 
         // Sort lets in dependency order
-        val lets = mapForPattern(e, patt).toList.sortWith {
+        val lets = mapForPattern(e, patt).toSeq.sortWith {
           case ((id1, e1), (id2, e2)) => exists{ _ == Variable(id1) }(e2)
         }
 
         Some(lets.foldRight(body) {
           case ((id, e), bd) => Let(id, e, bd)
-        })
+        })*/
+
+      case MatchExpr(scrut, cases) =>
+        // Merge match within match
+        var changed = false
+        val newCases = cases map {
+          case MatchCase(patt, g, LetPattern(innerPatt, Variable(id), body)) if patt.binders contains id =>
+            changed = true
+            val newPatt = PatternOps.preMap {
+              case WildcardPattern(Some(`id`)) => Some(innerPatt.withBinder(id))
+              case _ => None
+            }(patt)
+            MatchCase(newPatt, g, body)
+          case other =>
+            other
+        }
+        if(changed) Some(MatchExpr(scrut, newCases)) else None
 
       case _ => None
     }
diff --git a/src/main/scala/leon/purescala/GenTreeOps.scala b/src/main/scala/leon/purescala/GenTreeOps.scala
index 435110c41..2b9f1fcc5 100644
--- a/src/main/scala/leon/purescala/GenTreeOps.scala
+++ b/src/main/scala/leon/purescala/GenTreeOps.scala
@@ -23,7 +23,7 @@ trait GenTreeOps[SubTree <: Tree]  {
 
   /** An extractor for [[SubTree]]*/
   val Deconstructor: TreeExtractor[SubTree]
-  
+
   /* ========
    * Core API
    * ========
-- 
GitLab