diff --git a/src/main/scala/inox/solvers/smtlib/SMTLIBSolver.scala b/src/main/scala/inox/solvers/smtlib/SMTLIBSolver.scala
index da60b767d133fec5f2387f5272f18775c0dcb643..d6a3acd25ddaeb33891c477eb4ac2e18379dd531 100644
--- a/src/main/scala/inox/solvers/smtlib/SMTLIBSolver.scala
+++ b/src/main/scala/inox/solvers/smtlib/SMTLIBSolver.scala
@@ -8,11 +8,7 @@ import _root_.smtlib.parser.Commands.{Assert => SMTAssert, FunDef => SMTFunDef,
 import _root_.smtlib.parser.Terms.{Identifier => _, _}
 import _root_.smtlib.parser.CommandsResponses.{Error => ErrorResponse, _}
 
-import theories._
-import utils._
-
 trait SMTLIBSolver extends Solver with SMTLIBTarget {
-  val theories: TheoryEncoder { val trees: program.trees.type }
 
   import program._
   import trees._
@@ -24,8 +20,6 @@ trait SMTLIBSolver extends Solver with SMTLIBTarget {
   def targetName: String
   override def name: String = "smt-"+targetName
 
-  private val ids = new IncrementalBijection[Identifier, Identifier]()
-
   override def dbg(msg: => Any) = {
     debugOut foreach { o =>
       o.write(msg.toString)
@@ -34,16 +28,14 @@ trait SMTLIBSolver extends Solver with SMTLIBTarget {
   }
 
   /* Public solver interface */
-  def assertCnstr(raw: Expr): Unit = if (!hasError) {
+  def assertCnstr(expr: Expr): Unit = if (!hasError) {
     try {
-      val bindings = variablesOf(raw).map(v => v -> ids.cachedB(v.id)(theories.encode(v.id))).toMap
-      val expr = theories.encode(raw)(bindings)
       variablesOf(expr).foreach(declareVariable)
 
       val term = toSMT(expr)(Map())
       emit(SMTAssert(term))
     } catch {
-      case _ : SMTLIBUnsupportedError =>
+      case _ : SolverUnsupportedError =>
         // Store that there was an error. Now all following check()
         // invocations will return None
         addError()
@@ -54,64 +46,66 @@ trait SMTLIBSolver extends Solver with SMTLIBTarget {
     emit(Reset(), rawOut = true) match {
       case ErrorResponse(msg) =>
         reporter.warning(s"Failed to reset $name: $msg")
-        throw new Exception() //CantResetException(this)
+        throw new Exception() //CantResetException(this) FIXME
       case _ =>
     }
   }
 
-  override def check[R <: SolverResponse[Map[ValDef, Expr], Set[Expr]]](config: Configuration { type Response = R }): R = {
-    if (hasError) Unknown
-    else emit(CheckSat()) match {
-      case CheckSatStatus(SatStatus)     => Some(true)
-      case CheckSatStatus(UnsatStatus)   => Some(false)
-      case CheckSatStatus(UnknownStatus) => None
-      case e                             => None
-    }
-  }
-
-  protected def getModel(filter: Identifier => Boolean): Model = {
-    val syms = variables.aSet.filter(filter).map(variables.aToB)
-    if (syms.isEmpty) {
-      Model.empty
-    } else {
-      try {
-        emit(GetModel()) match {
-          case GetModelResponseSuccess(smodel) =>
-            // first-pass to gather functions
-            val modelFunDefs = smodel.collect {
-              case me @ DefineFun(SMTFunDef(a, args, _, _)) if args.nonEmpty =>
-                a -> me
-            }.toMap
-
-            val model = smodel.flatMap {
-              case DefineFun(SMTFunDef(s, _, _, e)) if syms(s) =>
-                try {
-                  val id = variables.toA(s)
-                  val value = fromSMT(e, id.getType)(Map(), modelFunDefs)
-                  Some(ids.getAorElse(id, id) -> theories.decode(value)(variablesOf(value).map(id => id -> ids.toA(id)).toMap))
-                } catch {
-                  case _: Unsupported =>
-                    None
-                }
-              case _ => None
-            }.toMap
-
-            new Model(model)
-
-          case _ =>
-            Model.empty // FIXME improve this
-        }
-      } catch {
-        case e : SMTLIBUnsupportedError =>
-          throw new SolverUnsupportedError(e.t, this, e.reason)
+  override def check(config: Configuration): config.Response[Model, Cores] = config.cast {
+    if (hasError) Unknown else {
+      emit(CheckSat()) match {
+        case CheckSatStatus(SatStatus)     =>
+          config match {
+            case All | Model =>
+              val syms = variables.aSet.map(variables.aToB)
+              emit(GetModel()) match {
+                case GetModelResponseSuccess(smodel) =>
+                  // first-pass to gather functions
+                  val modelFunDefs = smodel.collect {
+                    case me @ DefineFun(SMTFunDef(a, args, _, _)) if args.nonEmpty =>
+                      a -> me
+                  }.toMap
+
+                  val model = smodel.flatMap {
+                    case DefineFun(SMTFunDef(s, _, _, e)) if syms(s) =>
+                      try {
+                        val v = variables.toA(s)
+                        val value = fromSMT(e, v.getType)(Map(), modelFunDefs)
+                        Some(v.toVal -> value)
+                      } catch {
+                        case _: Unsupported =>
+                          None
+                      }
+                    case _ => None
+                  }.toMap
+
+                  SatWithModel(model)
+
+                case _ =>
+                  Unknown
+              }
+            case _ =>
+              Sat
+          }
+        case CheckSatStatus(UnsatStatus) =>
+          config match {
+            case All | Cores =>
+              emit(GetUnsatCore()) match {
+                case GetUnsatCoreResponseSuccess(syms) =>
+                  UnsatWithCores(Set.empty) // FIXME
+                case _ =>
+                  UnsatWithCores(Set.empty)
+              }
+            case _ =>
+              Unsat
+          }
+        case CheckSatStatus(UnknownStatus) => Unknown
+        case e                             => Unknown
       }
     }
   }
 
-  override def getModel: Model = getModel(_ => true)
-
-  override def push(): Unit = {
-    ids.push()
+  def push(): Unit = {
     constructors.push()
     selectors.push()
     testers.push()
@@ -124,8 +118,7 @@ trait SMTLIBSolver extends Solver with SMTLIBTarget {
     emit(Push(1))
   }
 
-  override def pop(): Unit = {
-    ids.pop()
+  def pop(): Unit = {
     constructors.pop()
     selectors.pop()
     testers.pop()
diff --git a/src/main/scala/inox/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/inox/solvers/smtlib/SMTLIBTarget.scala
index a7f84c0867e671cf9e0a5ae8cd44bc03170ad9fc..e3473a3b38e0207966a8457c9ce79341aa45b87e 100644
--- a/src/main/scala/inox/solvers/smtlib/SMTLIBTarget.scala
+++ b/src/main/scala/inox/solvers/smtlib/SMTLIBTarget.scala
@@ -142,7 +142,7 @@ trait SMTLIBTarget extends Interruptible with ADTManagers {
   protected val constructors  = new IncrementalBijection[Type, SSymbol]()
   protected val selectors     = new IncrementalBijection[(Type, Int), SSymbol]()
   protected val testers       = new IncrementalBijection[Type, SSymbol]()
-  protected val variables     = new IncrementalBijection[Identifier, SSymbol]()
+  protected val variables     = new IncrementalBijection[Variable, SSymbol]()
   protected val sorts         = new IncrementalBijection[Type, Sort]()
   protected val functions     = new IncrementalBijection[TypedFunDef, SSymbol]()
   protected val lambdas       = new IncrementalBijection[FunctionType, SSymbol]()
@@ -251,11 +251,10 @@ trait SMTLIBTarget extends Interruptible with ADTManagers {
     }
   }
 
-  protected def declareVariable(vd: ValDef): SSymbol = declareVariable(vd.id, vd.getType)
-  protected def declareVariable(id: Identifier, tp: Type) = {
-    variables.cachedB(id) {
-      val s = id2sym(id)
-      val cmd = DeclareFun(s, List(), declareSort(tp))
+  protected def declareVariable(v: Variable): SSymbol = {
+    variables.cachedB(v) {
+      val s = id2sym(v.id)
+      val cmd = DeclareFun(s, List(), declareSort(v.getType))
       emit(cmd)
       s
     }
@@ -309,13 +308,13 @@ trait SMTLIBTarget extends Interruptible with ADTManagers {
 
   protected def toSMT(e: Expr)(implicit bindings: Map[Identifier, Term]): Term = {
     e match {
-      case Variable(id, tp) =>
-        declareSort(e.getType)
-        bindings.getOrElse(id, variables.toB(id))
+      case v@Variable(id, tp) =>
+        declareSort(tp)
+        bindings.getOrElse(id, variables.toB(v))
 
       case UnitLiteral() =>
         declareSort(UnitType)
-        declareVariable(FreshIdentifier("Unit"), UnitType)
+        declareVariable(Variable(FreshIdentifier("Unit"), UnitType))
 
       case IntegerLiteral(i)     => if (i >= 0) Ints.NumeralLit(i) else Ints.Neg(Ints.NumeralLit(-i))
       case IntLiteral(i)         => FixedSizeBitVectors.BitVectorLit(Hexadecimal.fromInt(i))
@@ -772,7 +771,7 @@ trait SMTLIBTarget extends Interruptible with ADTManagers {
         fromSMT(lets(s), otpe)
 
       case (SimpleSymbol(s), otpe) =>
-        variables.getA(s).map(Variable(_, otpe.get)).getOrElse {
+        variables.getA(s).getOrElse {
           ctx.reporter.fatalError("Could not find variable from SMT")
         }