From 0727d73afd6152410bb8ecc254864fbfdcc94154 Mon Sep 17 00:00:00 2001
From: "Emmanouil (Manos) Koukoutos" <emmanouil.koukoutos@epfl.ch>
Date: Fri, 14 Nov 2014 16:23:48 +0100
Subject: [PATCH] Deprecate patternMatchReconstruction, minimize use of
 matchToIfThenElse

---
 .../scala/leon/codegen/CodeGeneration.scala   |  26 +-
 .../scala/leon/codegen/CompilationUnit.scala  |   2 -
 src/main/scala/leon/purescala/TreeOps.scala   | 485 +++++++++---------
 .../scala/leon/synthesis/rules/Cegis.scala    |   4 +-
 src/main/scala/leon/utils/Simplifiers.scala   |   7 -
 .../leon/verification/DefaultTactic.scala     |   8 +-
 .../leon/verification/InductionTactic.scala   |  12 +-
 src/main/scala/leon/verification/Tactic.scala |   7 +-
 .../regression/transformations/Match.scala    |  46 --
 .../test/purescala/TransformationTests.scala  |   5 -
 10 files changed, 280 insertions(+), 322 deletions(-)
 delete mode 100644 src/test/resources/regression/transformations/Match.scala

diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index 33c5f9db0..493efc40e 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -6,7 +6,7 @@ package codegen
 import purescala.Common._
 import purescala.Definitions._
 import purescala.Trees._
-import purescala.TreeOps.simplestValue
+import purescala.TreeOps.{simplestValue, matchToIfThenElse}
 import purescala.TypeTrees._
 import purescala.TypeTreeOps.instantiateType
 import utils._
@@ -180,14 +180,12 @@ trait CodeGeneration {
       bodyWithPre
     }
 
-    val exprToCompile = purescala.TreeOps.matchToIfThenElse(bodyWithPost)
-
     if (params.recordInvocations) {
       // index of monitor object will be before the first Scala parameter
       ch << ALoad(paramsOffset-1) << InvokeVirtual(MonitorClass, "onInvoke", "()V") 
     }
 
