From 50a8dda1be76422e2ed43156bd48df3c9f527b4f Mon Sep 17 00:00:00 2001
From: Philippe Suter <philippe.suter@gmail.com>
Date: Tue, 26 Oct 2010 15:58:11 +0000
Subject: [PATCH]

---
 WISHLIST                          |  7 +++--
 src/funcheck/CodeExtraction.scala |  4 +++
 src/funcheck/Extractors.scala     | 10 +++++++
 src/funcheck/FunCheckPlugin.scala |  3 +-
 src/purescala/Analysis.scala      | 50 +++++++++++++++----------------
 src/purescala/Settings.scala      |  1 -
 src/purescala/Z3Solver.scala      | 11 ++++---
 testcases/ExprComp.scala          |  1 +
 8 files changed, 50 insertions(+), 37 deletions(-)

diff --git a/WISHLIST b/WISHLIST
index f3f3f786d..fa1ab68c2 100644
--- a/WISHLIST
+++ b/WISHLIST
@@ -1,14 +1,15 @@
 Add here what you would love FunCheck to be able to do
 ------------------------------------------------------
 
-PS: rewrite pattern-matching translator to use if-then-else
 PS: generate VCs for preconditions
 PS: generate VCs for pattern-matching
-PS: support multiple top-level objects, and use 'private' accessor to indicate what's part of the interface
+PS: support multiple top-level objects
+PS: use 'private' accessor to indicate what's part of the interface
 PS: support tuples (including natively in Z3)
 
-
 Wishes granted so far
 ---------------------
 
 PS: create a wishlist
+PS: rewrite pattern-matching translator to use if-then-else
+VK: add IsValid class to allow for writing just "holds" in place of ensuring(_ == true)
diff --git a/src/funcheck/CodeExtraction.scala b/src/funcheck/CodeExtraction.scala
index 5817434ed..c76e1ca7f 100644
--- a/src/funcheck/CodeExtraction.scala
+++ b/src/funcheck/CodeExtraction.scala
@@ -227,6 +227,10 @@ trait CodeExtraction extends Extractors {
           realBody = body2
           ensCont = Some(c1)
         }
+        case ExHoldsExpression(body2) => {
+          realBody = body2
+          ensCont = Some(ResultVariable().setType(BooleanType))
+        }
         case _ => ;
       }
 
diff --git a/src/funcheck/Extractors.scala b/src/funcheck/Extractors.scala
index 110efa675..3b540a735 100644
--- a/src/funcheck/Extractors.scala
+++ b/src/funcheck/Extractors.scala
@@ -41,6 +41,16 @@ trait Extractors {
       }
     }
 
