diff --git a/lib-bin/libz3.so b/lib-bin/libz3.so
index a6ea716dd3c70164f2308536703537ae61663166..694ad9d01ee9b32055f9d5384b6c7ff9594eb030 100755
Binary files a/lib-bin/libz3.so and b/lib-bin/libz3.so differ
diff --git a/lib/z3.jar b/lib/z3.jar
index e40a8c348760944735605957c8a5d45f5dada7db..de54f24a71c5bab3e7fb506c76eecf4e5a9ae642 100644
Binary files a/lib/z3.jar and b/lib/z3.jar differ
diff --git a/src/funcheck/FunCheckPlugin.scala b/src/funcheck/FunCheckPlugin.scala
index 2ec1ba007071e67b47509f7a19eb787757de9495..826e99d2d18678fb61728961e69813b7024b206c 100644
--- a/src/funcheck/FunCheckPlugin.scala
+++ b/src/funcheck/FunCheckPlugin.scala
@@ -26,6 +26,7 @@ class FunCheckPlugin(val global: Global) extends Plugin {
     "  -P:funcheck:unrolling=[0,1,2]  Unrolling depth for recursive functions" + "\n" + 
     "  -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:quiet              No info and warning messages from the extensions" + "\n" +
     "  -P:funcheck:XP                 Enable weird transformations and other bug-producing features"
   )
