diff --git a/src/main/scala/leon/Analysis.scala b/src/main/scala/leon/Analysis.scala
deleted file mode 100644
index e1fc9fb1f3fa155bc194433c2948a7fb2b1a34c0..0000000000000000000000000000000000000000
--- a/src/main/scala/leon/Analysis.scala
+++ /dev/null
@@ -1,343 +0,0 @@
-package leon
-
-import purescala.Common._
-import purescala.Definitions._
-import purescala.Trees._
-import purescala.TreeOps._
-import purescala.TypeTrees._
-
-import Extensions._
-
-import solvers.TrivialSolver
-
-import scala.collection.mutable.{Set => MutableSet}
-
-class Analysis(val program : Program, val reporter: Reporter = Settings.reporter) {
-  Extensions.loadAll(reporter)
-
-  val analysisExtensions: Seq[Analyser] = loadedAnalysisExtensions
-
-  val trivialSolver = new TrivialSolver(reporter) // This one you can't disable :D
-
-  val solverExtensions: Seq[Solver] = trivialSolver +: loadedSolverExtensions
-
-  solverExtensions.foreach(_.setProgram(program))
-
-  val defaultTactic = new DefaultTactic(reporter)
-  defaultTactic.setProgram(program)
-  val inductionTactic = new InductionTactic(reporter)
-  inductionTactic.setProgram(program)
-
-  // Calling this method will run all analyses on the program passed at
-  // construction time. If at least one solver is loaded, verification
-  // conditions are generated and passed to all solvers. Otherwise, only the
-  // Analysis extensions are run on the program.
-  def analyse : Unit = {
-    // We generate all function templates in advance.
-    for(funDef <- program.definedFunctions if funDef.hasImplementation) {
-      // this gets cached :D
-      FunctionTemplate.mkTemplate(funDef)
-    }
-
-    if(solverExtensions.size > 1) {
-      reporter.info("Running verification condition generation...")
-
-      val list = generateVerificationConditions
-      checkVerificationConditions(list : _*)
-    } else {
-      reporter.warning("No solver specified. Cannot test verification conditions.")
-    }
-
-    analysisExtensions.foreach(ae => {
-      reporter.info("Running analysis from extension: " + ae.description)
-      ae.analyse(program)
-    })
-  }
-
-  private def generateVerificationConditions : List[VerificationCondition] = {
-    var allVCs: Seq[VerificationCondition] = Seq.empty
-    val analysedFunctions: MutableSet[String] = MutableSet.empty
-
-    for(funDef <- program.definedFunctions.toList.sortWith((fd1, fd2) => fd1 < fd2) if (Settings.functionsToAnalyse.isEmpty || Settings.functionsToAnalyse.contains(funDef.id.name))) {
-      analysedFunctions += funDef.id.name
-
-      val tactic: Tactic =
-        if(funDef.annotations.contains("induct")) {
-          inductionTactic
-        } else {
-          defaultTactic
-        }
-
-      if(funDef.body.isDefined) {
-        allVCs ++= tactic.generatePreconditions(funDef)
-        allVCs ++= tactic.generatePatternMatchingExhaustivenessChecks(funDef)
-        allVCs ++= tactic.generatePostconditions(funDef)
-        allVCs ++= tactic.generateMiscCorrectnessConditions(funDef)
-        allVCs ++= tactic.generateArrayAccessChecks(funDef)
-      }
-      allVCs = allVCs.sortWith((vc1, vc2) => {
-        val id1 = vc1.funDef.id.name
-        val id2 = vc2.funDef.id.name
-        if(id1 != id2) id1 < id2 else vc1 < vc2
-      })
-    }
-
-    val notFound: Set[String] = Settings.functionsToAnalyse -- analysedFunctions
-    notFound.foreach(fn => reporter.error("Did not find function \"" + fn + "\" though it was marked for analysis."))
-
-    allVCs.toList
-  }
-
-  def checkVerificationCondition(vc: VerificationCondition) : Unit = checkVerificationConditions(vc)
-  def checkVerificationConditions(vcs: VerificationCondition*) : Unit = {
-    for(vcInfo <- vcs) {
-      val funDef = vcInfo.funDef
-      val vc = vcInfo.condition
-
-      reporter.info("Now considering '" + vcInfo.kind + "' VC for " + funDef.id + "...")
-      reporter.info("Verification condition (" + vcInfo.kind + ") for ==== " + funDef.id + " ====")
-      // if(Settings.unrollingLevel == 0) {
-      reporter.info(simplifyLets(vc))
-      // } else {
-      //   reporter.info("(not showing unrolled VCs)")
-      // }
-
-      // try all solvers until one returns a meaningful answer
-      var superseeded : Set[String] = Set.empty[String]
-      solverExtensions.find(se => {
-        reporter.info("Trying with solver: " + se.shortDescription)
-        if(superseeded(se.shortDescription) || superseeded(se.description)) {
-          reporter.info("Solver was superseeded. Skipping.")
-          false
-        } else {
-          superseeded = superseeded ++ Set(se.superseeds: _*)
-
-          val t1 = System.nanoTime
-          se.init()
-          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 ====")
-
-              vcInfo.value = Some(true)
-              vcInfo.solvedWith = Some(se)
-              vcInfo.time = Some(dt)
-
-              true
-            }
-            case Some(false) => {
-              reporter.error("==== INVALID ====")
-
-              vcInfo.value = Some(false)
-              vcInfo.solvedWith = Some(se)
-              vcInfo.time = Some(dt)
-
-              true
-            }
-          }
-        }
-      }) match {
-        case None => {
-          reporter.warning("No solver could prove or disprove the verification condition.")
-        }
-        case _ => 
-      } 
-    
-    } 
-
-    if(vcs.size > 0) {
-      val summaryString = (
-        VerificationCondition.infoHeader +
-        vcs.map(_.infoLine).mkString("\n", "\n", "\n") +
-        VerificationCondition.infoFooter
-      )
-      reporter.info(summaryString)
-
-      if(Settings.simpleOutput) {
-        val outStr =
-          if(vcs.forall(_.status == "valid")) "valid" 
-          else if(vcs.exists(_.status == "invalid")) "invalid"
-          else "unknown"
-        println(outStr)
-      }
-
-      // Printing summary for the evaluation section of paper:
-      val writeSummary = false
-      if (writeSummary) {
-        def writeToFile(filename: String, content: String) : Unit = {
-          try {
-            val fw = new java.io.FileWriter(filename)
-            fw.write(content)
-            fw.close
-          } catch {
-            case e => reporter.error("There was an error while generating the test file" + filename)
-          }
-        }
-
-        var toWrite: String = ""
-        val functionVCs = vcs groupBy (_.funDef)
-        val vcsByPostcond = functionVCs groupBy 
-          (_._2 exists ((vc: VerificationCondition) => vc.kind == VCKind.Postcondition))
-        def functionInfoLine(id: String, funVCs: Traversable[VerificationCondition]) = {
-          val vcsByKind  = funVCs groupBy (_.kind)
-          val nbPrecond  = vcsByKind.get(VCKind.Precondition).getOrElse(Nil).size
-          val nbMatch    = vcsByKind.get(VCKind.ExhaustiveMatch).getOrElse(Nil).size
-          val totalTime  = 
-            (funVCs.foldLeft(0.0)((a, b) => a + b.time.getOrElse(0.0)))
-          val validStr   = "ok"
-          val invalidStr = "err"
-          val status = if (funVCs.forall(_.status == "valid")) validStr else invalidStr
-          val timeStr = if (totalTime < 0.01) "< 0.01" else ("%-3.2f" format totalTime)
-
-          val toRet =
-            "%-25s %-3s %-3s %-9s %6s" format (id, nbPrecond, nbMatch, status, timeStr)
-          toRet
-        }
-        for ((withPostcond, functionsByPostcond) <- vcsByPostcond) {
-          if (withPostcond)
-            toWrite += "with postcondition:\n"
-          else
-            toWrite += "without postcondition:\n"
-          for ((funDef, funVCs) <- functionsByPostcond.toList.sortWith((p1, p2) => p1._1 < p2._1)) {
-            toWrite += functionInfoLine(funDef.id.toString, funVCs) + "\n"
-          }
-        }
-
-        val fileName = program.mainObject.id.toString + "-evaluation.txt"
-        val folderName   = "summary"
-
-        new java.io.File(folderName).mkdir()
-
-        writeToFile(folderName + "/" + fileName, toWrite)
-      }
-    } else {
-      reporter.info("No verification conditions were analyzed.")
-    }
-  }
-}
-
-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(matchToIfThenElse(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, freshenLocals(matchToIfThenElse(fd.body.get)))
-    simplifyLets((newLetIDs zip args).foldRight(newBody)((iap, e) => Let(iap._1, iap._2, e)))
-  }
-
-  def inlineNonRecursiveFunctions(program: Program, expression: Expr) : 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 change: Boolean = true
-    var toReturn: Expr = expression
-    while(change) {
-      val (t,c) = searchAndReplaceDFSandTrackChanges(applyToCall)(toReturn)
-      change = c
-      toReturn = t
-    }
-    toReturn
-  }
-
-  def unrollRecursiveFunctions(program: Program, expression: Expr, times: Int) : Expr = {
-    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))
-    }
-
-    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
-    }
-
-    if(keepCallWhenInlined)
-      urf1(expression, times)
-    else
-      urf2(expression, times)
-  }
-
-  def inlineContracts(expression: Expr) : Expr = {
-    var trueThings: List[Expr] = Nil
-
-    def applyToCall(e: Expr) : Option[Expr] = e match {
-      case f @ FunctionInvocation(fd, args) if fd.hasPostcondition => {
-        val argsAsLet   = fd.args.map(a => FreshIdentifier("parg_" + a.id.name, true).setType(a.tpe)).toList
-        val argsAsLetVars = argsAsLet.map(Variable(_))
-        val resultAsLet = FreshIdentifier("call_" + fd.id.name, true).setType(f.getType)
-        val newFunCall = FunctionInvocation(fd, argsAsLetVars)
-        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, 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"
-        Some(defList.foldRight[Expr](Variable(resultAsLet))((iap, e) => Let(iap._1, iap._2, e)))
-      }
-      case _ => None
-    }
-    val result = searchAndReplaceDFS(applyToCall)(expression)
-    liftLets(Implies(And(trueThings.reverse), result))
-  }
-}
-
-object AnalysisPhase extends UnitPhase[Program] {
-  val name = "Analysis"
-  val description = "Leon Analyses"
-
-  def apply(ctx: LeonContext, program: Program) {
-    new Analysis(program).analyse
-  }
-}
diff --git a/src/main/scala/leon/Extensions.scala b/src/main/scala/leon/Extensions.scala
index 4b54a38552d3c91dcaea8f6676cf65dfcc882cc6..acc1707eb8e8762c3ef5ad0ca1a3953a8dc4de0b 100644
--- a/src/main/scala/leon/Extensions.scala
+++ b/src/main/scala/leon/Extensions.scala
@@ -6,53 +6,14 @@ import purescala.TreeOps._
 import purescala.Definitions._
 
 object Extensions {
-  sealed abstract class Extension(reporter: Reporter) {
+  import leon.verification.{Analyser,Tactic}
+  import leon.solvers.Solver
+
+  abstract class Extension(reporter: Reporter) {
     def description: String
     def shortDescription: String = description
   }
 
-  abstract class Solver(val reporter: Reporter) extends Extension(reporter) {
-    // This can be used by solvers to "see" the programs from which the
-    // formulas come. (e.g. to set up some datastructures for the defined
-    // ADTs, etc.) 
-    def setProgram(program: Program) : Unit = {}
-
-    // Returns Some(true) if valid, Some(false) if invalid,
-    // None if unknown.
-    // should halt as soon as possible with any result (Unknown is ok) as soon as forceStop is true
-    def solve(expression: Expr) : Option[Boolean]
-
-    def solveOrGetCounterexample(expression : Expr) : (Option[Boolean],Map[Identifier,Expr]) = (solve(expression), Map.empty)
-
-    def isUnsat(expression: Expr) : Option[Boolean] = solve(negate(expression))
-    def superseeds : Seq[String] = Nil
-
-    private var _forceStop = false
-    def halt() : Unit = {
-      _forceStop = true
-    }
-    def init() : Unit = {
-      _forceStop = false
-    }
-    protected def forceStop = _forceStop
-
-  }
-  
-  abstract class Analyser(reporter: Reporter) extends Extension(reporter) {
-    // Does whatever the analysis should. Uses the reporter to
-    // signal results and/or errors.
-    def analyse(program: Program) : Unit
-  }
-
-  abstract class Tactic(reporter: Reporter) extends Extension(reporter) {
-    def setProgram(program: Program) : Unit = {}
-    def generatePostconditions(function: FunDef) : Seq[VerificationCondition]
-    def generatePreconditions(function: FunDef) : Seq[VerificationCondition]
-    def generatePatternMatchingExhaustivenessChecks(function: FunDef) : Seq[VerificationCondition]
-    def generateMiscCorrectnessConditions(function: FunDef) : Seq[VerificationCondition]
-    def generateArrayAccessChecks(function: FunDef) : Seq[VerificationCondition]
-  }
-
   // The rest of the code is for dynamically loading extensions
 
   private var allLoaded : Seq[Extension] = Nil
diff --git a/src/main/scala/leon/LeonPhase.scala b/src/main/scala/leon/LeonPhase.scala
index d81b8eea718d40639c0ff5edce6bdc57c0837f83..b18f50d2559a196b22163b3c62ed3def2f610ef0 100644
--- a/src/main/scala/leon/LeonPhase.scala
+++ b/src/main/scala/leon/LeonPhase.scala
@@ -2,7 +2,7 @@ package leon
 
 import purescala.Definitions.Program
 
-abstract class LeonPhase[F, T] {
+abstract class LeonPhase[-F, +T] extends Pipeline[F, T] {
   val name: String
   val description: String
 
@@ -34,8 +34,8 @@ case class NoopPhase[T]() extends LeonPhase[T, T] {
   override def run(ctx: LeonContext)(v: T) = v
 }
 
-case class ExitPhase[T]() extends LeonPhase[T, Unit] {
+case class ExitPhase() extends LeonPhase[Any, Unit] {
   val name = "end";
   val description = "end"
-  override def run(ctx: LeonContext)(v: T) = ()
+  override def run(ctx: LeonContext)(v: Any) = ()
 }
diff --git a/src/main/scala/leon/Main.scala b/src/main/scala/leon/Main.scala
index f04a463cfe6dfaf969782c014a9cc344e72e012f..3f6f9e9278a6504a5e465db6870b84b987e67bfa 100644
--- a/src/main/scala/leon/Main.scala
+++ b/src/main/scala/leon/Main.scala
@@ -13,7 +13,7 @@ object Main {
       /*FunctionHoisting,*/
       Simplificator,
       synthesis.SynthesisPhase,
-      AnalysisPhase
+      verification.AnalysisPhase
     )
   }
 
@@ -104,11 +104,11 @@ object Main {
     // Process options we understand:
     for(opt <- leonOptions) opt match {
       case LeonFlagOption("synthesis") =>
-        settings = settings.copy(synthesis = true, xlang = false, analyze = false)
+        settings = settings.copy(synthesis = true, xlang = false, verify = false)
       case LeonFlagOption("xlang") =>
         settings = settings.copy(synthesis = false, xlang = true)
       case LeonFlagOption("parse") =>
-        settings = settings.copy(synthesis = false, xlang = false, analyze = false)
+        settings = settings.copy(synthesis = false, xlang = false, verify = false)
       case LeonFlagOption("help") =>
         displayHelp(reporter)
       case _ =>
@@ -117,12 +117,10 @@ object Main {
     LeonContext(settings = settings, reporter = reporter, files = files, options = leonOptions)
   }
 
-  implicit def phaseToPipeline[F, T](phase: LeonPhase[F, T]): Pipeline[F, T] = new PipeCons(phase, new PipeNil())
-
   def computePipeline(settings: Settings): Pipeline[List[String], Unit] = {
     import purescala.Definitions.Program
 
-    val pipeBegin = phaseToPipeline(plugin.ExtractionPhase)
+    val pipeBegin : Pipeline[List[String],Program] = plugin.ExtractionPhase
 
     val pipeTransforms: Pipeline[Program, Program] =
       if (settings.xlang) {
@@ -141,18 +139,18 @@ object Main {
         NoopPhase[Program]()
       }
 
-    val pipeAnalysis: Pipeline[Program, Program] =
-      if (settings.analyze) {
-        AnalysisPhase
+    val pipeVerify: Pipeline[Program, Any] =
+      if (settings.verify) {
+        verification.AnalysisPhase
       } else {
         NoopPhase[Program]()
       }
 
-    pipeBegin followedBy
-    pipeTransforms followedBy
-    pipeSynthesis followedBy
-    pipeAnalysis andThen
-    ExitPhase[Program]()
+    pipeBegin andThen
+    pipeTransforms andThen
+    pipeSynthesis andThen
+    pipeVerify andThen
+    ExitPhase()
   }
 
   def main(args : Array[String]) {
diff --git a/src/main/scala/leon/Pipeline.scala b/src/main/scala/leon/Pipeline.scala
index 477a08c31250ba1996ddccd59262631fe75499c1..cc79495df619d9cb6ed74fb7a8fb03f628e07d6b 100644
--- a/src/main/scala/leon/Pipeline.scala
+++ b/src/main/scala/leon/Pipeline.scala
@@ -1,26 +1,11 @@
 package leon
 
-abstract class Pipeline[F, T] {
-  def andThen[G](then: LeonPhase[T, G]): Pipeline[F, G];
-  def followedBy[G](pipe: Pipeline[T, G]): Pipeline[F, G];
-  def run(ctx: LeonContext)(v: F): T;
-}
-
-class PipeCons[F, V, T](phase: LeonPhase[F, V], then: Pipeline[V, T]) extends Pipeline[F, T] {
-  def andThen[G](last: LeonPhase[T, G]) = new PipeCons(phase, then andThen last)
-  def followedBy[G](pipe: Pipeline[T, G]) = new PipeCons(phase, then followedBy pipe);
-  def run(ctx: LeonContext)(v: F): T = then.run(ctx)(phase.run(ctx)(v))
+abstract class Pipeline[-F, +T] {
+  self => 
 
-  override def toString = {
-    phase.toString + " -> " + then.toString
+  def andThen[G](then: Pipeline[T, G]): Pipeline[F, G] = new Pipeline[F,G] {
+    def run(ctx : LeonContext)(v : F) : G = then.run(ctx)(self.run(ctx)(v))
   }
-}
 
-class PipeNil[T]() extends Pipeline[T,T] {
-  def andThen[G](last: LeonPhase[T, G]) = new PipeCons(last, new PipeNil)
-  def run(ctx: LeonContext)(v: T): T = v
-  def followedBy[G](pipe: Pipeline[T, G]) = pipe;
-  override def toString = {
-    "|"
-  }
+  def run(ctx: LeonContext)(v: F): T
 }
diff --git a/src/main/scala/leon/Reporter.scala b/src/main/scala/leon/Reporter.scala
index 03512770fc9c84d9d11a41b2124fafdc6683e506..814c4352a321f41a0f75bac34ad20643d69b6c7b 100644
--- a/src/main/scala/leon/Reporter.scala
+++ b/src/main/scala/leon/Reporter.scala
@@ -27,10 +27,7 @@ class DefaultReporter extends Reporter {
   protected val infoPfx    = "[ Info  ] "
   protected val fatalPfx   = "[ Fatal ] "
 
-  def output(msg: String) : Unit = {
-    if(!Settings.simpleOutput)
-      println(msg)
-  }
+  def output(msg: String) : Unit = println(msg)
 
   protected def reline(pfx: String, msg: String) : String = {
     val color = if(pfx == errorPfx || pfx == warningPfx || pfx == fatalPfx) {
diff --git a/src/main/scala/leon/Settings.scala b/src/main/scala/leon/Settings.scala
index c57a1e4514b00372033c7e19242b7782e40b8c56..04ed6bc41df6aa410879b2492aeb9f5580ab93a9 100644
--- a/src/main/scala/leon/Settings.scala
+++ b/src/main/scala/leon/Settings.scala
@@ -1,6 +1,7 @@
 package leon
 
 // typically these settings can be changed through some command-line switch.
+// TODO this global object needs to die (or at least clean out of its var's)
 object Settings {
   var experimental : Boolean = false
   var showIDs: Boolean = false
@@ -10,7 +11,6 @@ object Settings {
   var runDefaultExtensions: Boolean = true
   var noForallAxioms: Boolean = true
   var unrollingLevel: Int = 0
-  var zeroInlining : Boolean = true
   var useBAPA: Boolean = false
   var impureTestcases: Boolean = false
   var nbTestcases: Int = 1
@@ -26,7 +26,6 @@ object Settings {
   var bitvectorBitwidth : Option[Int] = None
   var debugLevel: Int = 0
   var debugTags: Set[String] = Set.empty
-  var simpleOutput: Boolean = false
   var synthesis: Boolean = false
   var transformProgram: Boolean              = true
   var stopAfterExtraction: Boolean           = false
@@ -38,5 +37,5 @@ object Settings {
 case class Settings(
   val synthesis: Boolean    = false,
   val xlang: Boolean        = false,
-  val analyze: Boolean      = true
+  val verify: Boolean      = true
 )
diff --git a/src/main/scala/leon/TestExtension.scala b/src/main/scala/leon/TestExtension.scala
deleted file mode 100644
index 5fd517280e6c00eb4939e0615a5b6d41f0822379..0000000000000000000000000000000000000000
--- a/src/main/scala/leon/TestExtension.scala
+++ /dev/null
@@ -1,109 +0,0 @@
-package leon
-
-import purescala.Common._
-import purescala.Trees._
-import purescala.TreeOps._
-import purescala.Extractors._
-import purescala.TypeTrees._
-import purescala.Definitions._
-import Extensions._
-
-class TestExtension(val reporter: Reporter) extends Analyser(reporter) {
-  val description : String = "Testing."
-  def analyse(program : Program) : Unit = {
-  }/*
-    for((f: FunDef) <- program.definedFunctions) {
-      reporter.info("Got an f ! " + f.id)
-      reporter.info("Normal  : " + f.body.get)
-      val iteized = matchToIfThenElse(expandLets(f.body.get))
-      reporter.info("ITEized : " + iteized)
-      reporter.info("Leadsto ? : " + (leadsToCall(iteized) : String))
-      cleanClausify(iteized, program)
-      val (e,l,m) = clausifyITE(iteized)
-      reporter.info("As clauses : " + e)
-      l.foreach(reporter.info(_))
-      reporter.info("***\n")
-    }
-    reporter.info("Done.")
-  }*/
-
-  type LiftedBoolean = Option[Boolean]
-  val Yes : LiftedBoolean  = Some(true)
-  val No : LiftedBoolean = Some(false)
-  val Maybe : LiftedBoolean = None
-  implicit def bool2liftedbool(b : Boolean) : LiftedBoolean = Some(b)
-  implicit def liftedbool2String(l : LiftedBoolean) : String = l match {
-    case Yes => "Yes"
-    case No => "No"
-    case Maybe => "Maybe"
-  }
-
-  // assumes no lets and no match.
-  def leadsToCall(e : Expr) : LiftedBoolean = e match {
-    case f : FunctionInvocation => true
-    case IfExpr(a1, a2, a3) => {
-      if(leadsToCall(a1) == Yes) Yes else (leadsToCall(a2),leadsToCall(a3)) match {
-        case (Yes,Yes) => Yes
-        case (No,No) => No
-        case _ => Maybe
-      }
-    }
-    case n @ NAryOperator(args, _) => {
-      val ra = args.map(leadsToCall(_))
-      if(ra.exists(_ == Yes)) {
-        Yes
-      } else if(ra.forall(_ == No)) {
-        No
-      } else {
-        Maybe
-      }
-    }
-    case b @ BinaryOperator(a1,a2,_) => (leadsToCall(a1),leadsToCall(a2)) match {
-      case (Yes,_) => Yes
-      case (_,Yes) => Yes
-      case (No,No) => No
-      case _ => Maybe
-    }
-    case u @ UnaryOperator(a,_) => leadsToCall(a)
-    case t : Terminal => false
-    case unhandled => scala.sys.error("unhandled.")
-  }
-
-  private def cleanClausify(formula : Expr, program : Program) : Unit = {
-    val nonRec = allNonRecursiveFunctionCallsOf(formula, program)
-    val allRec = functionCallsOf(formula) -- nonRec
-
-    val (e,l,m) = clausifyITE(formula)
-    var dangerSet : Set[Expr] = Set.empty[Expr] ++ allRec
-    var change : Boolean = true
-    var newSet : Set[Expr] = Set.empty
-
-    while(change) {
-      change = false
-    }
-  }
-
-  private def clausifyITE(formula : Expr) : (Expr, List[Expr], Map[Identifier,Identifier]) = {
-    var newClauses : List[Expr] = Nil
-    var ite2Bools : Map[Identifier,Identifier] = Map.empty
-
-    def clausify(ex : Expr) : Option[Expr] = ex match {
-      //case _ if leadsToCall(ex) == No => None
-      case ie @ IfExpr(cond, then, elze) => {
-        val switch = FreshIdentifier("path", true).setType(BooleanType).toVariable
-        val placeHolder = FreshIdentifier("iteval", true).setType(ie.getType).toVariable
-        newClauses = Iff(switch, cond) :: newClauses
-        newClauses = Implies(switch, Equals(placeHolder, then)) :: newClauses
-        newClauses = Implies(Not(switch), Equals(placeHolder, elze)) :: newClauses
-        // newBools = newBools + switch.id
-        ite2Bools = ite2Bools + (placeHolder.id -> switch.id)
-        Some(placeHolder)
-      }
-      case _ => None
-    }
-
-    val cleanedUp = searchAndReplaceDFS(clausify)(formula)
-
-    (cleanedUp, newClauses.reverse, ite2Bools)
-  }
-}
diff --git a/src/main/scala/leon/isabelle/Main.scala b/src/main/scala/leon/isabelle/Main.scala
index ac95c8095ec4a9af8543e8d0cecc795a5f8acd19..3db02146e338b8b6f72c886df9072c5d98f01311 100644
--- a/src/main/scala/leon/isabelle/Main.scala
+++ b/src/main/scala/leon/isabelle/Main.scala
@@ -4,6 +4,8 @@ import leon.Extensions._
 import leon.Reporter
 import leon.Settings._
 
+import leon.verification.Analyser
+
 import leon.purescala.Common.Identifier
 import leon.purescala.Definitions._
 import leon.purescala.PrettyPrinter
diff --git a/src/main/scala/leon/plugin/AnalysisComponent.scala b/src/main/scala/leon/plugin/AnalysisComponent.scala
index 77c058a6fa5335cbc5092b545c453d9ef0396cf0..1cc1cde07699255945ffab7a42dba0c52e586a98 100644
--- a/src/main/scala/leon/plugin/AnalysisComponent.scala
+++ b/src/main/scala/leon/plugin/AnalysisComponent.scala
@@ -24,10 +24,7 @@ class AnalysisComponent(val global: Global, val pluginInstance: LeonPlugin)
   
   protected def stopIfErrors: Unit = {
     if(reporter.hasErrors) {
-      if(Settings.simpleOutput)
-        println("error")
       sys.exit(1)
-      //throw new Exception("There were errors.")
     }
   }
 
diff --git a/src/main/scala/leon/plugin/ExtractorPhase.scala b/src/main/scala/leon/plugin/ExtractorPhase.scala
index ef94d03e53d357b4837173ff49cdf2d082fc3d97..fdc271d53cc641d587dde3fbef7b1520579f28e4 100644
--- a/src/main/scala/leon/plugin/ExtractorPhase.scala
+++ b/src/main/scala/leon/plugin/ExtractorPhase.scala
@@ -12,6 +12,8 @@ object ExtractionPhase extends LeonPhase[List[String], Program] {
   def run(ctx: LeonContext)(args: List[String]): Program = {
 
     val settings = new NSCSettings
+    settings.usejavacp.value = true
+
     val compilerOpts = args.filterNot(_.startsWith("--"))
 
     val command = new CompilerCommand(compilerOpts, settings) {
diff --git a/src/main/scala/leon/plugin/LeonPlugin.scala b/src/main/scala/leon/plugin/LeonPlugin.scala
index 13542da332745a4db94d34e09bb107a5f4d75e3b..afc5fa35d441c099da969c2e5789ea48ea229643 100644
--- a/src/main/scala/leon/plugin/LeonPlugin.scala
+++ b/src/main/scala/leon/plugin/LeonPlugin.scala
@@ -63,7 +63,6 @@ class LeonPlugin(val global: PluginRunner) extends Plugin {
         case "cores"         =>                     leon.Settings.useCores = true
         case "quickcheck"    =>                     leon.Settings.useQuickCheck = true
         case "parallel"      =>                     leon.Settings.useParallel = true
-        case "oneline"       =>                     leon.Settings.simpleOutput = true
         case "noLuckyTests"  =>                     leon.Settings.luckyTest = false
         case "noverifymodel" =>                     leon.Settings.verifyModel = false
         case "imperative"     =>                    leon.Settings.synthesis = false;
diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala
index 4610fb491c1dc139e0c824caf175162cf5308d7c..98551cbc108a6b6f0c4ea74f081584049b65adf4 100644
--- a/src/main/scala/leon/purescala/TreeOps.scala
+++ b/src/main/scala/leon/purescala/TreeOps.scala
@@ -1,7 +1,7 @@
 package leon
 package purescala
 
-import leon.Extensions.Solver
+import leon.solvers.Solver
 
 object TreeOps {
   import Common._
diff --git a/src/main/scala/leon/solvers/Solver.scala b/src/main/scala/leon/solvers/Solver.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d998013231be4548a885340fce579e39e09e40e9
--- /dev/null
+++ b/src/main/scala/leon/solvers/Solver.scala
@@ -0,0 +1,40 @@
+package leon
+package solvers
+
+import Extensions.Extension
+
+import purescala.Common._
+import purescala.Definitions._
+import purescala.TreeOps._
+import purescala.Trees._
+
+abstract class Solver(val reporter: Reporter) extends Extension(reporter) {
+  // This can be used by solvers to "see" the programs from which the
+  // formulas come. (e.g. to set up some datastructures for the defined
+  // ADTs, etc.) 
+  // Ideally, we would pass it at construction time and not change it later.
+  def setProgram(program: Program) : Unit = {}
+
+  // Returns Some(true) if valid, Some(false) if invalid,
+  // None if unknown.
+  // should halt as soon as possible with any result (Unknown is ok) as soon as forceStop is true
+  def solve(expression: Expr) : Option[Boolean]
+
+  def solveOrGetCounterexample(expression : Expr) : (Option[Boolean],Map[Identifier,Expr]) = (solve(expression), Map.empty)
+
+  def isUnsat(expression: Expr) : Option[Boolean] = solve(negate(expression))
+  def superseeds : Seq[String] = Nil
+
+  private var _forceStop = false
+
+  def halt() : Unit = {
+    _forceStop = true
+  }
+
+  def init() : Unit = {
+    _forceStop = false
+  }
+
+  protected def forceStop = _forceStop
+}
+
diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index 5c31961fb2bc40e0d749e6b44112b74788e22b4a..414e8e1a4941f51659215e545b68095cdf1e30bc 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -15,7 +15,7 @@ import scala.collection.mutable.{Set => MutableSet}
 // This is just to factor out the things that are common in "classes that deal
 // with a Z3 instance"
 trait AbstractZ3Solver {
-  self: Solver =>
+  self: leon.solvers.Solver =>
 
   val reporter: Reporter
 
diff --git a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
index 9d654c88fda3821b41765969de134acd28a50bbc..c229d44d3a81e1c4e1bbcf90ee94cc1657f807ba 100644
--- a/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/FairZ3Solver.scala
@@ -2,6 +2,9 @@ package leon
 package solvers.z3
 
 import z3.scala._
+
+import leon.solvers.Solver
+
 import purescala.Common._
 import purescala.Definitions._
 import purescala.Trees._
@@ -247,7 +250,7 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
       }
 
       reporter.info(" - Running Z3 search...")
-      val (answer, model, core) : (Option[Boolean], Z3Model, Seq[Z3AST]) = if(Settings.useCores) {
+      val answerModelCore : (Option[Boolean], Z3Model, Seq[Z3AST]) = if(Settings.useCores) {
         // println(blockingSetAsZ3)
         z3.checkAssumptions(blockingSetAsZ3 : _*)
       } else {
@@ -259,6 +262,8 @@ class FairZ3Solver(reporter: Reporter) extends Solver(reporter) with AbstractZ3S
         z3SearchStopwatch.stop
         (a, m, Seq.empty[Z3AST])
       }
+      val (answer, model, core) = answerModelCore // to work around the stupid type inferer
+
       reporter.info(" - Finished search with blocked literals")
       Logger.debug("The blocking guards are: " + blockingSet.mkString(", "), 4, "z3solver")
 
diff --git a/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala b/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala
index 1ad2ed1fc47f285d0b3ff3101b1c2698291a4958..0100286d6446b96173fa7e2c0b1d7b8d49ceeb9f 100644
--- a/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/UninterpretedZ3Solver.scala
@@ -2,6 +2,9 @@ package leon
 package solvers.z3
 
 import z3.scala._
+
+import leon.solvers.Solver
+
 import purescala.Common._
 import purescala.Definitions._
 import purescala.Trees._
diff --git a/src/main/scala/leon/synthesis/Synthesizer.scala b/src/main/scala/leon/synthesis/Synthesizer.scala
index 0dc4cb283f48c0674b8a3638a1e4f875f7e9affc..91ba9d37f14607bfd2ed867f750791cdbae5260d 100644
--- a/src/main/scala/leon/synthesis/Synthesizer.scala
+++ b/src/main/scala/leon/synthesis/Synthesizer.scala
@@ -7,7 +7,7 @@ import purescala.TreeOps._
 import purescala.Trees.{Expr, Not}
 import purescala.ScalaPrinter
 
-import Extensions.Solver
+import solvers.Solver
 import java.io.File
 
 import collection.mutable.PriorityQueue
diff --git a/src/main/scala/leon/testgen/TestGeneration.scala b/src/main/scala/leon/testgen/TestGeneration.scala
index 5056ec0e8ead3156847a18a5f358cde951b11d5e..ea6ccabcb826289172607dc94bbf7398e8137716 100644
--- a/src/main/scala/leon/testgen/TestGeneration.scala
+++ b/src/main/scala/leon/testgen/TestGeneration.scala
@@ -1,5 +1,7 @@
 package leon.testgen
 
+import leon.verification.Analyser
+
 import leon.purescala.Common._
 import leon.purescala.Definitions._
 import leon.purescala.Trees._
diff --git a/src/main/scala/leon/verification/Analyser.scala b/src/main/scala/leon/verification/Analyser.scala
new file mode 100644
index 0000000000000000000000000000000000000000..84a2d87221bdfeb1d225ec6bb3542c2a5db7f4e4
--- /dev/null
+++ b/src/main/scala/leon/verification/Analyser.scala
@@ -0,0 +1,13 @@
+package leon
+package verification
+
+import Extensions.Extension
+
+import purescala.Definitions.Program
+
+// TODO this class is slowly but surely becoming useless, as we now have a notion of phases.
+abstract class Analyser(reporter: Reporter) extends Extension(reporter) {
+  // Does whatever the analysis should. Uses the reporter to
+  // signal results and/or errors.
+  def analyse(program: Program) : Unit
+}
diff --git a/src/main/scala/leon/verification/Analysis.scala b/src/main/scala/leon/verification/Analysis.scala
new file mode 100644
index 0000000000000000000000000000000000000000..1521ad8e1e3fa4ad42d36664d76d27a5fed4966c
--- /dev/null
+++ b/src/main/scala/leon/verification/Analysis.scala
@@ -0,0 +1,157 @@
+package leon
+package verification
+
+import purescala.Common._
+import purescala.Definitions._
+import purescala.Trees._
+import purescala.TreeOps._
+import purescala.TypeTrees._
+
+import Extensions._
+
+import solvers.{Solver,TrivialSolver}
+
+import scala.collection.mutable.{Set => MutableSet}
+
+class Analysis(val program : Program, val reporter: Reporter) {
+  Extensions.loadAll(reporter)
+
+  val analysisExtensions: Seq[Analyser] = loadedAnalysisExtensions
+
+  val trivialSolver = new TrivialSolver(reporter) // This one you can't disable :D
+
+  val solverExtensions: Seq[Solver] = trivialSolver +: loadedSolverExtensions
+
+  solverExtensions.foreach(_.setProgram(program))
+
+  val defaultTactic = new DefaultTactic(reporter)
+  defaultTactic.setProgram(program)
+  val inductionTactic = new InductionTactic(reporter)
+  inductionTactic.setProgram(program)
+
+  // Calling this method will run all analyses on the program passed at
+  // construction time. If at least one solver is loaded, verification
+  // conditions are generated and passed to all solvers. Otherwise, only the
+  // Analysis extensions are run on the program.
+  def analyse : VerificationReport = {
+    // We generate all function templates in advance.
+    for(funDef <- program.definedFunctions if funDef.hasImplementation) {
+      // this gets cached :D
+      FunctionTemplate.mkTemplate(funDef)
+    }
+
+    val report = if(solverExtensions.size > 1) {
+      reporter.info("Running verification condition generation...")
+      checkVerificationConditions(generateVerificationConditions)
+    } else {
+      reporter.warning("No solver specified. Cannot test verification conditions.")
+      VerificationReport.emptyReport
+    }
+
+    analysisExtensions.foreach(ae => {
+      reporter.info("Running analysis from extension: " + ae.description)
+      ae.analyse(program)
+    })
+
+    report
+  }
+
+  private def generateVerificationConditions : List[VerificationCondition] = {
+    var allVCs: Seq[VerificationCondition] = Seq.empty
+    val analysedFunctions: MutableSet[String] = MutableSet.empty
+
+    for(funDef <- program.definedFunctions.toList.sortWith((fd1, fd2) => fd1 < fd2) if (Settings.functionsToAnalyse.isEmpty || Settings.functionsToAnalyse.contains(funDef.id.name))) {
+      analysedFunctions += funDef.id.name
+
+      val tactic: Tactic =
+        if(funDef.annotations.contains("induct")) {
+          inductionTactic
+        } else {
+          defaultTactic
+        }
+
+      if(funDef.body.isDefined) {
+        allVCs ++= tactic.generatePreconditions(funDef)
+        allVCs ++= tactic.generatePatternMatchingExhaustivenessChecks(funDef)
+        allVCs ++= tactic.generatePostconditions(funDef)
+        allVCs ++= tactic.generateMiscCorrectnessConditions(funDef)
+        allVCs ++= tactic.generateArrayAccessChecks(funDef)
+      }
+      allVCs = allVCs.sortWith((vc1, vc2) => {
+        val id1 = vc1.funDef.id.name
+        val id2 = vc2.funDef.id.name
+        if(id1 != id2) id1 < id2 else vc1 < vc2
+      })
+    }
+
+    val notFound: Set[String] = Settings.functionsToAnalyse -- analysedFunctions
+    notFound.foreach(fn => reporter.error("Did not find function \"" + fn + "\" though it was marked for analysis."))
+
+    allVCs.toList
+  }
+
+  private def checkVerificationConditions(vcs: Seq[VerificationCondition]) : VerificationReport = {
+    for(vcInfo <- vcs) {
+      val funDef = vcInfo.funDef
+      val vc = vcInfo.condition
+
+      reporter.info("Now considering '" + vcInfo.kind + "' VC for " + funDef.id + "...")
+      reporter.info("Verification condition (" + vcInfo.kind + ") for ==== " + funDef.id + " ====")
+      // if(Settings.unrollingLevel == 0) {
+      reporter.info(simplifyLets(vc))
+      // } else {
+      //   reporter.info("(not showing unrolled VCs)")
+      // }
+
+      // try all solvers until one returns a meaningful answer
+      var superseeded : Set[String] = Set.empty[String]
+      solverExtensions.find(se => {
+        reporter.info("Trying with solver: " + se.shortDescription)
+        if(superseeded(se.shortDescription) || superseeded(se.description)) {
+          reporter.info("Solver was superseeded. Skipping.")
+          false
+        } else {
+          superseeded = superseeded ++ Set(se.superseeds: _*)
+
+          val t1 = System.nanoTime
+          se.init()
+          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 ====")
+
+              vcInfo.value = Some(true)
+              vcInfo.solvedWith = Some(se)
+              vcInfo.time = Some(dt)
+
+              true
+            }
+            case Some(false) => {
+              reporter.error("==== INVALID ====")
+
+              vcInfo.value = Some(false)
+              vcInfo.solvedWith = Some(se)
+              vcInfo.time = Some(dt)
+
+              true
+            }
+          }
+        }
+      }) match {
+        case None => {
+          reporter.warning("No solver could prove or disprove the verification condition.")
+        }
+        case _ => 
+      } 
+    
+    } 
+
+    val report = new VerificationReport(vcs)
+    reporter.info(report.summaryString)
+    report
+  }
+}
diff --git a/src/main/scala/leon/verification/AnalysisPhase.scala b/src/main/scala/leon/verification/AnalysisPhase.scala
new file mode 100644
index 0000000000000000000000000000000000000000..726a7922a59de70142369301a5e57917c4b1ad2e
--- /dev/null
+++ b/src/main/scala/leon/verification/AnalysisPhase.scala
@@ -0,0 +1,13 @@
+package leon
+package verification
+
+import purescala.Definitions._
+
+object AnalysisPhase extends LeonPhase[Program,VerificationReport] {
+  val name = "Analysis"
+  val description = "Leon Verification"
+
+  def run(ctx: LeonContext)(program: Program) : VerificationReport = {
+    new Analysis(program, ctx.reporter).analyse
+  }
+}
diff --git a/src/main/scala/leon/DefaultTactic.scala b/src/main/scala/leon/verification/DefaultTactic.scala
similarity index 85%
rename from src/main/scala/leon/DefaultTactic.scala
rename to src/main/scala/leon/verification/DefaultTactic.scala
index 4078e6e490f8a1bbe5adc5a985459d144a13c363..47a2af0d2a098722e36af1c2e829bf31e5734a59 100644
--- a/src/main/scala/leon/DefaultTactic.scala
+++ b/src/main/scala/leon/verification/DefaultTactic.scala
@@ -1,11 +1,11 @@
 package leon
+package verification
 
 import purescala.Common._
 import purescala.Trees._
 import purescala.TreeOps._
 import purescala.Extractors._
 import purescala.Definitions._
-import Extensions.Tactic
 
 import scala.collection.mutable.{Map => MutableMap}
 
@@ -42,43 +42,7 @@ class DefaultTactic(reporter: Reporter) extends Tactic(reporter) {
             Implies(matchToIfThenElse(prec.get), bodyAndPost)
           }
 
-          import Analysis._
-
-          if(Settings.zeroInlining) {
-            withPrec
-          } else {
-            if(Settings.experimental) {
-              reporter.info("Raw:")
-              reporter.info(withPrec)
-              reporter.info("Raw, expanded:")
-              reporter.info(expandLets(withPrec))
-            }
-            reporter.info(" - inlining...")
-            val expr0 = inlineNonRecursiveFunctions(program, withPrec)
-            if(Settings.experimental) {
-              reporter.info("Inlined:")
-              reporter.info(expr0)
-              reporter.info("Inlined, expanded:")
-              reporter.info(expandLets(expr0))
-            }
-            reporter.info(" - unrolling...")
-            val expr1 = unrollRecursiveFunctions(program, expr0, Settings.unrollingLevel)
-            if(Settings.experimental) {
-              reporter.info("Unrolled:")
-              reporter.info(expr1)
-              reporter.info("Unrolled, expanded:")
-              reporter.info(expandLets(expr1))
-            }
-            reporter.info(" - inlining contracts...")
-            val expr2 = inlineContracts(expr1)
-            if(Settings.experimental) {
-              reporter.info("Contract'ed:")
-              reporter.info(expr2)
-              reporter.info("Contract'ed, expanded:")
-              reporter.info(expandLets(expr2))
-            }
-            expr2
-          }
+          withPrec
         }
         if(functionDefinition.fromLoop)
           Seq(new VerificationCondition(theExpr, functionDefinition.parent.get, VCKind.InvariantPost, this.asInstanceOf[DefaultTactic]).setPosInfo(functionDefinition))
diff --git a/src/main/scala/leon/InductionTactic.scala b/src/main/scala/leon/verification/InductionTactic.scala
similarity index 99%
rename from src/main/scala/leon/InductionTactic.scala
rename to src/main/scala/leon/verification/InductionTactic.scala
index 4adc158b323678d423ce9c7bb80705ac2512fc25..360f41493440cba920be3a4f21289f33ff3e9f1b 100644
--- a/src/main/scala/leon/InductionTactic.scala
+++ b/src/main/scala/leon/verification/InductionTactic.scala
@@ -1,4 +1,5 @@
 package leon
+package verification
 
 import purescala.Common._
 import purescala.Trees._
diff --git a/src/main/scala/leon/verification/Tactic.scala b/src/main/scala/leon/verification/Tactic.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d19752949f393e5bad32f2824b723ea6dfabed91
--- /dev/null
+++ b/src/main/scala/leon/verification/Tactic.scala
@@ -0,0 +1,15 @@
+package leon
+package verification
+
+import Extensions.Extension
+
+import purescala.Definitions._
+
+abstract class Tactic(reporter: Reporter) extends Extension(reporter) {
+  def setProgram(program: Program) : Unit = {}
+  def generatePostconditions(function: FunDef) : Seq[VerificationCondition]
+  def generatePreconditions(function: FunDef) : Seq[VerificationCondition]
+  def generatePatternMatchingExhaustivenessChecks(function: FunDef) : Seq[VerificationCondition]
+  def generateMiscCorrectnessConditions(function: FunDef) : Seq[VerificationCondition]
+  def generateArrayAccessChecks(function: FunDef) : Seq[VerificationCondition]
+}
diff --git a/src/main/scala/leon/VerificationCondition.scala b/src/main/scala/leon/verification/VerificationCondition.scala
similarity index 56%
rename from src/main/scala/leon/VerificationCondition.scala
rename to src/main/scala/leon/verification/VerificationCondition.scala
index e5556f1acf52fa3f8472556bcc66d3572c032488..217eb94b70287d8f74de5a98a1370c0068c831ac 100644
--- a/src/main/scala/leon/VerificationCondition.scala
+++ b/src/main/scala/leon/verification/VerificationCondition.scala
@@ -1,9 +1,10 @@
-package leon
+package leon.verification
 
-import purescala.Trees._
-import purescala.Definitions._
-import purescala.Common._
-import Extensions._
+import leon.purescala.Trees._
+import leon.purescala.Definitions._
+import leon.purescala.Common._
+
+import leon.solvers.Solver
 
 /** This is just to hold some history information. */
 class VerificationCondition(val condition: Expr, val funDef: FunDef, val kind: VCKind.Value, val tactic: Tactic, val info: String = "") extends ScalacPositional {
@@ -20,28 +21,16 @@ class VerificationCondition(val condition: Expr, val funDef: FunDef, val kind: V
     case Some(false) => "invalid"
   }
 
-  private def tacticStr = tactic.shortDescription match {
+  def tacticStr = tactic.shortDescription match {
     case "default" => ""
     case s => s
   }
 
-  private def solverStr = solvedWith match {
+  def solverStr = solvedWith match {
     case Some(s) => s.shortDescription
     case None => ""
   }
 
-  private def timeStr = time.map(t => "%-3.3f".format(t)).getOrElse("")
-
-  def infoLine : String = {
-    "║ %-25s %-9s %9s %-8s %-10s %-7s %7s ║" format (funDef.id.toString, kind, posInfo, status, tacticStr, solverStr, timeStr)
-  }
-}
-
-object VerificationCondition {
-  val infoFooter : String = "╚" + ("═" * 83) + "╝"
-  val infoHeader : String = ". ┌─────────┐\n" +
-                            "╔═╡ Summary ╞" + ("═" * 71) + "╗\n" +
-                            "║ └─────────┘" + (" " * 71) + "║"
 }
 
 object VCKind extends Enumeration {
diff --git a/src/main/scala/leon/verification/VerificationReport.scala b/src/main/scala/leon/verification/VerificationReport.scala
new file mode 100644
index 0000000000000000000000000000000000000000..16b6516241c806005605ec8ce0a56cc178eb3035
--- /dev/null
+++ b/src/main/scala/leon/verification/VerificationReport.scala
@@ -0,0 +1,48 @@
+package leon.verification
+
+class VerificationReport(val conditions : Seq[VerificationCondition]) {
+  lazy val totalConditions : Int = conditions.size
+
+  lazy val totalTime : Double = conditions.foldLeft(0.0d)((t,c) => t + c.time.getOrElse(0.0d))
+
+  lazy val totalValid : Int = conditions.count(_.value == Some(true))
+
+  lazy val totalInvalid : Int = conditions.count(_.value == Some(false))
+
+  lazy val totalUnknown : Int = conditions.count(_.value == None)
+
+  def summaryString : String = if(totalConditions >= 0) {
+    VerificationReport.infoHeader +
+    conditions.map(VerificationReport.infoLine).mkString("\n", "\n", "\n") +
+    VerificationReport.infoSep +
+    ("║ total: %-4d   valid: %-4d   invalid: %-4d   unknown %-4d " +
+      (" " * 18) +
+      " %-3.3f ║\n").format(totalConditions, totalValid, totalInvalid, totalUnknown, totalTime) +
+    VerificationReport.infoFooter
+  } else {
+    "No verification conditions were analyzed."
+  }
+}
+
+object VerificationReport {
+  def emptyReport : VerificationReport = new VerificationReport(Nil)
+
+  private val infoSep    : String = "╟" + ("┄" * 83) + "╢\n"
+  private val infoFooter : String = "╚" + ("═" * 83) + "╝"
+  private val infoHeader : String = ". ┌─────────┐\n" +
+                                    "╔═╡ Summary ╞" + ("═" * 71) + "╗\n" +
+                                    "║ └─────────┘" + (" " * 71) + "║"
+
+  private def infoLine(vc : VerificationCondition) : String = {
+    val timeStr = vc.time.map(t => "%-3.3f".format(t)).getOrElse("")
+
+    "║ %-25s %-9s %9s %-8s %-10s %-7s %7s ║".format(
+      vc.funDef.id.toString,
+      vc.kind,
+      vc.posInfo,
+      vc.status,
+      vc.tacticStr,
+      vc.solverStr,
+      timeStr)
+  }
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/AmortizedQueue.scala b/src/test/resources/regression/verification/purescala/valid/AmortizedQueue.scala
new file mode 100644
index 0000000000000000000000000000000000000000..dd5a75f89735805a74612665e487aa8fa99ec397
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/AmortizedQueue.scala
@@ -0,0 +1,124 @@
+import scala.collection.immutable.Set
+import leon.Utils._
+import leon.Annotations._
+
+object AmortizedQueue {
+  sealed abstract class List
+  case class Cons(head : Int, tail : List) extends List
+  case class Nil() extends List
+
+  sealed abstract class AbsQueue
+  case class Queue(front : List, rear : List) extends AbsQueue
+
+  def size(list : List) : Int = (list match {
+    case Nil() => 0
+    case Cons(_, xs) => 1 + size(xs)
+  }) ensuring(_ >= 0)
+
+  def content(l: List) : Set[Int] = l match {
+    case Nil() => Set.empty[Int]
+    case Cons(x, xs) => Set(x) ++ content(xs)
+  }
+  
+  def asList(queue : AbsQueue) : List = queue match {
+    case Queue(front, rear) => concat(front, reverse(rear))
+  }
+
+  def concat(l1 : List, l2 : List) : List = (l1 match {
+    case Nil() => l2
+    case Cons(x,xs) => Cons(x, concat(xs, l2))
+  }) ensuring (res => size(res) == size(l1) + size(l2) && content(res) == content(l1) ++ content(l2))
+
+  def isAmortized(queue : AbsQueue) : Boolean = queue match {
+    case Queue(front, rear) => size(front) >= size(rear)
+  }
+
+  def isEmpty(queue : AbsQueue) : Boolean = queue match {
+    case Queue(Nil(), Nil()) => true
+    case _ => false
+  }
+
+  def reverse(l : List) : List = (l match {
+    case Nil() => Nil()
+    case Cons(x, xs) => concat(reverse(xs), Cons(x, Nil()))
+  }) ensuring (content(_) == content(l))
+
+  def amortizedQueue(front : List, rear : List) : AbsQueue = {
+    if (size(rear) <= size(front))
+      Queue(front, rear)
+    else
+      Queue(concat(front, reverse(rear)), Nil())
+  } ensuring(isAmortized(_))
+
+  def enqueue(queue : AbsQueue, elem : Int) : AbsQueue = (queue match {
+    case Queue(front, rear) => amortizedQueue(front, Cons(elem, rear))
+  }) ensuring(isAmortized(_))
+
+  def tail(queue : AbsQueue) : AbsQueue = {
+    require(isAmortized(queue) && !isEmpty(queue))
+    queue match {
+      case Queue(Cons(f, fs), rear) => amortizedQueue(fs, rear)
+    }
+  } ensuring (isAmortized(_))
+
+  def front(queue : AbsQueue) : Int = {
+    require(isAmortized(queue) && !isEmpty(queue))
+    queue match {
+      case Queue(Cons(f, _), _) => f
+    }
+  }
+
+  // @induct
+  // def propEnqueue(rear : List, front : List, list : List, elem : Int) : Boolean = {
+  //   require(isAmortized(Queue(front, rear)))
+  //   val queue = Queue(front, rear)
+  //   if (asList(queue) == list) {
+  //     asList(enqueue(queue, elem)) == concat(list, Cons(elem, Nil()))
+  //   } else
+  //     true
+  // } holds
+
+  @induct
+  def propFront(queue : AbsQueue, list : List, elem : Int) : Boolean = {
+    require(!isEmpty(queue) && isAmortized(queue))
+    if (asList(queue) == list) {
+      list match {
+        case Cons(x, _) => front(queue) == x
+      }
+    } else
+      true
+  } holds
+
+  @induct
+  def propTail(rear : List, front : List, list : List, elem : Int) : Boolean = {
+    require(!isEmpty(Queue(front, rear)) && isAmortized(Queue(front, rear)))
+    if (asList(Queue(front, rear)) == list) {
+      list match {
+        case Cons(_, xs) => asList(tail(Queue(front, rear))) == xs
+      }
+    } else
+      true
+  } // holds
+
+  def enqueueAndFront(queue : AbsQueue, elem : Int) : Boolean = {
+    if (isEmpty(queue))
+      front(enqueue(queue, elem)) == elem
+    else
+      true
+  } holds
+
+  def enqueueDequeueThrice(queue : AbsQueue, e1 : Int, e2 : Int, e3 : Int) : Boolean = {
+    if (isEmpty(queue)) {
+      val q1 = enqueue(queue, e1)
+      val q2 = enqueue(q1, e2)
+      val q3 = enqueue(q2, e3)
+      val e1prime = front(q3)
+      val q4 = tail(q3)
+      val e2prime = front(q4)
+      val q5 = tail(q4)
+      val e3prime = front(q5)
+      e1 == e1prime && e2 == e2prime && e3 == e3prime
+    } else
+      true
+  } holds
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/AssociativeList.scala b/src/test/resources/regression/verification/purescala/valid/AssociativeList.scala
new file mode 100644
index 0000000000000000000000000000000000000000..f5a2fc0415a2cf6023f9ae1f3620e99f9fdc27cb
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/AssociativeList.scala
@@ -0,0 +1,50 @@
+import scala.collection.immutable.Set
+import leon.Utils._
+import leon.Annotations._
+
+object AssociativeList { 
+  sealed abstract class KeyValuePairAbs
+  case class KeyValuePair(key: Int, value: Int) extends KeyValuePairAbs
+
+  sealed abstract class List
+  case class Cons(head: KeyValuePairAbs, tail: List) extends List
+  case class Nil() extends List
+
+  sealed abstract class OptionInt
+  case class Some(i: Int) extends OptionInt
+  case class None() extends OptionInt
+
+  def domain(l: List): Set[Int] = l match {
+    case Nil() => Set.empty[Int]
+    case Cons(KeyValuePair(k,_), xs) => Set(k) ++ domain(xs)
+  }
+
+  def find(l: List, e: Int): OptionInt = l match {
+    case Nil() => None()
+    case Cons(KeyValuePair(k, v), xs) => if (k == e) Some(v) else find(xs, e)
+  }
+
+  def noDuplicates(l: List): Boolean = l match {
+    case Nil() => true
+    case Cons(KeyValuePair(k, v), xs) => find(xs, k) == None() && noDuplicates(xs)
+  }
+
+  def update(l1: List, l2: List): List = (l2 match {
+    case Nil() => l1
+    case Cons(x, xs) => update(updateElem(l1, x), xs)
+  }) ensuring(domain(_) == domain(l1) ++ domain(l2))
+
+  def updateElem(l: List, e: KeyValuePairAbs): List = (l match {
+    case Nil() => Cons(e, Nil())
+    case Cons(KeyValuePair(k, v), xs) => e match {
+      case KeyValuePair(ek, ev) => if (ek == k) Cons(KeyValuePair(ek, ev), xs) else Cons(KeyValuePair(k, v), updateElem(xs, e))
+    }
+  }) ensuring(res => e match {
+    case KeyValuePair(k, v) => domain(res) == domain(l) ++ Set[Int](k)
+  })
+
+  @induct
+  def readOverWrite(l: List, k1: Int, k2: Int, e: Int) : Boolean = {
+    find(updateElem(l, KeyValuePair(k2,e)), k1) == (if (k1 == k2) Some(e) else find(l, k1))
+  } holds
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/InsertionSort.scala b/src/test/resources/regression/verification/purescala/valid/InsertionSort.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d2ae67b3bb465f13437a1eb70a57a8e7e613347a
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/InsertionSort.scala
@@ -0,0 +1,80 @@
+import scala.collection.immutable.Set
+import leon.Annotations._
+import leon.Utils._
+
+object InsertionSort {
+  sealed abstract class List
+  case class Cons(head:Int,tail:List) extends List
+  case class Nil() extends List
+
+  sealed abstract class OptInt
+  case class Some(value: Int) extends OptInt
+  case class None() extends OptInt
+
+  def size(l : List) : Int = (l match {
+    case Nil() => 0
+    case Cons(_, xs) => 1 + size(xs)
+  }) ensuring(_ >= 0)
+
+  def contents(l: List): Set[Int] = l match {
+    case Nil() => Set.empty
+    case Cons(x,xs) => contents(xs) ++ Set(x)
+  }
+
+  def min(l : List) : OptInt = l match {
+    case Nil() => None()
+    case Cons(x, xs) => min(xs) match {
+      case None() => Some(x)
+      case Some(x2) => if(x < x2) Some(x) else Some(x2)
+    }
+  }
+
+  def isSorted(l: List): Boolean = l match {
+    case Nil() => true
+    case Cons(x, Nil()) => true
+    case Cons(x, Cons(y, ys)) => x <= y && isSorted(Cons(y, ys))
+  }   
+
+  /* Inserting element 'e' into a sorted list 'l' produces a sorted list with
+   * the expected content and size */
+  def sortedIns(e: Int, l: List): List = {
+    require(isSorted(l))
+    l match {
+      case Nil() => Cons(e,Nil())
+      case Cons(x,xs) => if (x <= e) Cons(x,sortedIns(e, xs)) else Cons(e, l)
+    } 
+  } ensuring(res => contents(res) == contents(l) ++ Set(e) 
+                    && isSorted(res)
+                    && size(res) == size(l) + 1
+            )
+
+  /* Inserting element 'e' into a sorted list 'l' produces a sorted list with
+   * the expected content and size */
+  def buggySortedIns(e: Int, l: List): List = {
+    // require(isSorted(l))
+    l match {
+      case Nil() => Cons(e,Nil())
+      case Cons(x,xs) => if (x <= e) Cons(x,buggySortedIns(e, xs)) else Cons(e, l)
+    } 
+  } ensuring(res => contents(res) == contents(l) ++ Set(e) 
+                    && isSorted(res)
+                    && size(res) == size(l) + 1
+            )
+
+  /* Insertion sort yields a sorted list of same size and content as the input
+   * list */
+  def sort(l: List): List = (l match {
+    case Nil() => Nil()
+    case Cons(x,xs) => sortedIns(x, sort(xs))
+  }) ensuring(res => contents(res) == contents(l) 
+                     && isSorted(res)
+                     && size(res) == size(l)
+             )
+
+  def main(args: Array[String]): Unit = {
+    val ls: List = Cons(5, Cons(2, Cons(4, Cons(5, Cons(1, Cons(8,Nil()))))))
+
+    println(ls)
+    println(sort(ls))
+  }
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/ListOperations.scala b/src/test/resources/regression/verification/purescala/valid/ListOperations.scala
new file mode 100644
index 0000000000000000000000000000000000000000..a4fc4f8dc44a90f59a772b52b1a05053316e94d2
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/ListOperations.scala
@@ -0,0 +1,107 @@
+import scala.collection.immutable.Set
+import leon.Annotations._
+import leon.Utils._
+
+object ListOperations {
+    sealed abstract class List
+    case class Cons(head: Int, tail: List) extends List
+    case class Nil() extends List
+
+    sealed abstract class IntPairList
+    case class IPCons(head: IntPair, tail: IntPairList) extends IntPairList
+    case class IPNil() extends IntPairList
+
+    sealed abstract class IntPair
+    case class IP(fst: Int, snd: Int) extends IntPair
+
+    def size(l: List) : Int = (l match {
+        case Nil() => 0
+        case Cons(_, t) => 1 + size(t)
+    }) ensuring(res => res >= 0)
+
+    def iplSize(l: IntPairList) : Int = (l match {
+      case IPNil() => 0
+      case IPCons(_, xs) => 1 + iplSize(xs)
+    }) ensuring(_ >= 0)
+
+    def zip(l1: List, l2: List) : IntPairList = {
+      // try to comment this and see how pattern-matching becomes
+      // non-exhaustive and post-condition fails
+      require(size(l1) == size(l2))
+
+      l1 match {
+        case Nil() => IPNil()
+        case Cons(x, xs) => l2 match {
+          case Cons(y, ys) => IPCons(IP(x, y), zip(xs, ys))
+        }
+      }
+    } ensuring(iplSize(_) == size(l1))
+
+    def sizeTailRec(l: List) : Int = sizeTailRecAcc(l, 0)
+    def sizeTailRecAcc(l: List, acc: Int) : Int = {
+     require(acc >= 0)
+     l match {
+       case Nil() => acc
+       case Cons(_, xs) => sizeTailRecAcc(xs, acc+1)
+     }
+    } ensuring(res => res == size(l) + acc)
+
+    def sizesAreEquiv(l: List) : Boolean = {
+      size(l) == sizeTailRec(l)
+    } holds
+
+    def content(l: List) : Set[Int] = l match {
+      case Nil() => Set.empty[Int]
+      case Cons(x, xs) => Set(x) ++ content(xs)
+    }
+
+    def sizeAndContent(l: List) : Boolean = {
+      size(l) == 0 || content(l) != Set.empty[Int]
+    } holds
+    
+    def drunk(l : List) : List = (l match {
+      case Nil() => Nil()
+      case Cons(x,l1) => Cons(x,Cons(x,drunk(l1)))
+    }) ensuring (size(_) == 2 * size(l))
+
+    def reverse(l: List) : List = reverse0(l, Nil()) ensuring(content(_) == content(l))
+    def reverse0(l1: List, l2: List) : List = (l1 match {
+      case Nil() => l2
+      case Cons(x, xs) => reverse0(xs, Cons(x, l2))
+    }) ensuring(content(_) == content(l1) ++ content(l2))
+
+    def append(l1 : List, l2 : List) : List = (l1 match {
+      case Nil() => l2
+      case Cons(x,xs) => Cons(x, append(xs, l2))
+    }) ensuring(content(_) == content(l1) ++ content(l2))
+
+    @induct
+    def nilAppend(l : List) : Boolean = (append(l, Nil()) == l) holds
+
+    @induct
+    def appendAssoc(xs : List, ys : List, zs : List) : Boolean =
+      (append(append(xs, ys), zs) == append(xs, append(ys, zs))) holds
+
+    def revAuxBroken(l1 : List, e : Int, l2 : List) : Boolean = {
+      (append(reverse(l1), Cons(e,l2)) == reverse0(l1, l2))
+    } holds
+
+    @induct
+    def sizeAppend(l1 : List, l2 : List) : Boolean =
+      (size(append(l1, l2)) == size(l1) + size(l2)) holds
+
+    @induct
+    def concat(l1: List, l2: List) : List = 
+      concat0(l1, l2, Nil()) ensuring(content(_) == content(l1) ++ content(l2))
+
+    @induct
+    def concat0(l1: List, l2: List, l3: List) : List = (l1 match {
+      case Nil() => l2 match {
+        case Nil() => reverse(l3)
+        case Cons(y, ys) => {
+          concat0(Nil(), ys, Cons(y, l3))
+        }
+      }
+      case Cons(x, xs) => concat0(xs, l2, Cons(x, l3))
+    }) ensuring(content(_) == content(l1) ++ content(l2) ++ content(l3))
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/PropositionalLogic.scala b/src/test/resources/regression/verification/purescala/valid/PropositionalLogic.scala
new file mode 100644
index 0000000000000000000000000000000000000000..a35c3ef9be56871900d5e9474b385f0896edccd4
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/PropositionalLogic.scala
@@ -0,0 +1,86 @@
+import scala.collection.immutable.Set
+import leon.Utils._
+import leon.Annotations._
+
+object PropositionalLogic { 
+
+  sealed abstract class Formula
+  case class And(lhs: Formula, rhs: Formula) extends Formula
+  case class Or(lhs: Formula, rhs: Formula) extends Formula
+  case class Implies(lhs: Formula, rhs: Formula) extends Formula
+  case class Not(f: Formula) extends Formula
+  case class Literal(id: Int) extends Formula
+
+  def simplify(f: Formula): Formula = (f match {
+    case And(lhs, rhs) => And(simplify(lhs), simplify(rhs))
+    case Or(lhs, rhs) => Or(simplify(lhs), simplify(rhs))
+    case Implies(lhs, rhs) => Or(Not(simplify(lhs)), simplify(rhs))
+    case Not(f) => Not(simplify(f))
+    case Literal(_) => f
+  }) ensuring(isSimplified(_))
+
+  def isSimplified(f: Formula): Boolean = f match {
+    case And(lhs, rhs) => isSimplified(lhs) && isSimplified(rhs)
+    case Or(lhs, rhs) => isSimplified(lhs) && isSimplified(rhs)
+    case Implies(_,_) => false
+    case Not(f) => isSimplified(f)
+    case Literal(_) => true
+  }
+
+  def nnf(formula: Formula): Formula = (formula match {
+    case And(lhs, rhs) => And(nnf(lhs), nnf(rhs))
+    case Or(lhs, rhs) => Or(nnf(lhs), nnf(rhs))
+    case Implies(lhs, rhs) => Implies(nnf(lhs), nnf(rhs))
+    case Not(And(lhs, rhs)) => Or(nnf(Not(lhs)), nnf(Not(rhs)))
+    case Not(Or(lhs, rhs)) => And(nnf(Not(lhs)), nnf(Not(rhs)))
+    case Not(Implies(lhs, rhs)) => And(nnf(lhs), nnf(Not(rhs)))
+    case Not(Not(f)) => nnf(f)
+    case Not(Literal(_)) => formula
+    case Literal(_) => formula
+  }) ensuring(isNNF(_))
+
+  def isNNF(f: Formula): Boolean = f match {
+    case And(lhs, rhs) => isNNF(lhs) && isNNF(rhs)
+    case Or(lhs, rhs) => isNNF(lhs) && isNNF(rhs)
+    case Implies(lhs, rhs) => isNNF(lhs) && isNNF(rhs)
+    case Not(Literal(_)) => true
+    case Not(_) => false
+    case Literal(_) => true
+  }
+
+  def vars(f: Formula): Set[Int] = {
+    require(isNNF(f))
+    f match {
+      case And(lhs, rhs) => vars(lhs) ++ vars(rhs)
+      case Or(lhs, rhs) => vars(lhs) ++ vars(rhs)
+      case Implies(lhs, rhs) => vars(lhs) ++ vars(rhs)
+      case Not(Literal(i)) => Set[Int](i)
+      case Literal(i) => Set[Int](i)
+    }
+  }
+
+  def fv(f : Formula) = { vars(nnf(f)) }
+
+  // @induct
+  // def wrongCommutative(f: Formula) : Boolean = {
+  //   nnf(simplify(f)) == simplify(nnf(f))
+  // } holds
+
+  @induct
+  def simplifyBreaksNNF(f: Formula) : Boolean = {
+    require(isNNF(f))
+    isNNF(simplify(f))
+  } holds
+
+  @induct
+  def nnfIsStable(f: Formula) : Boolean = {
+    require(isNNF(f))
+    nnf(f) == f
+  } holds
+  
+  @induct
+  def simplifyIsStable(f: Formula) : Boolean = {
+    require(isSimplified(f))
+    simplify(f) == f
+  } holds
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/README b/src/test/resources/regression/verification/purescala/valid/README
new file mode 100644
index 0000000000000000000000000000000000000000..2bb01d5fdbd6b59970c0c84f2c10db1ead6097a2
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/README
@@ -0,0 +1,2 @@
+This particular directory contains PureScala programs that can be entirely
+proved correct by Leon.
diff --git a/src/test/resources/regression/verification/purescala/valid/RedBlackTree.scala b/src/test/resources/regression/verification/purescala/valid/RedBlackTree.scala
new file mode 100644
index 0000000000000000000000000000000000000000..bc2de6ba96ee699736d4558932b752eea9ebba9f
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/RedBlackTree.scala
@@ -0,0 +1,117 @@
+import scala.collection.immutable.Set
+import leon.Annotations._
+import leon.Utils._
+
+object RedBlackTree { 
+  sealed abstract class Color
+  case class Red() extends Color
+  case class Black() extends Color
+ 
+  sealed abstract class Tree
+  case class Empty() extends Tree
+  case class Node(color: Color, left: Tree, value: Int, right: Tree) extends Tree
+
+  sealed abstract class OptionInt
+  case class Some(v : Int) extends OptionInt
+  case class None() extends OptionInt
+
+  def content(t: Tree) : Set[Int] = t match {
+    case Empty() => Set.empty
+    case Node(_, l, v, r) => content(l) ++ Set(v) ++ content(r)
+  }
+
+  def size(t: Tree) : Int = (t match {
+    case Empty() => 0
+    case Node(_, l, v, r) => size(l) + 1 + size(r)
+  }) ensuring(_ >= 0)
+
+  /* We consider leaves to be black by definition */
+  def isBlack(t: Tree) : Boolean = t match {
+    case Empty() => true
+    case Node(Black(),_,_,_) => true
+    case _ => false
+  }
+
+  def redNodesHaveBlackChildren(t: Tree) : Boolean = t match {
+    case Empty() => true
+    case Node(Black(), l, _, r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r)
+    case Node(Red(), l, _, r) => isBlack(l) && isBlack(r) && redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r)
+  }
+
+  def redDescHaveBlackChildren(t: Tree) : Boolean = t match {
+    case Empty() => true
+    case Node(_,l,_,r) => redNodesHaveBlackChildren(l) && redNodesHaveBlackChildren(r)
+  }
+
+  def blackBalanced(t : Tree) : Boolean = t match {
+    case Node(_,l,_,r) => blackBalanced(l) && blackBalanced(r) && blackHeight(l) == blackHeight(r)
+    case Empty() => true
+  }
+
+  def blackHeight(t : Tree) : Int = t match {
+    case Empty() => 1
+    case Node(Black(), l, _, _) => blackHeight(l) + 1
+    case Node(Red(), l, _, _) => blackHeight(l)
+  }
+
+  // <<insert element x into the tree t>>
+  def ins(x: Int, t: Tree): Tree = {
+    require(redNodesHaveBlackChildren(t) && blackBalanced(t))
+    t match {
+      case Empty() => Node(Red(),Empty(),x,Empty())
+      case Node(c,a,y,b) =>
+        if      (x < y)  balance(c, ins(x, a), y, b)
+        else if (x == y) Node(c,a,y,b)
+        else             balance(c,a,y,ins(x, b))
+    }
+  } ensuring (res => content(res) == content(t) ++ Set(x) 
+                   && size(t) <= size(res) && size(res) <= size(t) + 1
+                   && redDescHaveBlackChildren(res)
+                   && blackBalanced(res))
+
+  def makeBlack(n: Tree): Tree = {
+    require(redDescHaveBlackChildren(n) && blackBalanced(n))
+    n match {
+      case Node(Red(),l,v,r) => Node(Black(),l,v,r)
+      case _ => n
+    }
+  } ensuring(res => redNodesHaveBlackChildren(res) && blackBalanced(res))
+
+  def add(x: Int, t: Tree): Tree = {
+    require(redNodesHaveBlackChildren(t) && blackBalanced(t))
+    makeBlack(ins(x, t))
+  } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res) && blackBalanced(res))
+  
+  def buggyAdd(x: Int, t: Tree): Tree = {
+    require(redNodesHaveBlackChildren(t))
+    ins(x, t)
+  } ensuring (res => content(res) == content(t) ++ Set(x) && redNodesHaveBlackChildren(res))
+  
+  def balance(c: Color, a: Tree, x: Int, b: Tree): Tree = {
+    Node(c,a,x,b) match {
+      case Node(Black(),Node(Red(),Node(Red(),a,xV,b),yV,c),zV,d) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(Black(),Node(Red(),a,xV,Node(Red(),b,yV,c)),zV,d) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(Black(),a,xV,Node(Red(),Node(Red(),b,yV,c),zV,d)) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(Black(),a,xV,Node(Red(),b,yV,Node(Red(),c,zV,d))) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(c,a,xV,b) => Node(c,a,xV,b)
+    }
+  } ensuring (res => content(res) == content(Node(c,a,x,b)))// && redDescHaveBlackChildren(res))
+
+  def buggyBalance(c: Color, a: Tree, x: Int, b: Tree): Tree = {
+    Node(c,a,x,b) match {
+      case Node(Black(),Node(Red(),Node(Red(),a,xV,b),yV,c),zV,d) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(Black(),Node(Red(),a,xV,Node(Red(),b,yV,c)),zV,d) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(Black(),a,xV,Node(Red(),Node(Red(),b,yV,c),zV,d)) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      case Node(Black(),a,xV,Node(Red(),b,yV,Node(Red(),c,zV,d))) => 
+        Node(Red(),Node(Black(),a,xV,b),yV,Node(Black(),c,zV,d))
+      // case Node(c,a,xV,b) => Node(c,a,xV,b)
+    }
+  } ensuring (res => content(res) == content(Node(c,a,x,b)))// && redDescHaveBlackChildren(res))
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/SearchLinkedList.scala b/src/test/resources/regression/verification/purescala/valid/SearchLinkedList.scala
new file mode 100644
index 0000000000000000000000000000000000000000..2c137fd4ad6b9d411f7e14b4ada6b834234c9e9e
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/SearchLinkedList.scala
@@ -0,0 +1,48 @@
+import scala.collection.immutable.Set
+import leon.Utils._
+import leon.Annotations._
+
+object SearchLinkedList {
+  sealed abstract class List
+  case class Cons(head : Int, tail : List) extends List
+  case class Nil() extends List
+
+  def size(list : List) : Int = (list match {
+    case Nil() => 0
+    case Cons(_, xs) => 1 + size(xs)
+  }) ensuring(_ >= 0)
+
+  def contains(list : List, elem : Int) : Boolean = (list match {
+    case Nil() => false
+    case Cons(x, xs) => x == elem || contains(xs, elem)
+  })
+
+  def firstZero(list : List) : Int = (list match {
+    case Nil() => 0
+    case Cons(x, xs) => if (x == 0) 0 else firstZero(xs) + 1
+  }) ensuring (res =>
+    res >= 0 && (if (contains(list, 0)) {
+      firstZeroAtPos(list, res)
+    } else {
+      res == size(list)
+    }))
+
+  def firstZeroAtPos(list : List, pos : Int) : Boolean = {
+    list match {
+      case Nil() => false
+      case Cons(x, xs) => if (pos == 0) x == 0 else x != 0 && firstZeroAtPos(xs, pos - 1)
+    }
+  } 
+
+  def goal(list : List, i : Int) : Boolean = {
+    if(firstZero(list) == i) {
+      if(contains(list, 0)) {
+        firstZeroAtPos(list, i)
+      } else {
+        i == size(list)
+      }
+    } else {
+      true
+    }
+  } holds
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/SumAndMax.scala b/src/test/resources/regression/verification/purescala/valid/SumAndMax.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0aa4ce7060a391d34dd047338fcd1f638054843f
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/SumAndMax.scala
@@ -0,0 +1,46 @@
+import leon.Utils._
+import leon.Annotations._
+
+object SumAndMax {
+  sealed abstract class List
+  case class Cons(head : Int, tail : List) extends List
+  case class Nil() extends List
+
+  def max(list : List) : Int = {
+    require(list != Nil())
+    list match {
+      case Cons(x, Nil()) => x
+      case Cons(x, xs) => {
+        val m2 = max(xs)
+        if(m2 > x) m2 else x
+      }
+    }
+  }
+
+  def sum(list : List) : Int = list match {
+    case Nil() => 0
+    case Cons(x, xs) => x + sum(xs)
+  }
+
+  def size(list : List) : Int = (list match {
+    case Nil() => 0
+    case Cons(_, xs) => 1 + size(xs)
+  }) ensuring(_ >= 0)
+
+  def allPos(list : List) : Boolean = list match {
+    case Nil() => true
+    case Cons(x, xs) => x >= 0 && allPos(xs)
+  }
+
+  def prop0(list : List) : Boolean = {
+    require(list != Nil())
+    !allPos(list) || max(list) >= 0
+  } holds
+
+  @induct
+  def property(list : List) : Boolean = {
+    // This precondition was given in the problem but isn't actually useful :D
+    // require(allPos(list))
+    sum(list) <= size(list) * (if(list == Nil()) 0 else max(list))
+  } holds
+}
diff --git a/src/test/scala/leon/test/Test.scala b/src/test/scala/leon/test/Test.scala
new file mode 100644
index 0000000000000000000000000000000000000000..ed3549395b971f0e12fbdb8a8c7656526fe936e8
--- /dev/null
+++ b/src/test/scala/leon/test/Test.scala
@@ -0,0 +1,9 @@
+package leon.test
+
+import org.scalatest.FunSuite
+
+class Test extends FunSuite {
+  test("Tests work.") {
+    assert(true)
+  }
+}
diff --git a/src/test/scala/leon/test/ValidPrograms.scala b/src/test/scala/leon/test/ValidPrograms.scala
new file mode 100644
index 0000000000000000000000000000000000000000..37df60f224e91b9a23f030b4653ad725db9fad72
--- /dev/null
+++ b/src/test/scala/leon/test/ValidPrograms.scala
@@ -0,0 +1,48 @@
+package leon
+package test
+
+import org.scalatest.FunSuite
+
+import java.io.File
+
+class ValidPrograms extends FunSuite {
+  def runBasicLeonOnFile(filename : String) : Unit = {
+    val file = new File(filename)
+
+    assert(file.exists && file.isFile && file.canRead,
+           "Benchmark [%s] is not a readable file".format(filename))
+
+    val ctx = LeonContext(
+      settings = Settings(
+        synthesis = false,
+        xlang     = false,
+        verify    = true
+      ),
+      files = List(file),
+      reporter = new SilentReporter
+    )
+
+    val pipeline = Main.computePipeline(ctx.settings)
+    pipeline.run(ctx)("--timeout=2" :: file.getPath :: Nil)
+  }
+
+  def mkTest(filename : String) = {
+    test("Valid PureScala program: [%s]".format(filename)) {
+      runBasicLeonOnFile(filename)
+      assert(true)
+    }
+  }
+
+  test("List files") {
+    import scala.collection.JavaConversions._
+
+    val ress = this.getClass.getClassLoader.getResources("/regression/verification/purescala/valid/")
+
+    for(res <- ress) {
+      println(res)
+    }
+  }
+
+  // Sorry for leaving this there...
+  // mkTest("/home/psuter/Test.scala")
+}
diff --git a/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala b/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala
index 1682054408d45c00a7721bd9a113f61fad4706d9..6b015b9afc8fac4a8fbe51828680920b555a2a40 100644
--- a/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala
+++ b/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala
@@ -8,7 +8,7 @@ import leon.purescala.TypeTrees._
 
 import leon.SilentReporter
 
-import leon.Extensions.Solver
+import leon.solvers.Solver
 import leon.solvers.z3.UninterpretedZ3Solver
 
 import org.scalatest.FunSuite