-    mkExpr(exprToCompile, ch)(Locals(newMapping, Map.empty, Map.empty, isStatic))
+    mkExpr(bodyWithPost, ch)(Locals(newMapping, Map.empty, Map.empty, isStatic))
 
     funDef.returnType match {
       case Int32Type | BooleanType | UnitType =>
@@ -700,6 +698,9 @@ trait CodeGeneration {
       case This(ct) =>
         ch << ALoad(0) // FIXME what if doInstrument etc
         
+      case m : MatchExpr => 
+        mkExpr(matchToIfThenElse(m), ch)
+      
       case b if b.getType == BooleanType && canDelegateToMkBranch =>
         val fl = ch.getFreshLabel("boolfalse")
         val al = ch.getFreshLabel("boolafter")
@@ -865,6 +866,19 @@ trait CodeGeneration {
         mkExpr(l, ch)
         mkExpr(r, ch)
         ch << If_ICmpGe(thenn) << Goto(elze) 
+  
+      case IfExpr(c, t, e) => 
+        val innerThen = ch.getFreshLabel("then")
+        val innerElse = ch.getFreshLabel("else")
+        mkBranch(c, innerThen, innerElse, ch)
+        ch << Label(innerThen)
+        mkBranch(t, thenn, elze, ch)
+        ch << Label(innerElse)
+        mkBranch(e, thenn, elze, ch)
+
+      case cci@CaseClassInstanceOf(cct, e) =>
+        mkExpr(cci, ch)
+        ch << IfEq(elze) << Goto(thenn)
 
       case other if canDelegateToMkExpr =>
         mkExpr(other, ch, canDelegateToMkBranch = false)
@@ -943,7 +957,7 @@ trait CodeGeneration {
         METHOD_ACC_PUBLIC
       }) 
       val ch = accM.codeHandler
-      val body = purescala.TreeOps.matchToIfThenElse(lzy.body.getOrElse(throw CompilationException("Lazy field without body?")))
+      val body = lzy.body.getOrElse(throw CompilationException("Lazy field without body?"))
       val initLabel = ch.getFreshLabel("isInitialized")
       
       if (params.requireMonitor) {
@@ -1038,7 +1052,7 @@ trait CodeGeneration {
     val body = field.body.getOrElse(throw CompilationException("No body for field?"))
     val jvmType = typeToJVM(field.returnType)
     
-    mkExpr(purescala.TreeOps.matchToIfThenElse(body), ch)(NoLocals(isStatic)) // FIXME Locals?  
+    mkExpr(body, ch)(NoLocals(isStatic)) // FIXME Locals?  
     
     if (isStatic){
       ch << PutStatic(className, name, jvmType)
diff --git a/src/main/scala/leon/codegen/CompilationUnit.scala b/src/main/scala/leon/codegen/CompilationUnit.scala
index da2c32b0f..e55f57777 100644
--- a/src/main/scala/leon/codegen/CompilationUnit.scala
+++ b/src/main/scala/leon/codegen/CompilationUnit.scala
@@ -280,8 +280,6 @@ class CompilationUnit(val ctx: LeonContext,
         args.zipWithIndex.toMap
       }
 
-    val exprToCompile = purescala.TreeOps.matchToIfThenElse(e)
-
     mkExpr(e, ch)(Locals(newMapping, Map.empty, Map.empty, true))
 
     e.getType match {
diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala
index 85c686095..0ba220f7d 100644
--- a/src/main/scala/leon/purescala/TreeOps.scala
+++ b/src/main/scala/leon/purescala/TreeOps.scala
@@ -1037,247 +1037,6 @@ object TreeOps {
     genericTransform[Unit]((e,c) => (e, None), newPost, noCombiner)(())(expr)._1
   }
 
-  /*
-   * Transforms complicated Ifs into multiple nested if blocks
-   * It will decompose every OR clauses, and it will group AND clauses checking
-   * isInstanceOf toghether.
-   *
-   *  if (a.isInstanceof[T1] && a.tail.isInstanceof[T2] && a.head == a2 || C) {
-   *     T
-   *  } else {
-   *     E
-   *  }
-   *
-   * Becomes:
-   *
-   *  if (a.isInstanceof[T1] && a.tail.isInstanceof[T2]) {
-   *    if (a.head == a2) {
-   *      T
-   *    } else {
-   *      if(C) {
-   *        T
-   *      } else {
-   *        E
-   *      }
-   *    }
-   *  } else {
-   *    if(C) {
-   *      T
-   *    } else {
-   *      E
-   *    }
-   *  }
-   * 
-   * This transformation runs immediately before patternMatchReconstruction.
-   *
-   * Notes: positions are lost.
-   */
-  def decomposeIfs(e: Expr): Expr = {
-    def pre(e: Expr): Expr = e match {
-      case IfExpr(cond, thenn, elze) =>
-        val TopLevelOrs(orcases) = cond
-
-        if (orcases.exists{ case TopLevelAnds(ands) => ands.exists(_.isInstanceOf[CaseClassInstanceOf]) } ) {
-          if (!orcases.tail.isEmpty) {
-            pre(IfExpr(orcases.head, thenn, IfExpr(Or(orcases.tail), thenn, elze)))
-          } else {
-            val TopLevelAnds(andcases) = orcases.head
-
-            val (andis, andnotis) = andcases.partition(_.isInstanceOf[CaseClassInstanceOf])
-
-            if (andis.isEmpty || andnotis.isEmpty) {
-              e
-            } else {
-              IfExpr(And(andis), IfExpr(And(andnotis), thenn, elze), elze)
-            }
-          }
-        } else {
-          e
-        }
-      case _ =>
-        e
-    }
-
-    simplePreTransform(pre)(e)
-  }
-
-  /**
-   * Reconstructs match expressions from if-then-elses.
-   *
-   * Notes: positions are lost.
-   */
-  def patternMatchReconstruction(e: Expr): Expr = {
-    def post(e: Expr): Expr = e match {
-      case IfExpr(cond, thenn, elze) =>
-        val TopLevelAnds(cases) = cond
-
-        if (cases.forall(_.isInstanceOf[CaseClassInstanceOf])) {
-          // matchingOn might initially be: a : T1, a.tail : T2, b: T2
-          def selectorDepth(e: Expr): Int = e match {
-            case cd: CaseClassSelector =>
-              1+selectorDepth(cd.caseClass)
-            case _ =>
-              0
-          }
-
-          var scrutSet = Set[Expr]()
-          var conditions = Map[Expr, CaseClassType]()
-
-          var matchingOn = cases.collect { case cc : CaseClassInstanceOf => cc } sortBy(cc => selectorDepth(cc.expr))
-          for (CaseClassInstanceOf(cct, expr) <- matchingOn) {
-            conditions += expr -> cct
-
-            expr match {
-              case cd: CaseClassSelector =>
-                if (!scrutSet.contains(cd.caseClass)) {
-                  // we found a test looking like "a.foo.isInstanceof[..]"
-                  // without a check on "a".
-                  scrutSet += cd
-                }
-              case e =>
-                scrutSet += e
-            }
-          }
-
-          var substMap = Map[Expr, Expr]()
-
-          def computePatternFor(ct: CaseClassType, prefix: Expr): Pattern = {
-
-            val name = prefix match {
-              case CaseClassSelector(_, _, id) => id.name
-              case Variable(id) => id.name
-              case _ => "tmp"
-            }
-
-            val binder = FreshIdentifier(name, true).setType(prefix.getType) 
-
-            // prefix becomes binder
-            substMap += prefix -> Variable(binder)
-            substMap += CaseClassInstanceOf(ct, prefix) -> BooleanLiteral(true)
-
-            val subconds = for (f <- ct.fields) yield {
-              val fieldSel = CaseClassSelector(ct, prefix, f.id)
-              if (conditions contains fieldSel) {
-                computePatternFor(conditions(fieldSel), fieldSel)
-              } else {
-                val b = FreshIdentifier(f.id.name, true).setType(f.tpe)
-                substMap += fieldSel -> Variable(b)
-                WildcardPattern(Some(b))
-              }
-            }
-
-            CaseClassPattern(Some(binder), ct, subconds)
-          }
-
-          val (scrutinees, patterns) = scrutSet.toSeq.map(s => (s, computePatternFor(conditions(s), s))).unzip
-
-          val (scrutinee, pattern) = if (scrutinees.size > 1) {
-            (Tuple(scrutinees), TuplePattern(None, patterns))
-          } else {
-            (scrutinees.head, patterns.head)
-          }
-
-          // We use searchAndReplace to replace the biggest match first
-          // (topdown).
-          // So replaceing using Map(a => b, CC(a) => d) will replace
-          // "CC(a)" by "d" and not by "CC(b)"
-          val newThen = preMap(substMap.lift)(thenn)
-
-          // Remove unused binders
-          val vars = variablesOf(newThen)
-
-          def simplerBinder(oid: Option[Identifier]) = oid.filter(vars(_))
-
-          def simplifyPattern(p: Pattern): Pattern = p match {
-            case CaseClassPattern(ob, cd, subpatterns) =>
-              CaseClassPattern(simplerBinder(ob), cd, subpatterns map simplifyPattern)
-            case WildcardPattern(ob) =>
-              WildcardPattern(simplerBinder(ob))
-            case TuplePattern(ob, patterns) =>
-              TuplePattern(simplerBinder(ob), patterns map simplifyPattern)
-            case LiteralPattern(ob,lit) => LiteralPattern(simplerBinder(ob), lit)
-            case _ =>
-              p
-          }
-
-          val resCases = List(
-                           SimpleCase(simplifyPattern(pattern), newThen),
-                           SimpleCase(WildcardPattern(None), elze)
-                         )
-
-          def mergePattern(to: Pattern, anchor: Identifier, pat: Pattern): Pattern = to match {
-            case CaseClassPattern(ob, cd, subs) =>
-              if (ob == Some(anchor)) {
-                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
-                pat
-              } else {
-                CaseClassPattern(ob, cd, subs.map(mergePattern(_, anchor, pat)))
-              }
-            case InstanceOfPattern(ob, cd) =>
-              if (ob == Some(anchor)) {
-                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
-                pat
-              } else {
-                InstanceOfPattern(ob, cd)
-              }
-
-            case WildcardPattern(ob) =>
-              if (ob == Some(anchor)) {
-                pat
-              } else {
-                WildcardPattern(ob)
-              }
-            case TuplePattern(ob,subs) =>
-              if (ob == Some(anchor)) {
-                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
-                pat
-              } else {
-                TuplePattern(ob, subs)
-              }
-            case LiteralPattern(ob, lit) => // TODO: is this correct?
-              if (ob == Some(anchor)) {
-                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
-                pat
-              } else {
-                LiteralPattern(ob,lit) 
-              }
-                
-          }
-
-          val newCases = resCases.flatMap { c => c match {
-            case SimpleCase(wp: WildcardPattern, m @ MatchExpr(ex, cases)) if ex == scrutinee  =>
-              cases
-
-            case SimpleCase(pattern, m @ MatchExpr(v @ Variable(id), cases)) =>
-              if (pattern.binders(id)) {
-                cases.map{ nc =>
-                  SimpleCase(mergePattern(pattern, id, nc.pattern), nc.rhs)
-                }
-              } else {
-                Seq(c)
-              }
-            case _ => 
-              Seq(c)
-          }}
-
-          var finalMatch = MatchExpr(scrutinee, List(newCases.head)).setType(e.getType)
-
-          for (toAdd <- newCases.tail if !isMatchExhaustive(finalMatch)) {
-            finalMatch = MatchExpr(scrutinee, finalMatch.cases :+ toAdd).setType(e.getType)
-          }
-
-          finalMatch
-
-        } else {
-          e
-        }
-      case _ =>
-        e
-    }
-
-    simplePostTransform(post)(e)
-  }
-
   /**
    * Simplify If expressions when the branch is predetermined by the path
    * condition
@@ -2283,5 +2042,249 @@ object TreeOps {
 
   @deprecated("Use exists instead", "Leon 0.2.1")
   def contains(e: Expr, matcher: Expr => Boolean): Boolean = exists(matcher)(e)
+ 
+  /*
+   * Transforms complicated Ifs into multiple nested if blocks
+   * It will decompose every OR clauses, and it will group AND clauses checking
+   * isInstanceOf toghether.
+   *
+   *  if (a.isInstanceof[T1] && a.tail.isInstanceof[T2] && a.head == a2 || C) {
+   *     T
+   *  } else {
+   *     E
+   *  }
+   *
+   * Becomes:
+   *
+   *  if (a.isInstanceof[T1] && a.tail.isInstanceof[T2]) {
+   *    if (a.head == a2) {
+   *      T
+   *    } else {
+   *      if(C) {
+   *        T
+   *      } else {
+   *        E
+   *      }
+   *    }
+   *  } else {
+   *    if(C) {
+   *      T
+   *    } else {
+   *      E
+   *    }
+   *  }
+   * 
+   * This transformation runs immediately before patternMatchReconstruction.
+   *
+   * Notes: positions are lost.
+   */
+  @deprecated("Mending an expression after matchToIfThenElse is unsafe", "Leon 0.2.4")
+  def decomposeIfs(e: Expr): Expr = {
+    def pre(e: Expr): Expr = e match {
+      case IfExpr(cond, thenn, elze) =>
+        val TopLevelOrs(orcases) = cond
+
+        if (orcases.exists{ case TopLevelAnds(ands) => ands.exists(_.isInstanceOf[CaseClassInstanceOf]) } ) {
+          if (!orcases.tail.isEmpty) {
+            pre(IfExpr(orcases.head, thenn, IfExpr(Or(orcases.tail), thenn, elze)))
+          } else {
+            val TopLevelAnds(andcases) = orcases.head
+
+            val (andis, andnotis) = andcases.partition(_.isInstanceOf[CaseClassInstanceOf])
+
+            if (andis.isEmpty || andnotis.isEmpty) {
+              e
+            } else {
+              IfExpr(And(andis), IfExpr(And(andnotis), thenn, elze), elze)
+            }
+          }
+        } else {
+          e
+        }
+      case _ =>
+        e
+    }
+
+    simplePreTransform(pre)(e)
+  }
+
+  /**
+   * Reconstructs match expressions from if-then-elses.
+   *
+   * Notes: positions are lost.
+   */
+  @deprecated("Mending an expression after matchToIfThenElse is unsafe", "Leon 0.2.4")
+  def patternMatchReconstruction(e: Expr): Expr = {
+    def post(e: Expr): Expr = e match {
+      case IfExpr(cond, thenn, elze) =>
+        val TopLevelAnds(cases) = cond
+
+        if (cases.forall(_.isInstanceOf[CaseClassInstanceOf])) {
+          // matchingOn might initially be: a : T1, a.tail : T2, b: T2
+          def selectorDepth(e: Expr): Int = e match {
+            case cd: CaseClassSelector =>
+              1+selectorDepth(cd.caseClass)
+            case _ =>
+              0
+          }
+
+          var scrutSet = Set[Expr]()
+          var conditions = Map[Expr, CaseClassType]()
+
+          var matchingOn = cases.collect { case cc : CaseClassInstanceOf => cc } sortBy(cc => selectorDepth(cc.expr))
+          for (CaseClassInstanceOf(cct, expr) <- matchingOn) {
+            conditions += expr -> cct
+
+            expr match {
+              case cd: CaseClassSelector =>
+                if (!scrutSet.contains(cd.caseClass)) {
+                  // we found a test looking like "a.foo.isInstanceof[..]"
+                  // without a check on "a".
+                  scrutSet += cd
+                }
+              case e =>
+                scrutSet += e
+            }
+          }
+
+          var substMap = Map[Expr, Expr]()
+
+          def computePatternFor(ct: CaseClassType, prefix: Expr): Pattern = {
+
+            val name = prefix match {
+              case CaseClassSelector(_, _, id) => id.name
+              case Variable(id) => id.name
+              case _ => "tmp"
+            }
+
+            val binder = FreshIdentifier(name, true).setType(prefix.getType) 
+
+            // prefix becomes binder
+            substMap += prefix -> Variable(binder)
+            substMap += CaseClassInstanceOf(ct, prefix) -> BooleanLiteral(true)
+
+            val subconds = for (f <- ct.fields) yield {
+              val fieldSel = CaseClassSelector(ct, prefix, f.id)
+              if (conditions contains fieldSel) {
+                computePatternFor(conditions(fieldSel), fieldSel)
+              } else {
+                val b = FreshIdentifier(f.id.name, true).setType(f.tpe)
+                substMap += fieldSel -> Variable(b)
+                WildcardPattern(Some(b))
+              }
+            }
+
+            CaseClassPattern(Some(binder), ct, subconds)
+          }
+
+          val (scrutinees, patterns) = scrutSet.toSeq.map(s => (s, computePatternFor(conditions(s), s))).unzip
+
+          val (scrutinee, pattern) = if (scrutinees.size > 1) {
+            (Tuple(scrutinees), TuplePattern(None, patterns))
+          } else {
+            (scrutinees.head, patterns.head)
+          }
+
+          // We use searchAndReplace to replace the biggest match first
+          // (topdown).
+          // So replaceing using Map(a => b, CC(a) => d) will replace
+          // "CC(a)" by "d" and not by "CC(b)"
+          val newThen = preMap(substMap.lift)(thenn)
+
+          // Remove unused binders
+          val vars = variablesOf(newThen)
+
+          def simplerBinder(oid: Option[Identifier]) = oid.filter(vars(_))
+
+          def simplifyPattern(p: Pattern): Pattern = p match {
+            case CaseClassPattern(ob, cd, subpatterns) =>
+              CaseClassPattern(simplerBinder(ob), cd, subpatterns map simplifyPattern)
+            case WildcardPattern(ob) =>
+              WildcardPattern(simplerBinder(ob))
+            case TuplePattern(ob, patterns) =>
+              TuplePattern(simplerBinder(ob), patterns map simplifyPattern)
+            case LiteralPattern(ob,lit) => LiteralPattern(simplerBinder(ob), lit)
+            case _ =>
+              p
+          }
+
+          val resCases = List(
+                           SimpleCase(simplifyPattern(pattern), newThen),
+                           SimpleCase(WildcardPattern(None), elze)
+                         )
+
+          def mergePattern(to: Pattern, anchor: Identifier, pat: Pattern): Pattern = to match {
+            case CaseClassPattern(ob, cd, subs) =>
+              if (ob == Some(anchor)) {
+                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
+                pat
+              } else {
+                CaseClassPattern(ob, cd, subs.map(mergePattern(_, anchor, pat)))
+              }
+            case InstanceOfPattern(ob, cd) =>
+              if (ob == Some(anchor)) {
+                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
+                pat
+              } else {
+                InstanceOfPattern(ob, cd)
+              }
+
+            case WildcardPattern(ob) =>
+              if (ob == Some(anchor)) {
+                pat
+              } else {
+                WildcardPattern(ob)
+              }
+            case TuplePattern(ob,subs) =>
+              if (ob == Some(anchor)) {
+                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
+                pat
+              } else {
+                TuplePattern(ob, subs)
+              }
+            case LiteralPattern(ob, lit) => // TODO: is this correct?
+              if (ob == Some(anchor)) {
+                sys.error("WOOOT: "+to+" <<= "+pat +" on "+anchor)
+                pat
+              } else {
+                LiteralPattern(ob,lit) 
+              }
+                
+          }
+
+          val newCases = resCases.flatMap { c => c match {
+            case SimpleCase(wp: WildcardPattern, m @ MatchExpr(ex, cases)) if ex == scrutinee  =>
+              cases
+
+            case SimpleCase(pattern, m @ MatchExpr(v @ Variable(id), cases)) =>
+              if (pattern.binders(id)) {
+                cases.map{ nc =>
+                  SimpleCase(mergePattern(pattern, id, nc.pattern), nc.rhs)
+                }
+              } else {
+                Seq(c)
+              }
+            case _ => 
+              Seq(c)
+          }}
+
+          var finalMatch = MatchExpr(scrutinee, List(newCases.head)).setType(e.getType)
+
+          for (toAdd <- newCases.tail if !isMatchExhaustive(finalMatch)) {
+            finalMatch = MatchExpr(scrutinee, finalMatch.cases :+ toAdd).setType(e.getType)
+          }
+
+          finalMatch
+
+        } else {
+          e
+        }
+      case _ =>
+        e
+    }
+
+    simplePostTransform(post)(e)
+  }
+
 
 }
diff --git a/src/main/scala/leon/synthesis/rules/Cegis.scala b/src/main/scala/leon/synthesis/rules/Cegis.scala
index c74c52839..17a586dbe 100644
--- a/src/main/scala/leon/synthesis/rules/Cegis.scala
+++ b/src/main/scala/leon/synthesis/rules/Cegis.scala
@@ -240,7 +240,7 @@ abstract class CEGISLike(name: String) extends Rule(name) {
           val forArray = replace(substMap, simplerRes)
 
           // We trust arrays to be fast...
-          val eval = evaluator.compile(matchToIfThenElse(forArray), ba +: p.as)
+          val eval = evaluator.compile(forArray, ba +: p.as)
 
           eval.map{e => { case (bss, ins) => 
             e(FiniteArray(bss).setType(ArrayType(BooleanType)) +: ins)
@@ -248,7 +248,7 @@ abstract class CEGISLike(name: String) extends Rule(name) {
         }
 
         def compileWithArgs(): Option[(Seq[Expr], Seq[Expr]) => EvaluationResult] = {
-          val eval = evaluator.compile(matchToIfThenElse(simplerRes), bssOrdered ++ p.as)
+          val eval = evaluator.compile(simplerRes, bssOrdered ++ p.as)
 
           eval.map{e => { case (bss, ins) => 
             e(bss ++ ins)
diff --git a/src/main/scala/leon/utils/Simplifiers.scala b/src/main/scala/leon/utils/Simplifiers.scala
index 6849a97dc..cb57f3fd1 100644
--- a/src/main/scala/leon/utils/Simplifiers.scala
+++ b/src/main/scala/leon/utils/Simplifiers.scala
@@ -17,10 +17,7 @@ object Simplifiers {
       removeWitnesses(p) _,
       simplifyTautologies(uninterpretedZ3)(_),
       simplifyLets _,
-      decomposeIfs _,
-      matchToIfThenElse _,
       simplifyPaths(uninterpretedZ3)(_),
-      patternMatchReconstruction _,
       rewriteTuples _,
       evalGround(ctx, p),
       normalizeExpression _
@@ -46,10 +43,7 @@ object Simplifiers {
     val simplifiers = List[Expr => Expr](
       simplifyTautologies(uninterpretedZ3)(_),
       simplifyLets _,
-      decomposeIfs _,
-      matchToIfThenElse _,
       simplifyPaths(uninterpretedZ3)(_),
-      patternMatchReconstruction _,
       rewriteTuples _//,
       //normalizeExpression _
     )
@@ -68,7 +62,6 @@ object Simplifiers {
 
     val simplifiers = List[Expr => Expr](
       simplifyTautologies(uninterpretedZ3)(_),
-      decomposeIfs _,
       rewriteTuples _,
       evalGround(ctx, p),
       normalizeExpression _
diff --git a/src/main/scala/leon/verification/DefaultTactic.scala b/src/main/scala/leon/verification/DefaultTactic.scala
index 71a8b8203..f3c607f6e 100644
--- a/src/main/scala/leon/verification/DefaultTactic.scala
+++ b/src/main/scala/leon/verification/DefaultTactic.scala
@@ -19,7 +19,7 @@ class DefaultTactic(vctx: VerificationContext) extends Tactic(vctx) {
       (fd.postcondition, fd.body) match {
         case (Some((id, post)), Some(body)) =>
           val res = id.freshen
-          val vc = Implies(precOrTrue(fd), Let(res, safe(body), replace(Map(id.toVariable -> res.toVariable), safe(post))))
+          val vc = Implies(precOrTrue(fd), Let(res, body, replace(Map(id.toVariable -> res.toVariable), post)))
 
           Seq(new VerificationCondition(vc, fd, VCPostcondition, this).setPos(post))
         case _ =>
@@ -32,11 +32,11 @@ class DefaultTactic(vctx: VerificationContext) extends Tactic(vctx) {
         case Some(body) =>
           val calls = collectWithPC {
             case c @ FunctionInvocation(tfd, _) if tfd.hasPrecondition => (c, tfd.precondition.get)
-          }(safe(body))
+          }(body)
 
           calls.map {
             case ((fi @ FunctionInvocation(tfd, args), pre), path) =>
-              val pre2 = replaceFromIDs((tfd.params.map(_.id) zip args).toMap, safe(pre))
+              val pre2 = replaceFromIDs((tfd.params.map(_.id) zip args).toMap, pre)
               val vc = Implies(And(precOrTrue(fd), path), pre2)
 
               new VerificationCondition(vc, fd, VCPrecondition, this).setPos(fi)
@@ -70,7 +70,7 @@ class DefaultTactic(vctx: VerificationContext) extends Tactic(vctx) {
             case a @ Assert(cond, None, _) => (a, VCAssert, cond)
             // Only triggered for inner ensurings, general postconditions are handled by generatePostconditions
             case a @ Ensuring(body, id, post) => (a, VCAssert, Let(id, body, post))
-          }(safe(body))
+          }(body)
 
           calls.map {
             case ((e, kind, errorCond), path) =>
diff --git a/src/main/scala/leon/verification/InductionTactic.scala b/src/main/scala/leon/verification/InductionTactic.scala
index 97804cb76..293efa58b 100644
--- a/src/main/scala/leon/verification/InductionTactic.scala
+++ b/src/main/scala/leon/verification/InductionTactic.scala
@@ -27,10 +27,10 @@ class InductionTactic(vctx: VerificationContext) extends DefaultTactic(vctx) {
   }
 
   override def generatePostconditions(fd: FunDef): Seq[VerificationCondition] = {
-    (fd.body.map(safe), firstAbsClassDef(fd.params), fd.postcondition) match {
+    (fd.body, firstAbsClassDef(fd.params), fd.postcondition) match {
       case (Some(b), Some((parentType, arg)), Some((id, p))) =>
-        val post = safe(p)
-        val body = safe(b)
+        val post = p
+        val body = b
 
         for (cct <- parentType.knownCCDescendents) yield {
           val selectors = selectorsOfParentType(parentType, cct, arg.toVariable)
@@ -56,12 +56,12 @@ class InductionTactic(vctx: VerificationContext) extends DefaultTactic(vctx) {
   }
 
   override def generatePreconditions(fd: FunDef): Seq[VerificationCondition] = {
-    (fd.body.map(safe), firstAbsClassDef(fd.params)) match {
+    (fd.body, firstAbsClassDef(fd.params)) match {
       case (Some(b), Some((parentType, arg))) =>
-        val body = safe(b)
+        val body = b
 
         val calls = collectWithPC {
-          case fi @ FunctionInvocation(tfd, _) if tfd.hasPrecondition => (fi, safe(tfd.precondition.get))
+          case fi @ FunctionInvocation(tfd, _) if tfd.hasPrecondition => (fi, tfd.precondition.get)
         }(body)
 
         calls.flatMap {
diff --git a/src/main/scala/leon/verification/Tactic.scala b/src/main/scala/leon/verification/Tactic.scala
index 7f4418023..26eef79c1 100644
--- a/src/main/scala/leon/verification/Tactic.scala
+++ b/src/main/scala/leon/verification/Tactic.scala
@@ -14,7 +14,9 @@ abstract class Tactic(vctx: VerificationContext) {
   val program  = vctx.program
   val reporter = vctx.reporter
 
-  def generateVCs(fd: FunDef): Seq[VerificationCondition] = {
+  def generateVCs(fdUnsafe: FunDef): Seq[VerificationCondition] = {
+    val fd = fdUnsafe.duplicate
+    fd.fullBody = matchToIfThenElse(fd.fullBody)
     generatePostconditions(fd) ++
     generatePreconditions(fd) ++
     generateCorrectnessConditions(fd)
@@ -26,9 +28,8 @@ abstract class Tactic(vctx: VerificationContext) {
 
 
   // Helper functions
-  protected def safe(e: Expr): Expr = matchToIfThenElse(e)
   protected def precOrTrue(fd: FunDef): Expr = fd.precondition match {
-    case Some(pre) => safe(pre)
+    case Some(pre) => pre
     case None => BooleanLiteral(true)
   }
 
diff --git a/src/test/resources/regression/transformations/Match.scala b/src/test/resources/regression/transformations/Match.scala
deleted file mode 100644
index 2567ba2b3..000000000
--- a/src/test/resources/regression/transformations/Match.scala
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright 2009-2014 EPFL, Lausanne */
-
-import leon.annotation._
-import leon.lang._
-
-object Transform {
-    sealed abstract class List
-    case class Cons(head: Int, tail: List) extends List
-    case object Nil extends List
-
-    def input01(a: List): Int = a match {
-      case Cons(h, Cons(th, tt)) =>
-        h + th
-      case _ =>
-        a match {
-          case Cons(th, Nil) =>
-            th
-          case _ =>
-            0
-        }
-    }
-
-    def output01(a: List): Int = a match {
-      case Cons(h, Cons(th, _)) =>
-        h + th
-      case Cons(th, Nil) =>
-        th
-      case _ =>
-        0
-    }
-    def input02(a: List): Int = a match {
-      case Cons(h, t) =>
-        t match {
-          case Cons(th, tt) => 1
-          case Nil => 2
-        }
-      case Nil =>
-        3
-    }
-
-    def output02(a: List): Int = a match {
-      case Cons(_, Cons(_, _)) => 1
-      case Cons(_, Nil) => 2
-      case Nil => 3
-    }
-}
diff --git a/src/test/scala/leon/test/purescala/TransformationTests.scala b/src/test/scala/leon/test/purescala/TransformationTests.scala
index 141259f61..7335365aa 100644
--- a/src/test/scala/leon/test/purescala/TransformationTests.scala
+++ b/src/test/scala/leon/test/purescala/TransformationTests.scala
@@ -40,11 +40,6 @@ class TransformationTests extends LeonTestSuite {
           "Simplifying paths",
           simpPaths
         )
-      case "Match.scala" =>
-        (
-          "Match reconstruction/flattening",
-          apply (matchToIfThenElse _, patternMatchReconstruction _)
-        )
       case n =>
         fail("Unknown name "+n)
     }
-- 
GitLab