@@ -42,6 +43,7 @@ class FunCheckPlugin(val global: Global) extends Plugin {
         case "quiet"      =>                     purescala.Settings.quietExtensions = true
         case "nodefaults" =>                     purescala.Settings.runDefaultExtensions = false
         case "axioms"     =>                     purescala.Settings.noForallAxioms = false
+        case "nobapa"     =>                     purescala.Settings.useBAPA = false
         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 6a88eb3b64837cc9e62e1d1b12c3bf26fce959f2..4f2f8778fe8aa7bcdbd02fc6cb08b88dbee0f8e6 100644
--- a/src/purescala/Analysis.scala
+++ b/src/purescala/Analysis.scala
@@ -35,7 +35,7 @@ class Analysis(val program: Program) {
 
   def checkVerificationConditions : Unit = {
     // just for the summary:
-    var verifiedVCs: List[(String,String,String,String)] = Nil
+    var verifiedVCs: List[(String,String,String,String,String)] = Nil
     var analysedFunctions: MutableSet[String] = MutableSet.empty
 
     solverExtensions.foreach(_.setProgram(program))
@@ -45,14 +45,14 @@ class Analysis(val program: Program) {
       if(funDef.body.isDefined) {
         val vc = postconditionVC(funDef)
         if(vc == BooleanLiteral(false)) {
-          verifiedVCs = (funDef.id.toString, "postcondition", "invalid", "trivial") :: verifiedVCs
+          verifiedVCs = (funDef.id.toString, "postcondition", "invalid", "trivial", "--") :: verifiedVCs
         } else if(vc == BooleanLiteral(true)) {
           if(funDef.hasPostcondition) {
-            verifiedVCs = (funDef.id.toString, "postcondition", "valid", "tautology") :: verifiedVCs
+            verifiedVCs = (funDef.id.toString, "postcondition", "valid", "tautology", "--") :: verifiedVCs
           }
         } else {
           reporter.info("Verification condition (post) for ==== " + funDef.id + " ====")
-          if(Settings.unrollingLevel == 0) {
+          if(true || Settings.unrollingLevel == 0) {
             reporter.info(simplifyLets(vc))
           } else {
             reporter.info("(not showing unrolled VCs)")
@@ -72,16 +72,22 @@ class Analysis(val program: Program) {
               false
             } else {
               superseeded = superseeded ++ Set(se.superseeds: _*)
-              se.solve(vc) match {
+
+              val t1 = System.nanoTime
+              val solverResult = se.solve(vc)
+              val t2 = System.nanoTime
+              val dt = ((t2 - t1) / 1000000) / 1000.0
+
+              solverResult match {
                 case None => false
                 case Some(true) => {
                   reporter.info("==== VALID ====")
-                  verifiedVCs = (funDef.id.toString, "postcondition", "valid", se.shortDescription) :: verifiedVCs
+                  verifiedVCs = (funDef.id.toString, "postcondition", "valid", se.shortDescription, dt + "s.") :: verifiedVCs
                   true
                 }
                 case Some(false) => {
                   reporter.error("==== INVALID ====")
-                  verifiedVCs = (funDef.id.toString, "postcondition", "invalid", se.shortDescription) :: verifiedVCs
+                  verifiedVCs = (funDef.id.toString, "postcondition", "invalid", se.shortDescription, dt + "s.") :: verifiedVCs
                   true
                 }
               }
@@ -89,7 +95,7 @@ class Analysis(val program: Program) {
           }) match {
             case None => {
               reporter.warning("No solver could prove or disprove the verification condition.")
-              verifiedVCs = (funDef.id.toString, "postcondition", "unknown", "---") :: verifiedVCs
+              verifiedVCs = (funDef.id.toString, "postcondition", "unknown", "--", "--") :: verifiedVCs
             }
             case _ => 
           } 
@@ -97,7 +103,7 @@ class Analysis(val program: Program) {
       } else {
         if(funDef.postcondition.isDefined) {
           reporter.warning(funDef, "Could not verify postcondition: function implementation is unknown.")
-          verifiedVCs = (funDef.id.toString, "postcondition", "unknown", "no body") :: verifiedVCs
+          verifiedVCs = (funDef.id.toString, "postcondition", "unknown", "no body", "--") :: verifiedVCs
         }
       }
     } 
@@ -107,14 +113,16 @@ class Analysis(val program: Program) {
       val col1wdth  = verifiedVCs.map(_._1).map(_.length).max + 2
       val col2wdth  = verifiedVCs.map(_._2).map(_.length).max + 2
       val col3wdth  = verifiedVCs.map(_._3).map(_.length).max + 2
-      val col4wdth  = verifiedVCs.map(_._4).map(_.length).max 
-      def mk1line(line: (String,String,String,String)) : String = {
+      val col4wdth  = verifiedVCs.map(_._4).map(_.length).max + 2
+      val col5wdth  = verifiedVCs.map(_._5).map(_.length).max
+      def mk1line(line: (String,String,String,String,String)) : String = {
         line._1 + (" " * (col1wdth - line._1.length)) +
         line._2 + (" " * (col2wdth - line._2.length)) +
         line._3 + (" " * (col3wdth - line._3.length)) +
-        line._4 
+        line._4 + (" " * (col4wdth - line._4.length)) +
+        line._5
       }
-      val dashes : String = "=" * (col1wdth + col2wdth + col3wdth + col4wdth)
+      val dashes : String = "=" * (col1wdth + col2wdth + col3wdth + col4wdth + col5wdth)
       reporter.info("Summary:\n" + dashes + "\n" + verifiedVCs.sortWith(_._1 < _._1).map(mk1line(_)).mkString("\n") + "\n" + dashes)
     } else {
       reporter.info("No verification conditions were generated.")
@@ -187,11 +195,25 @@ class Analysis(val program: Program) {
 }
 
 object Analysis {
+  private val keepCallWhenInlined: Boolean = true
+
+  private def defineOneInlining(f : FunctionInvocation) : (Expr, Expr) = {
+    val FunctionInvocation(fd, args) = f
+    val newLetIDs = fd.args.map(a => FreshIdentifier("arg_" + a.id.name, true).setType(a.tpe)).toList
+    val substMap = Map[Expr,Expr]((fd.args.map(_.toVariable) zip newLetIDs.map(Variable(_))) : _*)
+    val newBody = replace(substMap, freshenLocals(fd.body.get))
+    val newFunctionCall = FunctionInvocation(fd, newLetIDs.map(Variable(_))).setType(f.getType)
+    val callID = FreshIdentifier("call_" + fd.id.name, true).setType(newBody.getType)
+    val callTree = Let(callID, (newLetIDs zip args).foldRight(newBody)((iap, e) => Let(iap._1, iap._2, e)), Variable(callID))
+
+    (Equals(newFunctionCall, Variable(callID)), callTree)
+  }
+
   private def inlineFunctionCall(f : FunctionInvocation) : Expr = {
     val FunctionInvocation(fd, args) = f
     val newLetIDs = fd.args.map(a => FreshIdentifier("arg_" + a.id.name, true).setType(a.tpe)).toList
     val substMap = Map[Expr,Expr]((fd.args.map(_.toVariable) zip newLetIDs.map(Variable(_))) : _*)
-    val newBody = replace(substMap, fd.body.get)
+    val newBody = replace(substMap, freshenLocals(fd.body.get))
     simplifyLets((newLetIDs zip args).foldRight(newBody)((iap, e) => Let(iap._1, iap._2, e)))
   }
 
@@ -200,7 +222,7 @@ object Analysis {
       case f @ FunctionInvocation(fd, args) if fd.hasImplementation && !program.isRecursive(fd) => Some(inlineFunctionCall(f))
       case _ => None
     }
-
+  
     var change: Boolean = true
     var toReturn: Expr = expression
     while(change) {
@@ -212,21 +234,52 @@ object Analysis {
   }
 
   def unrollRecursiveFunctions(program: Program, expression: Expr, times: Int) : Expr = {
-    def applyToCall(e: Expr) : Option[Expr] = e match {
-      case f @ FunctionInvocation(fd, args) if fd.hasImplementation && program.isRecursive(fd) => Some(inlineFunctionCall(f))
-      case _ => None
+    def urf1(expression: Expr, times: Int) : Expr = {
+      var newEqs: List[Expr] = Nil
+
+      def applyToCall(e: Expr) : Option[Expr] = e match {
+        case f @ FunctionInvocation(fd, args) if fd.hasImplementation && program.isRecursive(fd) => {
+          val (newEq, bdy) = defineOneInlining(f)
+          newEqs = newEq :: newEqs
+          Some(bdy)
+        }
+        case _ => None
+      }
+
+      var remaining = if(times < 0) 0 else times
+      var change: Boolean = true
+      var toReturn: Expr = expression
+      while(remaining > 0 && change) {
+        val (t,c) = searchAndReplaceDFSandTrackChanges(applyToCall)(toReturn)
+        change = c
+        toReturn = inlineNonRecursiveFunctions(program, t)
+        remaining = remaining - 1
+      }
+      liftLets(Implies(And(newEqs.reverse), toReturn))
     }
 
-    var remaining = if(times < 0) 0 else times
-    var change: Boolean = true
-    var toReturn: Expr = expression
-    while(remaining > 0 && change) {
-      val (t,c) = searchAndReplaceDFSandTrackChanges(applyToCall)(toReturn)
-      change = c
-      toReturn = inlineNonRecursiveFunctions(program, t)
-      remaining = remaining - 1
+    def urf2(expression: Expr, times: Int) : Expr = {
+      def applyToCall(e: Expr) : Option[Expr] = e match {
+        case f @ FunctionInvocation(fd, args) if fd.hasImplementation && program.isRecursive(fd) => Some(inlineFunctionCall(f))
+        case _ => None
+      }
+
+      var remaining = if(times < 0) 0 else times
+      var change: Boolean = true
+      var toReturn: Expr = expression
+      while(remaining > 0 && change) {
+        val (t,c) = searchAndReplaceDFSandTrackChanges(applyToCall)(toReturn)
+        change = c
+        toReturn = inlineNonRecursiveFunctions(program, t)
+        remaining = remaining - 1
+      }
+      toReturn
     }
-    toReturn
+
+    if(keepCallWhenInlined)
+      urf1(expression, times)
+    else
+      urf2(expression, times)
   }
 
   def inlineContracts(expression: Expr) : Expr = {
@@ -241,7 +294,7 @@ object Analysis {
         val substMap = Map[Expr,Expr]((fd.args.map(_.toVariable) zip argsAsLetVars) : _*) + (ResultVariable() -> Variable(resultAsLet))
         // this thing is full of let variables! We will need to lift the let
         // defs. later to make sure they capture this
-        val trueFact = replace(substMap, fd.postcondition.get)
+        val trueFact = replace(substMap, freshenLocals(fd.postcondition.get))
         val defList: Seq[(Identifier,Expr)] = ((argsAsLet :+ resultAsLet) zip (args :+ newFunCall))
         trueThings = trueFact :: trueThings
         // again: these let defs. need eventually to capture the "true thing"
diff --git a/src/purescala/Settings.scala b/src/purescala/Settings.scala
index 9dda6e21ae36f680344d23266b002a3b9f837015..8be325547994522268aee17396920a8cb74963cb 100644
--- a/src/purescala/Settings.scala
+++ b/src/purescala/Settings.scala
@@ -12,4 +12,5 @@ object Settings {
   var runDefaultExtensions: Boolean = true
   var noForallAxioms: Boolean = true
   var unrollingLevel: Int = 0
+  var useBAPA: Boolean = true
 }
diff --git a/src/purescala/Trees.scala b/src/purescala/Trees.scala
index cafc43db50c49ca75a8e517c37f49bd819778376..f15671b320786af27fb173d7c32d036b56762011 100644
--- a/src/purescala/Trees.scala
+++ b/src/purescala/Trees.scala
@@ -64,9 +64,19 @@ object Trees {
     def expressions = List(guard, rhs)
   }
 
-  sealed abstract class Pattern
-  case class InstanceOfPattern(binder: Option[Identifier], classTypeDef: ClassTypeDef) extends Pattern // c: Class
-  case class WildcardPattern(binder: Option[Identifier]) extends Pattern // c @ _
+  sealed abstract class Pattern {
+    val subPatterns: Seq[Pattern]
+    val binder: Option[Identifier]
+
+    private def subBinders = subPatterns.map(_.binders).foldLeft[Set[Identifier]](Set.empty)(_ ++ _)
+    def binders: Set[Identifier] = subBinders ++ (if(binder.isDefined) Set(binder.get) else Set.empty)
+  }
+  case class InstanceOfPattern(binder: Option[Identifier], classTypeDef: ClassTypeDef) extends Pattern { // c: Class
+    val subPatterns = Seq.empty
+  }
+  case class WildcardPattern(binder: Option[Identifier]) extends Pattern { // c @ _
+    val subPatterns = Seq.empty
+  } 
   case class CaseClassPattern(binder: Option[Identifier], caseClassDef: CaseClassDef, subPatterns: Seq[Pattern]) extends Pattern
   // case class ExtractorPattern(binder: Option[Identifier], 
   //   		      extractor : ExtractorTypeDef, 
@@ -561,6 +571,38 @@ object Trees {
     (res, somethingChanged)
   }
 
+  // rewrites pattern-matching expressions to use fresh variables for the binders
+  def freshenLocals(expr: Expr) : Expr = {
+    def rewritePattern(p: Pattern, sm: Map[Identifier,Identifier]) : Pattern = p match {
+      case InstanceOfPattern(Some(b), ctd) => InstanceOfPattern(Some(sm(b)), ctd)
+      case WildcardPattern(Some(b)) => WildcardPattern(Some(sm(b)))
+      case CaseClassPattern(ob, ccd, sps) => CaseClassPattern(ob.map(sm(_)), ccd, sps.map(rewritePattern(_, sm)))
+      case other => other
+    }
+
+    def freshenCase(cse: MatchCase) : MatchCase = {
+      val allBinders: Set[Identifier] = cse.pattern.binders
+      val subMap: Map[Identifier,Identifier] = Map(allBinders.map(i => (i, FreshIdentifier(i.name, true).setType(i.getType))).toSeq : _*)
+      val subVarMap: Map[Expr,Expr] = subMap.map(kv => (Variable(kv._1) -> Variable(kv._2)))
+      
+      cse match {
+        case SimpleCase(pattern, rhs) => SimpleCase(rewritePattern(pattern, subMap), replace(subVarMap, rhs))
+        case GuardedCase(pattern, guard, rhs) => GuardedCase(rewritePattern(pattern, subMap), replace(subVarMap, guard), replace(subVarMap, rhs))
+      }
+    }
+
+    def applyToTree(e : Expr) : Option[Expr] = e match {
+      case m @ MatchExpr(s, cses) => Some(MatchExpr(s, cses.map(freshenCase(_))).setType(m.getType))
+      case l @ Let(i,e,b) => {
+        val newID = FreshIdentifier(i.name, true).setType(i.getType)
+        Some(Let(newID, e, replace(Map(Variable(i) -> Variable(newID)), b)))
+      }
+      case _ => None
+    }
+
+    searchAndReplaceDFS(applyToTree)(expr)
+  }
+
   // convert describes how to compute a value for the leaves (that includes
   // functions with no args.)
   // combine descriess how to combine two values
diff --git a/src/purescala/Z3Solver.scala b/src/purescala/Z3Solver.scala
index cb16c5cfcbea22eb1cea679004e5a432d142306a..418bb1f20f6eb04a7d53683dcb94b8d82ce7a664 100644
--- a/src/purescala/Z3Solver.scala
+++ b/src/purescala/Z3Solver.scala
@@ -10,6 +10,7 @@ import TypeTrees._
 import z3plugins.bapa.BAPATheory
 
 class Z3Solver(reporter: Reporter) extends Solver(reporter) {
+  import Settings.useBAPA
   val description = "Z3 Solver"
   override val shortDescription = "Z3"
 
@@ -45,7 +46,8 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) {
       z3.delete
     }
     z3 = new Z3Context(z3cfg)
-    bapa = new BAPATheory(z3)
+    // z3.traceToStdout
+    if(useBAPA) bapa = new BAPATheory(z3)
     counter = 0
     prepareSorts
     prepareFunctions
@@ -244,7 +246,7 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) {
         adtSorts(cd)
       }
     }
-    case IntSetType => bapa.mkSetSort
+    case IntSetType if(useBAPA) => bapa.mkSetSort
     case SetType(base) => setSorts.get(base) match {
       case Some(s) => s
       case None => {
@@ -372,41 +374,41 @@ class Z3Solver(reporter: Reporter) extends Solver(reporter) {
         abstractedFormula = true
         z3.mkApp(functionDefToDef(fd), args.map(rec(_)): _*)
       }
-      case e @ EmptySet(_) => if(e.getType == IntSetType) {
+      case e @ EmptySet(_) => if(useBAPA && e.getType == IntSetType) {
         bapa.mkEmptySet
       } else {
         z3.mkEmptySet(typeToSort(e.getType.asInstanceOf[SetType].base))
       }
       case SetEquals(s1,s2) => z3.mkEq(rec(s1), rec(s2))
-      case ElementOfSet(e, s) if s.getType == IntSetType => {
+      case ElementOfSet(e, s) if(useBAPA && s.getType == IntSetType) => {
         bapa.mkElementOf(rec(e), rec(s))
       }
-      case SubsetOf(s1,s2) => if(s1.getType == IntSetType) {
+      case SubsetOf(s1,s2) => if(useBAPA && s1.getType == IntSetType) {
         bapa.mkSubsetEq(rec(s1), rec(s2))
       } else {
         z3.mkSetSubset(rec(s1), rec(s2))
       } 
-      case SetIntersection(s1,s2) => if(s1.getType == IntSetType) {
+      case SetIntersection(s1,s2) => if(useBAPA && s1.getType == IntSetType) {
         bapa.mkIntersect(rec(s1), rec(s2)) 
       } else {
         z3.mkSetIntersect(rec(s1), rec(s2))
       }
-      case SetUnion(s1,s2) => if(s1.getType == IntSetType) {
+      case SetUnion(s1,s2) => if(useBAPA && s1.getType == IntSetType) {
         bapa.mkUnion(rec(s1), rec(s2))
       } else {
         z3.mkSetUnion(rec(s1), rec(s2))
       }
-      case SetDifference(s1,s2) => if(s1.getType == IntSetType) {
+      case SetDifference(s1,s2) => if(useBAPA && s1.getType == IntSetType) {
         bapa.mkIntersect(rec(s1), bapa.mkComplement(rec(s2))) 
       } else {
         z3.mkSetDifference(rec(s1), rec(s2))
       }
-      case f @ FiniteSet(elems) => if(f.getType == IntSetType) {
+      case f @ FiniteSet(elems) => if(useBAPA && f.getType == IntSetType) {
         elems.map(e => bapa.mkSingleton(rec(e))).reduceLeft(bapa.mkUnion(_,_))
       } else {
         elems.foldLeft(z3.mkEmptySet(typeToSort(f.getType.asInstanceOf[SetType].base)))((ast,el) => z3.mkSetAdd(ast,rec(el)))
       }
-      case SetCardinality(s) if s.getType == IntSetType => {
+      case SetCardinality(s) if (useBAPA && s.getType == IntSetType) => {
         bapa.mkCard(rec(s))
       }
       case _ => {
diff --git a/vmcai2011-testcases/ListProperties.scala b/vmcai2011-testcases/ListProperties.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c884ed883e1d6c3f5f63cc729ca5e2c1915d3f19
--- /dev/null
+++ b/vmcai2011-testcases/ListProperties.scala
@@ -0,0 +1,44 @@
+import scala.collection.immutable.Set
+
+object IntListProperties {
+  sealed abstract class IntList
+  case class Cons(head: Int, tail: IntList) extends IntList
+  case class Nil() extends IntList
+
+  def size(list: IntList) : Int = (list match {
+    case Nil() => 0
+    case Cons(_, xs) => 1 + size(xs)
+  }) ensuring(_ >= 0)
+
+  def content(list: IntList) : Set[Int] = (list match {
+    case Nil() => Set.empty[Int]
+    case Cons(x, xs) => Set(x) ++ content(xs)
+  }) //ensuring(_.size <= size(list))
+
+  def removeDuplicates(list: IntList) : IntList = (list match {
+    case Nil() => Nil()
+    case Cons(x, xs) => Cons(x, removeDuplicates(removeFrom(x, xs)))
+  }) ensuring(newList => content(newList) == content(list))
+  def removeFrom(v: Int, list: IntList) : IntList = (list match {
+    case Nil() => Nil()
+    case Cons(x, xs) => {
+      val rest = removeFrom(v, xs)
+      if(v == x) rest else Cons(x, rest)
+    }
+  }) ensuring(newList => content(newList) == content(list) -- Set(v))
+
+//  def reverse(list: IntList) : IntList = reverse0(list, Nil())
+//  def reverse0(list1: IntList, list2: IntList) : IntList = list1 match {
+//    case Nil() => list2
+//    case Cons(x, xs) => reverse0(xs, Cons(x, list2))
+//  }
+//
+//  def concat(list1: IntList, list2: IntList) : IntList = concat0(list1, list2, Nil())
+//  def concat0(list1: IntList, list2: IntList, list3: IntList) : IntList = list1 match {
+//    case Nil() => list2 match {
+//      case Nil() => reverse(list3)
+//      case Cons(y, ys) => concat0(Nil(), ys, Cons(y, list3))
+//    }
+//    case Cons(x, xs) => concat0(xs, list2, Cons(x, list3))
+//  }
+}