diff --git a/src/main/scala/inox/evaluators/SolvingEvaluator.scala b/src/main/scala/inox/evaluators/SolvingEvaluator.scala
index 3d8e64fe51feb5ce98f5eac98747fbc798c4bc9b..eb791cf360165c818cd31be39f7d46bbdc042b8f 100644
--- a/src/main/scala/inox/evaluators/SolvingEvaluator.scala
+++ b/src/main/scala/inox/evaluators/SolvingEvaluator.scala
@@ -33,14 +33,14 @@ trait SolvingEvaluator extends Evaluator {
       case o @ InoxOption(opt, _) if opt == optForallCache => o
     }.toSeq : _*)
 
-    import solver.SolverResponses._
+    import SolverResponses._
 
     solver.assertCnstr(body)
-    val res = solver.check(model = true)
+    val res = solver.check(solver.Model)
     timer.stop()
 
     res match {
-      case Model(model) =>
+      case SatWithModel(model) =>
         valuateWithModel(model)(vd)
 
       case _ =>
@@ -62,18 +62,18 @@ trait SolvingEvaluator extends Evaluator {
         InoxOption(optForallCache)(cache)
       )
 
-      import solver.SolverResponses._
+      import SolverResponses._
 
       solver.assertCnstr(Not(forall.body))
-      val res = solver.check(model = true)
+      val res = solver.check(solver.Model)
       timer.stop()
 
       res match {
-        case Unsat() =>
+        case Unsat =>
           cache(forall) = true
           true
 
-        case Model(model) =>
+        case SatWithModel(model) =>
           cache(forall) = false
           eval(Not(forall.body), model) match {
             case EvaluationResults.Successful(BooleanLiteral(true)) => false
diff --git a/src/main/scala/inox/solvers/SimpleSolverAPI.scala b/src/main/scala/inox/solvers/SimpleSolverAPI.scala
index 8f7c4b404cd9cec770800ad93d708cd844b1d71a..deb96092b6c93f01291fd4a04de4032aceb3c479 100644
--- a/src/main/scala/inox/solvers/SimpleSolverAPI.scala
+++ b/src/main/scala/inox/solvers/SimpleSolverAPI.scala
@@ -1,58 +1,54 @@
 /* Copyright 2009-2016 EPFL, Lausanne */
 
-package leon
+package inox
 package solvers
 
-import purescala.Expressions._
+trait SimpleSolverAPI {
+  protected val factory: SolverFactory
+
+  import factory.program.trees._
+  import SolverResponses._
 
-class SimpleSolverAPI(sf: SolverFactory[Solver]) {
   def solveVALID(expression: Expr): Option[Boolean] = {
-    val s = sf.getNewSolver()
+    val s = factory.getNewSolver()
+    import s._
     try {
       s.assertCnstr(Not(expression))
-      s.check.map(r => !r)
+      s.check(Simple) match {
+        case Check(r) => Some(!r)
+        case _ => None
+      }
     } finally {
-      sf.reclaim(s)
+      factory.reclaim(s)
     }
   }
 
-  def solveSAT(expression: Expr): (Option[Boolean], Model) = {
-    val s = sf.getNewSolver()
+  def solveSAT(expression: Expr): ResponseWithModel[Map[ValDef, Expr]] = {
+    val s = factory.getNewSolver()
+    import s._
     try {
       s.assertCnstr(expression)
-      s.check match {
-        case Some(true) =>
-          (Some(true), s.getModel)
-        case Some(false) =>
-          (Some(false), Model.empty)
-        case None =>
-          (None, Model.empty)
-      }
+      s.check(Model)
     } finally {
-      sf.reclaim(s)
+      factory.reclaim(s)
     }
   }
 
-  def solveSATWithCores(expression: Expr, assumptions: Set[Expr]): Option[Either[Set[Expr], Model]] = {
-    val s = sf.getNewSolver()
+  def solveSATWithCores(expression: Expr, assumptions: Set[Expr]):
+                        ResponseWithModelAndCores[Map[ValDef, Expr], Set[Expr]] = {
+    val s = factory.getNewSolver()
+    import s._
     try {
       s.assertCnstr(expression)
-      s.checkAssumptions(assumptions) match {
-        case Some(false) =>
-          Some(Left(s.getUnsatCore))
-        case Some(true) =>
-          Some(Right(s.getModel))
-        case None =>
-          None
-      }
+      s.checkAssumptions(All)(assumptions)
     } finally {
-      sf.reclaim(s)
+      factory.reclaim(s)
     }
   }
 }
 
 object SimpleSolverAPI {
-  def apply(sf: SolverFactory[Solver]) = {
-    new SimpleSolverAPI(sf)
+  def apply(sf: SolverFactory) = new SimpleSolverAPI {
+    val factory: sf.type = sf
   }
 }
diff --git a/src/main/scala/inox/solvers/Solver.scala b/src/main/scala/inox/solvers/Solver.scala
index d4bf0d11b1febdeaf6a7c66cfb1423b3bf0f283d..a353f24596fc5042113775daeedcc043fa9c0a6c 100644
--- a/src/main/scala/inox/solvers/Solver.scala
+++ b/src/main/scala/inox/solvers/Solver.scala
@@ -29,60 +29,62 @@ trait Solver extends Interruptible {
   import program._
   import program.trees._
 
-  object SolverResponses {
-    sealed trait SolverResponse
-    case object Unknown extends SolverResponse
-
-    sealed trait SolverUnsatResponse extends SolverResponse
-    case object UnsatResponse extends SolverUnsatResponse
-    case class UnsatResponseWithCores(cores: Set[Expr]) extends SolverUnsatResponse
-
-    sealed trait SolverSatResponse extends SolverResponse
-    case object SatResponse extends SolverSatResponse
-    case class SatResponseWithModel(model: Map[ValDef, Expr]) extends SolverSatResponse
-
-    object Check {
-      def unapply(resp: SolverResponse): Option[Boolean] = resp match {
-        case _: SolverUnsatResponse => Some(false)
-        case _: SolverSatResponse   => Some(true)
-        case Unknown => None
-      }
-    }
+  import SolverResponses._
 
-    object Sat {
-      def unapply(resp: SolverSatResponse): Boolean = resp match {
-        case SatResponse => true
-        case SatResponseWithModel(_) => throw FatalError("Unexpected sat response with model")
-        case _ => false
-      }
+  sealed trait Configuration {
+    type Response <: SolverResponse[Map[ValDef, Expr], Set[Expr]]
+
+    def max(that: Configuration): Configuration = (this, that) match {
+      case (All  , _    ) => All
+      case (_    , All  ) => All
+      case (Model, Cores) => All
+      case (Cores, Model) => All
+      case (Model, _    ) => Model
+      case (_    , Model) => Model
+      case (Cores, _    ) => Cores
+      case (_    , Cores) => Cores
+      case _              => Simple
     }
 
-    object Model {
-      def unapply(resp: SolverSatResponse): Option[Map[ValDef, Expr]] = resp match {
-        case SatResponseWithModel(model) => Some(model)
-        case SatResponse => throw FatalError("Unexpected sat response without model")
-        case _ => None
-      }
+    def min(that: Configuration): Configuration = (this, that) match {
+      case (o1, o2) if o1 == o2 => o1
+      case (Simple, _) => Simple
+      case (_, Simple) => Simple
+      case (Model, Cores) => Simple
+      case (Cores, Model) => Simple
+      case (All, o) => o
+      case (o, All) => o
     }
 
-    object Unsat {
-      def unapply(resp: SolverUnsatResponse): Boolean = resp match {
-        case UnsatResponse => true
-        case UnsatResponseWithCores(_) => throw FatalError("Unexpected unsat response with cores")
-        case _ => false
-      }
+    def in(solver: Solver): solver.Configuration = this match {
+      case Simple => solver.Simple
+      case Model => solver.Model
+      case Cores => solver.Cores
+      case All => solver.All
     }
 
-    object Core {
-      def unapply(resp: SolverUnsatResponse): Option[Set[Expr]] = resp match {
-        case UnsatResponseWithCores(cores) => Some(cores)
-        case UnsatResponse => throw FatalError("Unexpected unsat response with cores")
-        case _ => None
-      }
-    }
+    def cast(resp: SolverResponse[Map[ValDef, Expr], Set[Expr]]): Response = ((this, resp) match {
+      case (_             , Unknown)               => Unknown
+      case (Simple | Cores, Sat)                   => Sat
+      case (Model  | All  , s @ SatWithModel(_))   => s
+      case (Simple | Model, Unsat)                 => Unsat
+      case (Cores  | All  , u @ UnsatWithCores(_)) => u
+      case _ => throw FatalError("Unexpected response " + resp + " for configuration " + this)
+    }).asInstanceOf[Response]
   }
 
-  import SolverResponses._
+  object Configuration {
+    def apply(model: Boolean = false, cores: Boolean = false): Configuration =
+      if (model && cores) All
+      else if (model) Model
+      else if (cores) Cores
+      else Simple
+  }
+
+  case object Simple extends Configuration { type Response = SimpleResponse }
+  case object Model  extends Configuration { type Response = ResponseWithModel[Map[ValDef, Expr]] }
+  case object Cores  extends Configuration { type Response = ResponseWithCores[Set[Expr]] }
+  case object All    extends Configuration { type Response = ResponseWithModelAndCores[Map[ValDef, Expr], Set[Expr]] }
 
   object SolverUnsupportedError {
     def msg(t: Tree, reason: Option[String]) = {
@@ -100,9 +102,9 @@ trait Solver extends Interruptible {
 
   def assertCnstr(expression: Expr): Unit
 
-  def check(model: Boolean = false, cores: Boolean = false): SolverResponse
-  def checkAssumptions(model: Boolean = false, cores: Boolean = false)(assumptions: Set[Expr]): SolverResponse
-  
+  def check[R](config: Configuration { type Response <: R }): R
+  def checkAssumptions[R](config: Configuration { type Response <: R })(assumptions: Set[Expr]): R
+
   def getResultSolver: Option[Solver] = Some(this)
 
   def free()
diff --git a/src/main/scala/inox/solvers/SolverFactory.scala b/src/main/scala/inox/solvers/SolverFactory.scala
index 6409e544cef3ba3545fc8dbfbbf671d4cdf9516e..c82a9b0d4dc4c351373e7611ab8bf51ac1ee7abf 100644
--- a/src/main/scala/inox/solvers/SolverFactory.scala
+++ b/src/main/scala/inox/solvers/SolverFactory.scala
@@ -5,7 +5,13 @@ package solvers
 
 import scala.reflect.runtime.universe._
 
-abstract class SolverFactory[+S <: Solver] {
+trait SolverFactory {
+  val program: Program
+
+  type S <: Solver { val program: SolverFactory.this.program.type }
+
+  val name: String
+
   def getNewSolver(): S
 
   def shutdown(): Unit = {}
@@ -13,13 +19,15 @@ abstract class SolverFactory[+S <: Solver] {
   def reclaim(s: Solver) {
     s.free()
   }
-
-  val name: String
 }
 
 object SolverFactory {
-  def apply[S <: Solver : TypeTag](nme: String, builder: () => S): SolverFactory[S] = {
-    new SolverFactory[S] {
+  def apply[S1 <: Solver : TypeTag](p: Program)(nme: String, builder: () => S1 { val program: p.type }):
+           SolverFactory { val program: p.type; type S = S1 { val program: p.type } } = {
+    new SolverFactory {
+      val program: p.type = p
+      type S = S1 { val program: p.type }
+
       val name = nme
       def getNewSolver() = builder()
     }
diff --git a/src/main/scala/inox/solvers/SolverResponses.scala b/src/main/scala/inox/solvers/SolverResponses.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0f5f7f87faa89e8d12aa75db8b30b776fcede277
--- /dev/null
+++ b/src/main/scala/inox/solvers/SolverResponses.scala
@@ -0,0 +1,46 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+package inox
+package solvers
+
+object SolverResponses {
+  sealed trait SolverResponse[+Model,+Cores]
+
+  sealed trait Satisfiable
+  sealed trait Unsatisfiable
+
+  sealed trait SimpleResponse extends SolverResponse[Nothing, Nothing]
+  sealed trait ResponseWithModel[+Model] extends SolverResponse[Model, Nothing]
+  sealed trait ResponseWithCores[+Cores] extends SolverResponse[Nothing, Cores]
+  sealed trait ResponseWithModelAndCores[+Model,+Cores] extends SolverResponse[Model, Cores]
+
+  case object Sat extends Satisfiable
+    with SimpleResponse
+    with ResponseWithCores[Nothing]
+
+  case object Unsat extends Unsatisfiable
+    with SimpleResponse
+    with ResponseWithModel[Nothing]
+
+  case class SatWithModel[Model](model: Model) extends Satisfiable
+    with ResponseWithModel[Model]
+    with ResponseWithModelAndCores[Model, Nothing]
+
+  case class UnsatWithCores[Cores](cores: Cores) extends Unsatisfiable
+    with ResponseWithCores[Cores]
+    with ResponseWithModelAndCores[Nothing, Cores]
+
+  case object Unknown extends SimpleResponse
+    with ResponseWithModel[Nothing]
+    with ResponseWithCores[Nothing]
+    with ResponseWithModelAndCores[Nothing, Nothing]
+
+  object Check {
+    def unapply[Core,Model](resp: SolverResponse[Core,Model]): Option[Boolean] = resp match {
+      case _: Satisfiable   => Some(true)
+      case _: Unsatisfiable => Some(false)
+      case Unknown => None
+    }
+  }
+}
+
diff --git a/src/main/scala/inox/solvers/unrolling/UnrollingSolver.scala b/src/main/scala/inox/solvers/unrolling/UnrollingSolver.scala
index adfdf3a9ff838bb3fcbaec4316498e0aeb766738..2b3f4079438ae65ca5369418db0836205cd9f890 100644
--- a/src/main/scala/inox/solvers/unrolling/UnrollingSolver.scala
+++ b/src/main/scala/inox/solvers/unrolling/UnrollingSolver.scala
@@ -42,8 +42,8 @@ trait AbstractUnrollingSolver
   val assumePreHolds   = options.findOptionOrDefault(optAssumePre)
   val silentErrors     = options.findOptionOrDefault(optSilentErrors)
 
-  def check(model: Boolean = false, cores: Boolean = false): SolverResponses.SolverResponse =
-    checkAssumptions(model = model, cores = cores)(Set.empty)
+  def check[R](config: Configuration { type Response <: R }): R =
+    checkAssumptions(config)(Set.empty)
 
   private val constraints = new IncrementalSeq[Expr]()
   private val freeVars    = new IncrementalMap[Variable, Encoded]()
@@ -124,15 +124,17 @@ trait AbstractUnrollingSolver
    *  This sequence of calls can also be used to mimic solver.checkAssumptions()
    *  for solvers that don't support the construct natively.
    */
-  def solverCheck[R](clauses: Seq[Encoded], model: Boolean = false, cores: Boolean = false)
+  def solverCheck[R](config: Configuration)
+                    (clauses: Seq[Encoded])
                     (block: Response => R): R
 
   /** We define solverCheckAssumptions in CPS in order for solvers that don't
    *  support this feature to be able to use the provided [[solverCheck]] CPS
    *  construction.
    */
-  def solverCheckAssumptions[R](assumptions: Seq[Encoded], model: Boolean = false, cores: Boolean = false)
-                               (block: Response => R): R = solverCheck(assumptions)(block)
+  def solverCheckAssumptions[R](config: Configuration)
+                               (assumptions: Seq[Encoded])
+                               (block: Response => R): R = solverCheck(config)(assumptions)(block)
 
   trait ModelWrapper {
     def modelEval(elem: Encoded, tpe: Type): Option[Expr]
@@ -284,7 +286,7 @@ trait AbstractUnrollingSolver
     }
   }
 
-  def checkAssumptions(model: Boolean = false, cores: Boolean = false)(assumptions: Set[Expr]) = {
+  def checkAssumptions[R](config: Configuration { type Response <: R })(assumptions: Set[Expr]): R = {
 
     val assumptionsSeq       : Seq[Expr]          = assumptions.toSeq
     val encodedAssumptions   : Seq[Encoded]       = assumptionsSeq.map { expr =>
@@ -302,7 +304,7 @@ trait AbstractUnrollingSolver
     }
 
     sealed abstract class CheckState
-    class CheckResult(val response: SolverResponses.SolverResponse) extends CheckState
+    class CheckResult(val response: config.Response) extends CheckState
     case class Validate(model: Option[Map[ValDef, Expr]]) extends CheckState
     case object ModelCheck extends CheckState
     case object FiniteRangeCheck extends CheckState
@@ -311,15 +313,18 @@ trait AbstractUnrollingSolver
     case object Unroll extends CheckState
 
     object CheckResult {
-      def apply(resp: SolverResponses.SolverResponse) = new CheckResult(resp)
-      def apply(resp: Response): CheckResult = new CheckResult(resp match {
-        case Unknown           => SolverResponses.Unknown
-        case Sat(None)         => SolverResponses.SatResponse
-        case Sat(Some(model))  => SolverResponses.SatResponseWithModel(extractSimpleModel(model))
-        case Unsat(None)       => SolverResponses.UnsatResponse
-        case Unsat(Some(core)) => SolverResponses.UnsatResponseWithCores(encodedCoreToCore(core))
-      })
-      def unapply(res: CheckResult): Option[SolverResponses.SolverResponse] = Some(res.response)
+      def apply(resp: config.Response) = new CheckResult(resp)
+
+      def apply(resp: Response): CheckResult = new CheckResult(config.cast(resp match {
+        case Unknown            => SolverResponses.Unknown
+        case Sat(None)          => SolverResponses.Sat
+        case Sat(Some(model))   => SolverResponses.SatWithModel(extractSimpleModel(model))
+        case Unsat(None)        => SolverResponses.Unsat
+        case Unsat(Some(cores)) => SolverResponses.UnsatWithCores(encodedCoreToCore(cores))
+        case _ => throw FatalError("Unexpected response " + resp + " for configuration " + config)
+      }))
+
+      def unapply(res: CheckResult): Option[config.Response] = Some(res.response)
     }
 
     object Abort {
@@ -335,14 +340,13 @@ trait AbstractUnrollingSolver
         case ModelCheck =>
           reporter.debug(" - Running search...")
 
-          val withModel = model && !templates.requiresFiniteRangeCheck
-          val withCores = cores || unrollUnsatCores
+          val checkConfig = config
+            .min(Configuration(model = !templates.requiresFiniteRangeCheck, cores = true))
+            .max(Configuration(model = false, cores = unrollUnsatCores))
 
           val timer = ctx.timers.solvers.check.start()
-          solverCheckAssumptions(
-            encodedAssumptions.toSeq ++ templates.satisfactionAssumptions,
-            model = withModel,
-            cores = withCores
+          solverCheckAssumptions(checkConfig)(
+            encodedAssumptions.toSeq ++ templates.satisfactionAssumptions
           ) { res =>
             timer.stop()
 
@@ -379,9 +383,8 @@ trait AbstractUnrollingSolver
 
           val clauses = templates.getFiniteRangeClauses
           val timer = ctx.timers.solvers.check.start()
-          solverCheck(
-            encodedAssumptions.toSeq ++ templates.satisfactionAssumptions ++ clauses,
-            model = model
+          solverCheck(config min Model)(
+            encodedAssumptions.toSeq ++ templates.satisfactionAssumptions ++ clauses
           ) { res =>
             timer.stop()
 
@@ -400,11 +403,11 @@ trait AbstractUnrollingSolver
           }
 
         case Validate(optModel) => optModel match {
-          case None => CheckResult(SolverResponses.SatResponse)
+          case None => CheckResult(config cast SolverResponses.Sat)
           case Some(model) =>
             val valid = !checkModels || validateModel(model, assumptionsSeq, silenceErrors = silentErrors)
             if (valid) {
-              CheckResult(SolverResponses.SatResponseWithModel(model))
+              CheckResult(config cast SolverResponses.SatWithModel(model))
             } else {
               reporter.error(
                 "Something went wrong. The model should have been valid, yet we got this: " +
@@ -431,10 +434,8 @@ trait AbstractUnrollingSolver
           }
 
           val timer = ctx.timers.solvers.check.start()
-          solverCheckAssumptions(
-            encodedAssumptions.toSeq ++ templates.refutationAssumptions,
-            model = feelingLucky,
-            cores = cores
+          solverCheckAssumptions(config max Configuration(model = feelingLucky))(
+            encodedAssumptions.toSeq ++ templates.refutationAssumptions
           ) { res =>
             timer.stop()
 
@@ -532,20 +533,21 @@ trait UnrollingSolver extends AbstractUnrollingSolver {
     solver.assertCnstr(cnstr)
   }
 
-  case class Model(model: Map[ValDef, Expr]) extends ModelWrapper {
+  case class ModelWrapper(model: Map[ValDef, Expr]) extends super.ModelWrapper {
     def modelEval(elem: Expr, tpe: Type): Option[Expr] = evaluator.eval(elem, model).result
     override def toString = model.mkString("\n")
   }
 
-  def solverCheck[R](clauses: Seq[Expr], model: Boolean = false, cores: Boolean = false)(block: Response => R): R = {
+  def solverCheck[R](config: Configuration)(clauses: Seq[Expr])(block: Response => R): R = {
     solver.push()
     for (cls <- clauses) solver.assertCnstr(cls)
-    val res = solver.check(model = model, cores = cores) match {
-      case solver.SolverResponses.Unknown                       => Unknown
-      case solver.SolverResponses.UnsatResponse                 => Unsat(None)
-      case solver.SolverResponses.UnsatResponseWithCores(cores) => Unsat(Some(cores))
-      case solver.SolverResponses.SatResponse                   => Sat(None)
-      case solver.SolverResponses.SatResponseWithModel(model)   => Sat(Some(Model(model)))
+    import SolverResponses.{SolverResponse => SR}
+    val res = solver.check[SR[Map[ValDef, Expr], Set[Expr]]](config in solver) match {
+      case SolverResponses.Unknown               => Unknown
+      case SolverResponses.Unsat                 => Unsat(None)
+      case SolverResponses.UnsatWithCores(cores) => Unsat(Some(cores))
+      case SolverResponses.Sat                   => Sat(None)
+      case SolverResponses.SatWithModel(model)   => Sat(Some(ModelWrapper(model)))
     }
     val r = block(res)
     solver.pop()