+    object ExHoldsExpression {
+      def unapply(tree: Select) : Option[Tree] = tree match {
+        case Select(Apply(Select(Select(funcheckIdent, utilsName), any2IsValidName), realExpr :: Nil), holdsName) if (
+          utilsName.toString == "Utils" &&
+          any2IsValidName.toString == "any2IsValid" &&
+          holdsName.toString == "holds") => Some(realExpr)
+        case _ => None
+      }        
+    }
+
     object ExRequiredExpression {
       /** Extracts the 'require' contract from an expression (only if it's the
        * first call in the block). */
diff --git a/src/funcheck/FunCheckPlugin.scala b/src/funcheck/FunCheckPlugin.scala
index 4a580fa23..6bed3131a 100644
--- a/src/funcheck/FunCheckPlugin.scala
+++ b/src/funcheck/FunCheckPlugin.scala
@@ -27,7 +27,6 @@ class FunCheckPlugin(val global: Global) extends Plugin {
     "  -P:funcheck:axioms             Generate simple forall axioms for recursive functions when possible" + "\n" + 
     "  -P:funcheck:tolerant           Silently extracts non-pure function bodies as ''unknown''" + "\n" +
     "  -P:funcheck:nobapa             Disable BAPA Z3 extension" + "\n" +
-    "  -P:funcheck:newPM              Use the new pattern-matching translator" + "\n" +
     "  -P:funcheck:quiet              No info and warning messages from the extensions" + "\n" +
     "  -P:funcheck:XP                 Enable weird transformations and other bug-producing features"
   )
@@ -45,7 +44,7 @@ class FunCheckPlugin(val global: Global) extends Plugin {
         case "nodefaults" =>                     purescala.Settings.runDefaultExtensions = false
         case "axioms"     =>                     purescala.Settings.noForallAxioms = false
         case "nobapa"     =>                     purescala.Settings.useBAPA = false
-        case "newPM"      =>                     purescala.Settings.useNewPatternMatchingTranslator = true
+        case "newPM"      =>                     { println("''newPM'' is no longer a command-line option, because the new translation is now on by default."); System.exit(0) }
         case "XP"         =>                     purescala.Settings.experimental = true
         case s if s.startsWith("unrolling=") =>  purescala.Settings.unrollingLevel = try { s.substring("unrolling=".length, s.length).toInt } catch { case _ => 0 }
         case s if s.startsWith("functions=") =>  purescala.Settings.functionsToAnalyse = Set(splitList(s.substring("functions=".length, s.length)): _*)
diff --git a/src/purescala/Analysis.scala b/src/purescala/Analysis.scala
index daff57637..4ffa87ea5 100644
--- a/src/purescala/Analysis.scala
+++ b/src/purescala/Analysis.scala
@@ -259,29 +259,29 @@ object Analysis {
 
   // Rewrites pattern matching expressions where the cases simply correspond to
   // the list of constructors
-  def rewriteSimplePatternMatching(expression: Expr) : Expr = {
-    var extras : List[Expr] = Nil
-
-    def rewritePM(e: Expr) : Option[Expr] = e match {
-      // case NotSoSimplePatternMatching(_) => None
-      case SimplePatternMatching(scrutinee, classType, casesInfo) => {
-        val newVar = Variable(FreshIdentifier("pm", true)).setType(e.getType)
-        val scrutAsLetID = FreshIdentifier("scrut", true).setType(scrutinee.getType)
-        val lle : List[(Variable,List[Expr])] = casesInfo.map(cseInfo => {
-          val (ccd, newPID, argIDs, rhs) = cseInfo
-          val newPVar = Variable(newPID)
-          val argVars = argIDs.map(Variable(_))
-          (newPVar, List(Equals(newPVar, CaseClass(ccd, argVars)), Implies(Equals(Variable(scrutAsLetID), newPVar), Equals(newVar, rhs))))
-        }).toList
-        val (newPVars, newExtras) = lle.unzip
-        extras = Let(scrutAsLetID, scrutinee, And(Or(newPVars.map(Equals(Variable(scrutAsLetID), _))), And(newExtras.flatten))) :: extras 
-        Some(newVar)
-      }
-      case m @ MatchExpr(s,_) => Settings.reporter.error("Untranslatable PM expression on type " + s.getType + " : " + m); None
-      case _ => None
-    }
-
-    val newExpr = searchAndReplaceDFS(rewritePM)(expression)
-    liftLets(Implies(And(extras), newExpr))
-  }
+  // def rewriteSimplePatternMatching(expression: Expr) : Expr = {
+  //   var extras : List[Expr] = Nil
+
+  //   def rewritePM(e: Expr) : Option[Expr] = e match {
+  //     // case NotSoSimplePatternMatching(_) => None
+  //     case SimplePatternMatching(scrutinee, classType, casesInfo) => {
+  //       val newVar = Variable(FreshIdentifier("pm", true)).setType(e.getType)
+  //       val scrutAsLetID = FreshIdentifier("scrut", true).setType(scrutinee.getType)
+  //       val lle : List[(Variable,List[Expr])] = casesInfo.map(cseInfo => {
+  //         val (ccd, newPID, argIDs, rhs) = cseInfo
+  //         val newPVar = Variable(newPID)
+  //         val argVars = argIDs.map(Variable(_))
+  //         (newPVar, List(Equals(newPVar, CaseClass(ccd, argVars)), Implies(Equals(Variable(scrutAsLetID), newPVar), Equals(newVar, rhs))))
+  //       }).toList
+  //       val (newPVars, newExtras) = lle.unzip
+  //       extras = Let(scrutAsLetID, scrutinee, And(Or(newPVars.map(Equals(Variable(scrutAsLetID), _))), And(newExtras.flatten))) :: extras 
+  //       Some(newVar)
+  //     }
+  //     case m @ MatchExpr(s,_) => Settings.reporter.error("Untranslatable PM expression on type " + s.getType + " : " + m); None
+  //     case _ => None
+  //   }
+
+  //   val newExpr = searchAndReplaceDFS(rewritePM)(expression)
+  //   liftLets(Implies(And(extras), newExpr))
+  // }
 }
diff --git a/src/purescala/Settings.scala b/src/purescala/Settings.scala
index 51225d73f..8be325547 100644
--- a/src/purescala/Settings.scala
+++ b/src/purescala/Settings.scala
@@ -13,5 +13,4 @@ object Settings {
   var noForallAxioms: Boolean = true
   var unrollingLevel: Int = 0
   var useBAPA: Boolean = true
-  var useNewPatternMatchingTranslator: Boolean = false
 }
diff --git a/src/purescala/Z3Solver.scala b/src/purescala/Z3Solver.scala
index eca0b4ccd..666b1a3f9 100644
--- a/src/purescala/Z3Solver.scala
+++ b/src/purescala/Z3Solver.scala
@@ -165,16 +165,14 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) with Z3ModelReconstr
       functionDefToDef = functionDefToDef + (funDef -> z3.mkFreshFuncDecl(funDef.id.name, sortSeq, typeToSort(funDef.returnType)))
     }
 
-    // universally quantifies all functions !
+    // Attempts to universally quantify all functions !
     if (!Settings.noForallAxioms) {
-      for (funDef <- program.definedFunctions) if (funDef.hasImplementation && program.isRecursive(funDef) && funDef.args.size > 0) {
+      for (funDef <- program.definedFunctions) if (funDef.hasImplementation /* && program.isRecursive(funDef) */ && funDef.args.size > 0) {
         // println("Generating forall axioms for " + funDef.id.name)
         funDef.body.get match {
           case SimplePatternMatching(scrutinee, _, infos) if (
-                  // funDef.args.size == 1 && funDef.args(0).toVariable == scrutinee
                   funDef.args.size >= 1 && funDef.args.map(_.toVariable).contains(scrutinee)
                   ) => {
-            // println("...has simple PM structure.")
             infos.foreach(i => if (!contains(i._4, _.isInstanceOf[MatchExpr])) {
               val argsAsVars: Seq[Option[Variable]] = funDef.args.map(a => {
                 val v = a.toVariable
@@ -195,7 +193,8 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) with Z3ModelReconstr
                   }
                 }
               }
-              val (ccd, pid, subids, rhs) = i
+              val (ccd, pid, subids, dirtyRHS) = i
+              val cleanRHS = matchToIfThenElse(dirtyRHS)
               val argSorts: Seq[Z3Sort] = subids.map(id => typeToSort(id.getType))
               val boundVars = argSorts.zip((c + 1) until (c + 1 + argSorts.size)).map(p => z3.mkBound(p._2, p._1))
               val matcher: Z3AST = adtConstructors(ccd)(boundVars: _*)
@@ -211,7 +210,7 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) with Z3ModelReconstr
                   case Some(v) => v
                 }))
 
-              val toConvert = Equals(fOfT, rhs)
+              val toConvert = Equals(fOfT, cleanRHS)
               //println(toConvert)
               val initialMap: Map[String, Z3AST] =
               Map((funDef.args.map(_.id) zip otherFunBounds).map(_ match {
diff --git a/testcases/ExprComp.scala b/testcases/ExprComp.scala
index 34c343c8a..df71a041d 100644
--- a/testcases/ExprComp.scala
+++ b/testcases/ExprComp.scala
@@ -60,6 +60,7 @@ object ExprComp {
 	case NStack(v1,vs1) => vs1 match {
 	  case EStack() => Fail()
 	  case NStack(v2,vs2) => Fail() // should be: run(rest, NStack(evalOp(v1,op,v2),vs2))
+	  //case NStack(v2,vs2) => run(rest, NStack(evalOp(v1,op,v2),vs2))
 	}
       }
     }
-- 
GitLab