diff --git a/project/Build.scala b/project/Build.scala
index 4f6b4ddd0f3857eb0101cc26165d0bbe4d4f4b22..cad27e6d3252ec65ecf6c974791ac5d8818ddc4c 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -79,7 +79,7 @@ object Leon extends Build {
   object Github {
     lazy val bonsai = RootProject(uri("git://github.com/colder/bonsai.git#8f485605785bda98ac61885b0c8036133783290a"))
 
-    private val scalaSmtLibVersion = "90f66cf07aef34b05dc5585bb35aca773b3d0d43"
+    private val scalaSmtLibVersion = "4cc4cb1ce38fe62790b674666ab141d0430b0f00"
     lazy val scalaSmtLib = RootProject(uri("git://github.com/regb/scala-smtlib.git#%s".format(scalaSmtLibVersion)))
   }
 }
diff --git a/src/main/scala/leon/purescala/Trees.scala b/src/main/scala/leon/purescala/Trees.scala
index c70d835e5e59fa5ebcf9733b097da20457ade32d..7f5d5f4c64966890842fb5c57699e34c7dff358f 100644
--- a/src/main/scala/leon/purescala/Trees.scala
+++ b/src/main/scala/leon/purescala/Trees.scala
@@ -576,10 +576,12 @@ object Trees {
   }
 
   /* Array operations */
+  @deprecated("Unsupported Array operation with most solvers", "Leon 2.3")
   case class ArrayFill(length: Expr, defaultValue: Expr) extends Expr with FixedType {
     val fixedType = ArrayType(defaultValue.getType)
   }
 
+  @deprecated("Unsupported Array operation with most solvers", "Leon 2.3")
   case class ArrayMake(defaultValue: Expr) extends Expr with FixedType {
     val fixedType = ArrayType(defaultValue.getType)
   }
@@ -613,6 +615,8 @@ object Trees {
     val fixedType = Int32Type
   }
   case class FiniteArray(exprs: Seq[Expr]) extends Expr
+
+  @deprecated("Unsupported Array operation with most solvers", "Leon 2.3")
   case class ArrayClone(array: Expr) extends Expr {
     if(array.getType != Untyped)
       setType(array.getType)
diff --git a/src/main/scala/leon/purescala/TypeTrees.scala b/src/main/scala/leon/purescala/TypeTrees.scala
index a4b86d0722c0ec44ea51a041fed524b2e19bd42e..eb6908420247e0fb0c09efbb862711293423982d 100644
--- a/src/main/scala/leon/purescala/TypeTrees.scala
+++ b/src/main/scala/leon/purescala/TypeTrees.scala
@@ -49,7 +49,7 @@ object TypeTrees {
   }
     
 
-  sealed abstract class TypeTree extends Tree
+  abstract class TypeTree extends Tree
 
   case object Untyped extends TypeTree
   case object BooleanType extends TypeTree
diff --git a/src/main/scala/leon/solvers/SolverFactory.scala b/src/main/scala/leon/solvers/SolverFactory.scala
index ce5bb8c8907dbb233d5ecb93714b510512bbe2b2..7827dfd693859ce555ebb4fd223b154652775f3e 100644
--- a/src/main/scala/leon/solvers/SolverFactory.scala
+++ b/src/main/scala/leon/solvers/SolverFactory.scala
@@ -34,10 +34,10 @@ object SolverFactory {
         SolverFactory(() => new EnumerationSolver(ctx, program) with TimeoutSolver)
 
       case "smt" | "smt-z3" =>
-        SolverFactory(() => new UnrollingSolver(ctx, new SMTLIBSolver(ctx, program) with SMTLIBZ3Target) with TimeoutSolver)
+        SolverFactory(() => new UnrollingSolver(ctx, program, new SMTLIBSolver(ctx, program) with SMTLIBZ3Target) with TimeoutSolver)
 
       case "smt-cvc4" =>
-        SolverFactory(() => new UnrollingSolver(ctx, new SMTLIBSolver(ctx, program) with SMTLIBCVC4Target) with TimeoutSolver)
+        SolverFactory(() => new UnrollingSolver(ctx, program, new SMTLIBSolver(ctx, program) with SMTLIBCVC4Target) with TimeoutSolver)
 
       case _ =>
         ctx.reporter.fatalError("Unknown solver "+name)
diff --git a/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala b/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala
index 99dc09f0048f3d46773718d256d5b064d8517baa..96450da434f8e1e23029bf48a0a7cbcd9e2d66f2 100644
--- a/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala
+++ b/src/main/scala/leon/solvers/combinators/UnrollingSolver.scala
@@ -12,23 +12,42 @@ import purescala.TypeTrees._
 
 import solvers.templates._
 import utils.Interruptible
+import evaluators._
 
-import scala.collection.mutable.{Map=>MutableMap}
+class UnrollingSolver(val context: LeonContext, program: Program, underlying: IncrementalSolver) extends Solver with Interruptible {
 
-class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
-        extends Solver with Interruptible {
+  val (feelingLucky, useCodeGen) = locally {
+    var lucky            = false
+    var codegen          = false
 
-  private var lastCheckResult: (Boolean, Option[Boolean], Option[Map[Identifier,Expr]]) = (false, None, None)
+    for(opt <- context.options) opt match {
+      case LeonFlagOption("feelinglucky", v)       => lucky   = v
+      case LeonFlagOption("codegen", v)            => codegen = v
+      case _ =>
+    }
 
-  val reporter = context.reporter
+    (lucky, codegen)
+  }
 
+  private val evaluator : Evaluator = {
+    if(useCodeGen) {
+      new CodeGenEvaluator(context, program)
+    } else {
+      new DefaultEvaluator(context, program)
+    }
+  }
+
+  private var lastCheckResult: (Boolean, Option[Boolean], Option[Map[Identifier,Expr]]) = (false, None, None)
+  private var varsInVC       = List[Set[Identifier]](Set())
+  private var constraints    = List[List[Expr]](Nil)
   private var interrupted: Boolean = false
 
+  val reporter = context.reporter
+
   def name = "U:"+underlying.name
 
   def free {}
 
-  var varsInVC    = List[Set[Identifier]](Set())
 
   val templateGenerator = new TemplateGenerator(new TemplateEncoder[Expr] {
     def encodeId(id: Identifier): Expr= {
@@ -65,6 +84,7 @@ class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
     }
 
     varsInVC    = (varsInVC.head ++ freeIds) :: varsInVC.tail
+    constraints = (constraints.head ++ newClauses) :: constraints.tail
   }
 
 
@@ -72,12 +92,14 @@ class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
     unrollingBank.push()
     solver.push()
     varsInVC = Set[Identifier]() :: varsInVC
+    constraints = Nil :: constraints
   }
 
   def pop(lvl: Int = 1) {
     unrollingBank.pop(lvl)
     solver.pop(lvl)
     varsInVC = varsInVC.drop(lvl)
+    constraints = constraints.drop(lvl)
   }
 
   def check: Option[Boolean] = {
@@ -90,6 +112,36 @@ class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
     lastCheckResult = (true, res, model)
   }
 
+  def isValidModel(model: Map[Identifier, Expr], silenceErrors: Boolean = false): Boolean = {
+    import EvaluationResults._
+
+    val expr = And(constraints.flatten)
+
+    val fullModel = variablesOf(expr).map(v => v -> model.getOrElse(v, simplestValue(v.getType))).toMap
+
+    evaluator.eval(expr, fullModel) match {
+      case Successful(BooleanLiteral(true)) =>
+        reporter.debug("- Model validated.")
+        true
+
+      case Successful(BooleanLiteral(false)) =>
+        reporter.debug("- Invalid model.")
+        false
+
+      case RuntimeError(msg) =>
+        reporter.debug("- Model leads to runtime error.")
+        false
+
+      case EvaluatorError(msg) => 
+        if (silenceErrors) {
+          reporter.debug("- Model leads to evaluator error: " + msg)
+        } else {
+          reporter.warning("- Model leads to evaluator error: " + msg)
+        }
+        false
+    }
+  }
+
   def genericCheck(assumptions: Set[Expr]): Option[Boolean] = {
     lastCheckResult = (false, None, None)
 
@@ -99,12 +151,13 @@ class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
       solver.push()
       solver.assertCnstr(And((assumptions ++ unrollingBank.currentBlockers).toSeq))
       val res = solver.check
-      solver.pop()
 
       reporter.debug(" - Finished search with blocked literals")
 
       res match {
         case None =>
+          solver.pop()
+
           reporter.ifDebug { debug =>
             reporter.debug("Solver returned unknown!?")
           }
@@ -112,23 +165,29 @@ class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
 
         case Some(true) => // SAT
           val model = solver.getModel
+          solver.pop()
 
           foundAnswer(Some(true), Some(model))
 
         case Some(false) if !unrollingBank.canUnroll =>
+          solver.pop()
           foundAnswer(Some(false))
 
         case Some(false) =>
           //debug("UNSAT BECAUSE: "+solver.getUnsatCore.mkString("\n  AND  \n"))
           //debug("UNSAT BECAUSE: "+core.mkString("  AND  "))
+          solver.pop()
 
           if (!interrupted) {
-            reporter.debug(" - Running search without blocked literals (w/o lucky test)")
+            if (feelingLucky) {
+              reporter.debug(" - Running search without blocked literals (w/ lucky test)")
+            } else {
+              reporter.debug(" - Running search without blocked literals (w/o lucky test)")
+            }
 
             solver.push()
             solver.assertCnstr(And(assumptions.toSeq))
             val res2 = solver.check
-            solver.pop()
 
             res2 match {
               case Some(false) =>
@@ -136,10 +195,19 @@ class UnrollingSolver(val context: LeonContext, underlying: IncrementalSolver)
                 foundAnswer(Some(false))
 
               case Some(true) =>
+                if (feelingLucky && !interrupted) {
+                  val model = solver.getModel
+
+                  // we might have been lucky :D
+                  if (isValidModel(model, silenceErrors = true)) {
+                    foundAnswer(Some(true), Some(model))
+                  }
+                }
 
               case None =>
                 foundAnswer(None)
             }
+            solver.pop()
           }
 
           if(interrupted) {
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
index f9f9a59e594d5b1663c0e1d4439d9a5624e63a68..cf2ae8760ac2e4df282d21ad9911b0049875da65 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
@@ -13,39 +13,91 @@ import TypeTrees._
 
 import _root_.smtlib.sexpr.SExprs._
 import _root_.smtlib.interpreters.CVC4Interpreter
+import _root_.smtlib.Commands.{Identifier => _, _}
 
 trait SMTLIBCVC4Target extends SMTLIBTarget {
   this: SMTLIBSolver =>
 
-  val targetName = "cvc4"
+  def targetName = "cvc4"
 
   def getNewInterpreter() = new CVC4Interpreter
 
-  val extSym = SSymbol("_")
+  override def declareSort(t: TypeTree): SExpr = {
+    val tpe = normalizeType(t)
+    sorts.cachedB(tpe) {
+      tpe match {
+        case TypeParameter(id) =>
+          val s = id2sym(id)
+          val cmd = NonStandardCommand(SList(SSymbol("declare-sort"), s, SInt(0)))
+          sendCommand(cmd)
+          s
+        case SetType(base) =>
+          SList(SSymbol("Set"), declareSort(base))
+        case _ =>
+          super[SMTLIBTarget].declareSort(t)
+      }
+    }
+  }
+
+  override def fromSMT(s: SExpr, tpe: TypeTree)(implicit letDefs: Map[SSymbol, SExpr]): Expr = (s, tpe) match {
+    case (s: SSymbol, tp: TypeParameter) =>
+      val n = s.s.split("_").toList.last
+      GenericValue(tp, n.toInt)
+
+    case (SList(SSymbol("as") ::  SSymbol("emptyset") :: _), SetType(base)) =>
+      FiniteSet(Seq()).setType(tpe)
+
+    case (SList(SSymbol("setenum") :: elems), SetType(base)) =>
+      FiniteSet(elems.map(fromSMT(_, base))).setType(tpe)
+
+    case (SList(SSymbol("union") :: elems), SetType(base)) =>
+      FiniteSet(elems.map(fromSMT(_, tpe) match {
+        case FiniteSet(elems) => elems
+      }).flatten).setType(tpe)
+
+    case _ =>
+      super[SMTLIBTarget].fromSMT(s, tpe)
+  }
 
   override def toSMT(e: Expr)(implicit bindings: Map[Identifier, SExpr]) = e match {
-      case fs @ FiniteSet(elems) =>
-        val ss = declareSort(fs.getType)
-        var res = SList(SSymbol("as"), SSymbol("const"), ss, toSMT(BooleanLiteral(false)))
+    case a @ FiniteArray(elems) =>
+      val tpe @ ArrayType(base) = normalizeType(a.getType)
+      declareSort(tpe)
+
+      var ar: SExpr = declareVariable(FreshIdentifier("arrayconst").setType(RawArrayType(Int32Type, base)))
+
+      for ((e, i) <- elems.zipWithIndex) {
+        ar = SList(SSymbol("store"), ar, toSMT(IntLiteral(i)), toSMT(e))
+      }
+
+      SList(constructors.toB(tpe), toSMT(IntLiteral(elems.size)), ar)
+
+    /**
+     * ===== Set operations =====
+     */
+    case fs @ FiniteSet(elems) =>
+      if (elems.isEmpty) {
+        SList(SSymbol("as"), SSymbol("emptyset"), declareSort(fs.getType))
+      } else {
+        SList(SSymbol("setenum") :: elems.map(toSMT).toList)
+      }
+
+    case SubsetOf(ss, s) =>
+      SList(SSymbol("subseteq"), toSMT(ss), toSMT(s))
 
-        for (e <- elems) {
-          res = SList(SSymbol("store"), res, toSMT(e), toSMT(BooleanLiteral(true)))
-        }
+    case ElementOfSet(e, s) =>
+      SList(SSymbol("in"), toSMT(e), toSMT(s))
 
-        res
+    case SetDifference(a, b) =>
+      SList(SSymbol("setminus"), toSMT(a), toSMT(b))
 
-      case sd @ SetDifference(a, b) =>
-        // a -- b
-        // becomes:
-        // a && not(b)
-        SList(SList(extSym, SSymbol("map"), SSymbol("and")), toSMT(a), SList(SList(extSym, SSymbol("map"), SSymbol("not")), toSMT(b)))
-      case SetUnion(l, r) =>
-        SList(SList(extSym, SSymbol("map"), SSymbol("or")), toSMT(l), toSMT(r))
+    case SetUnion(a, b) =>
+      SList(SSymbol("union"), toSMT(a), toSMT(b))
 
-      case SetIntersection(l, r) =>
-        SList(SList(extSym, SSymbol("map"), SSymbol("and")), toSMT(l), toSMT(r))
+    case SetIntersection(a, b) =>
+      SList(SSymbol("intersection"), toSMT(a), toSMT(b))
 
-      case _ =>
-        super.toSMT(e)
+    case _ =>
+      super[SMTLIBTarget].toSMT(e)
   }
 }
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
index 87196540dfde988a43af69440f495889bf07cba2..720e238f83117e60a477246928bd5ffee0107b34 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
@@ -49,7 +49,15 @@ trait SMTLIBTarget {
     case _ =>   t
   }
 
-  def unsupported(str: Any) = reporter.fatalError(s"Unsupported in $targetName: $str")
+  // Corresponds to a smt map, not a leon/scala array
+  // Should NEVER escape past SMT-world
+  case class RawArrayType(from: TypeTree, to: TypeTree) extends TypeTree
+
+  // Corresponds to a raw array value, which is coerced to a Leon expr depending on target type (set/array)
+  // Should NEVER escape past SMT-world
+  case class RawArrayValue(keyTpe: TypeTree, elems: Map[Expr, Expr], default: Expr) extends Expr
+
+  def unsupported(str: Any) = reporter.fatalError(s"Unsupported in smt-$targetName: $str")
 
   def declareSort(t: TypeTree): SExpr = {
     val tpe = normalizeType(t)
@@ -57,17 +65,16 @@ trait SMTLIBTarget {
       tpe match {
         case BooleanType => SSymbol("Bool")
         case Int32Type => SSymbol("Int")
-        case UnitType =>
-          val s = SSymbol("Unit")
-          val cmd = NonStandardCommand(SList(SSymbol("declare-sort"), s))
-          sendCommand(cmd)
-          s
+
+        case RawArrayType(from, to) =>
+          SList(SSymbol("Array"), declareSort(from), declareSort(to))
+
         case TypeParameter(id) =>
           val s = id2sym(id)
           val cmd = NonStandardCommand(SList(SSymbol("declare-sort"), s))
           sendCommand(cmd)
           s
-        case _: ClassType | _: TupleType =>
+        case _: ClassType | _: TupleType | _: ArrayType | UnitType =>
           declareStructuralSort(tpe)
         case _ =>
           unsupported("Sort "+t)
@@ -115,7 +122,7 @@ trait SMTLIBTarget {
           for (ct <- root +: sub; f <- ct.fields) findDependencies(f.tpe)
         }
       case tt @ TupleType(bases) =>
-        if (!(datatypes contains tt) && !(sorts containsA tt)) {
+        if (!(datatypes contains t) && !(sorts containsA t)) {
           val sym = freshSym("tuple"+bases.size)
 
           val c = Constructor(freshSym(sym.s), tt, bases.zipWithIndex.map {
@@ -127,8 +134,27 @@ trait SMTLIBTarget {
           bases.foreach(findDependencies)
         }
 
-      case st @ SetType(base) =>
+      case UnitType =>
+        if (!(datatypes contains t) && !(sorts containsA t)) {
+
+          val sym = freshSym("Unit")
+
+          datatypes += t -> DataType(sym, Seq(Constructor(freshSym(sym.s), t, Nil)))
+        }
+
+      case at @ ArrayType(base) =>
+        if (!(datatypes contains t) && !(sorts containsA t)) {
+          val sym = freshSym("array")
+
+          val c = Constructor(freshSym(sym.s), at, List(
+            (freshSym("size"), Int32Type),
+            (freshSym("content"), RawArrayType(Int32Type, base))
+          ))
 
+          datatypes += at -> DataType(sym, Seq(c))
+
+          findDependencies(base)
+        }
 
       case _ =>
     }
@@ -193,7 +219,11 @@ trait SMTLIBTarget {
         declareSort(e.getType)
         bindings.getOrElse(id, variables.toB(id))
 
-      case IntLiteral(v) => SInt(v)
+      case UnitLiteral() =>
+        declareSort(UnitType)
+        declareVariable(FreshIdentifier("Unit").setType(UnitType))
+
+      case IntLiteral(i) => if (i > 0) SInt(i) else SList(SSymbol("-"), SInt(-i))
       case BooleanLiteral(v) => SSymbol(if (v) "true" else "false")
       case StringLiteral(s) => SString(s)
       case Let(b,d,e) =>
@@ -235,8 +265,26 @@ trait SMTLIBTarget {
 
       case ts @ TupleSelect(t, i) =>
         val tpe = normalizeType(t.getType)
+        declareSort(tpe)
         SList(selectors.toB((tpe, i-1)), toSMT(t))
 
+      case al @ ArrayLength(a) =>
+        val tpe = normalizeType(a.getType)
+        SList(selectors.toB((tpe, 0)), toSMT(a))
+
+      case as @ ArraySelect(a, i) =>
+        val tpe = normalizeType(a.getType)
+        SList(SSymbol("select"), SList(selectors.toB((tpe, 1)), toSMT(a)), toSMT(i))
+
+      case as @ ArrayUpdated(a, i, e) =>
+        val tpe = normalizeType(a.getType)
+
+        val ssize    = SList(selectors.toB((tpe, 0)), toSMT(a))
+        val scontent = SList(selectors.toB((tpe, 1)), toSMT(a))
+
+        SList(constructors.toB(tpe), ssize, SList(SSymbol("store"), scontent, toSMT(i), toSMT(e)))
+
+
       case e @ UnaryOperator(u, _) =>
         val op = e match {
           case _: Not => SSymbol("not")
@@ -281,15 +329,21 @@ trait SMTLIBTarget {
     }
   }
 
-  def extractSpecialSymbols(s: SSymbol): Option[Expr] = {
-    None
+  def fromSMT(pair: (SExpr, TypeTree))(implicit letDefs: Map[SSymbol, SExpr]): Expr = {
+    fromSMT(pair._1, pair._2)
   }
 
-  def fromSMT(s: SExpr)(implicit bindings: Map[SSymbol, Expr]): Expr = s match {
-    case SInt(n)          => IntLiteral(n.toInt)
-    case SSymbol("true")  => BooleanLiteral(true)
-    case SSymbol("false") => BooleanLiteral(false)
-    case s: SSymbol if constructors.containsB(s) =>
+  def fromSMT(s: SExpr, tpe: TypeTree)(implicit letDefs: Map[SSymbol, SExpr]): Expr = (s, tpe) match {
+    case (_, UnitType) =>
+      UnitLiteral()
+
+    case (SInt(n), Int32Type) =>
+      IntLiteral(n.toInt)
+
+    case (SSymbol(s), BooleanType)  =>
+      BooleanLiteral(s == "true")
+
+    case (s: SSymbol, _: ClassType) if constructors.containsB(s) =>
       constructors.toA(s) match {
         case cct: CaseClassType =>
           CaseClass(cct, Nil)
@@ -297,42 +351,51 @@ trait SMTLIBTarget {
           unsupported("woot? for a single constructor for non-case-object: "+t)
       }
 
-    case s: SSymbol =>
-      (bindings.get(s) orElse variables.getA(s).map(_.toVariable)
-                       orElse extractSpecialSymbols(s)).getOrElse {
+    case (s: SSymbol, tpe) if letDefs contains s =>
+      fromSMT(letDefs(s), tpe)
+
+    case (s: SSymbol, _) =>
+      variables.getA(s).map(_.toVariable).getOrElse {
         unsupported("Unknown symbol: "+s)
       }
 
-    case SList((s: SSymbol) :: args) if(constructors.containsB(s)) => 
-      val rargs = args.map(fromSMT)
+    case (SList((s: SSymbol) :: args), tpe) if constructors.containsB(s) =>
       constructors.toA(s) match {
         case cct: CaseClassType =>
+          val rargs = args.zip(cct.fields.map(_.tpe)).map(fromSMT)
           CaseClass(cct, rargs)
         case tt: TupleType =>
+          val rargs = args.zip(tt.bases).map(fromSMT)
           Tuple(rargs)
+
+        case at: ArrayType =>
+          val IntLiteral(size)                 = fromSMT(args(0), Int32Type)
+          val RawArrayValue(_, elems, default) = fromSMT(args(1), RawArrayType(Int32Type, at.base))
+
+          val entries = for (i <- 0 to size-1) yield elems.getOrElse(IntLiteral(i), default)
+
+          FiniteArray(entries).setType(at)
+
         case t =>
           unsupported("Woot? structural type that is non-structural: "+t)
       }
 
-    case SList(List(SSymbol("let"), SList(defs), body)) =>
-      val leonDefs: Seq[(SSymbol, Identifier, Expr)] = defs.map {
+    // EK: Since we have no type information, we cannot do type-directed
+    // extraction of defs, instead, we expand them in smt-world
+    case (SList(List(SSymbol("let"), SList(defs), body)), tpe) =>
+      val defsMap: Map[SSymbol, SExpr] = defs.map {
         case SList(List(s : SSymbol, value)) =>
-          (s, FreshIdentifier(s.s), fromSMT(value))
-      }
+          (s, value)
+      }.toMap
 
-      val newBindings = bindings ++ leonDefs.map(d => d._1 -> d._3)
-      val newBody = fromSMT(body)(newBindings)
-
-      LetTuple(leonDefs.map(_._2), Tuple(leonDefs.map(_._3)), newBody)
-
-    case SList(SSymbol(app) :: args) => {
-      val recArgs = args.map(fromSMT)
+      fromSMT(body, tpe)(letDefs ++ defsMap)
 
+    case (SList(SSymbol(app) :: args), tpe) => {
       app match {
         case "-" =>
-          recArgs match {
-            case List(a) => UMinus(a)
-            case List(a, b) => Minus(a, b)
+          args match {
+            case List(a) => UMinus(fromSMT(a, Int32Type))
+            case List(a, b) => Minus(fromSMT(a, Int32Type), fromSMT(b, Int32Type))
           }
 
         case _ =>
@@ -350,9 +413,11 @@ trait SMTLIBTarget {
       out.flush
     }
 
-    val response = interpreter.eval(cmd)
-    assert(!response.isInstanceOf[Error])
-    response
+    interpreter.eval(cmd) match {
+      case ErrorResponse(msg) =>
+        reporter.fatalError("Unnexpected error from smt-"+targetName+" solver: "+msg)
+      case res => res
+    }
   }
 
   override def assertCnstr(expr: Expr): Unit = {
@@ -375,7 +440,9 @@ trait SMTLIBTarget {
 
     valuationPairs.collect {
       case (sym: SSymbol, value) if variables.containsB(sym) =>
-        (variables.toA(sym), fromSMT(value)(Map()))
+        val id = variables.toA(sym)
+
+        (id, fromSMT(value, id.getType)(Map()))
     }.toMap
   }
 
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
index 127f1e79cd40894687278c90ea9dcaafa992f322..1bd4f6b13f6bc4ea5a05278f30195a4823cbc0c1 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
@@ -10,6 +10,7 @@ import Common._
 import Trees._
 import Extractors._
 import TypeTrees._
+import TreeOps.simplestValue
 
 import _root_.smtlib.sexpr.SExprs._
 import _root_.smtlib.interpreters.Z3Interpreter
@@ -26,14 +27,19 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
   val extSym = SSymbol("_")
 
   var setSort: Option[SSymbol] = None
+  var mapSort: Option[SSymbol] = None
+  var optionSort: Option[SSymbol] = None
 
   override def declareSort(t: TypeTree): SExpr = {
     val tpe = normalizeType(t)
     sorts.cachedB(tpe) {
       tpe match {
+        case MapType(from, to) =>
+          declareMapSort(from, to)
         case SetType(base) =>
           declareSetSort(base)
-        case _ => super.declareSort(t)
+        case _ =>
+          super.declareSort(t)
       }
     }
   }
@@ -53,35 +59,108 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
     SList(setSort.get, declareSort(of))
   }
 
-  override def extractSpecialSymbols(s: SSymbol): Option[Expr] = {
-    s.s.split("!").toList.reverse match {
-      case n :: "val" :: rest =>
-        val sort = rest.reverse.mkString("!")
+  def declareOptionSort(of: TypeTree) = {
+    optionSort match {
+      case None =>
+        val t      = SSymbol("T")
 
-        sorts.getA(SSymbol(sort)) match {
-          case Some(tp : TypeParameter) =>
-            Some(GenericValue(tp, n.toInt))
-          case _ =>
-            None
-        }
+        val s      = SSymbol("Option")
+        val some   = SSymbol("Some")
+        val some_v = SSymbol("Some_v")
+        val none   = SSymbol("None")
+
+        val caseSome = SList(some, SList(some_v, t))
+        val caseNone = none
+
+        val cmd = NonStandardCommand(SList(SSymbol("declare-datatypes"), SList(t), SList(SList(s, caseSome, caseNone))))
+        sendCommand(cmd)
+
+        optionSort = Some(s)
+      case _ =>
+    }
+
+    SList(optionSort.get, declareSort(of))
+  }
+
+  def declareMapSort(from: TypeTree, to: TypeTree) = {
+    mapSort match {
+      case None =>
+        val m = SSymbol("Map")
+        val a = SSymbol("A")
+        val b = SSymbol("B")
+        mapSort = Some(m)
+        declareOptionSort(to)
+
+        val cmd = NonStandardCommand(SList(SSymbol("define-sort"), m, SList(a, b), SList(SSymbol("Array"), a, SList(optionSort.get, b))))
+        sendCommand(cmd)
       case _ =>
-        None
     }
+
+    SList(mapSort.get, declareSort(from), declareSort(to))
   }
 
-  override def fromSMT(s: SExpr)(implicit bindings: Map[SSymbol, Expr]): Expr = s match {
-    case SList(List(`extSym`, SSymbol("as-array"), k: SSymbol)) =>
-      bindings(k)
+  override def fromSMT(s: SExpr, tpe: TypeTree)(implicit letDefs: Map[SSymbol, SExpr]): Expr = (s, tpe) match {
+    case (s: SSymbol, tp: TypeParameter) =>
+      val n = s.s.split("!").toList.last
+      GenericValue(tp, n.toInt)
+
+
+    case (SList(List(`extSym`, SSymbol("as-array"), k: SSymbol)), tpe) =>
+      if (letDefs contains k) {
+        // Need to recover value form function model
+        fromRawArray(extractRawArray(letDefs(k)), tpe)
+      } else {
+        unsupported(" as-array on non-function or unknown symbol "+k)
+      }
 
     // SMT representation for empty sets: Array(* -> false)
-    case SList(List(SList(List(SSymbol("as"), SSymbol("const"), SList(List(SSymbol("Array"), s, SSymbol("Bool"))))), SSymbol("false"))) =>
-      FiniteSet(Nil).setType(sorts.fromB(s))
+    case (SList(List(SList(List(SSymbol("as"), SSymbol("const"), SList(List(SSymbol("Array"), k, v)))), defV)), tpe) =>
+      val ktpe = sorts.fromB(k)
+      val vtpe = sorts.fromB(v)
+
+      fromRawArray(RawArrayValue(ktpe, Map(), fromSMT(defV, vtpe)), tpe)
 
     case _ =>
-      super.fromSMT(s)
+      super[SMTLIBTarget].fromSMT(s, tpe)
   }
 
   override def toSMT(e: Expr)(implicit bindings: Map[Identifier, SExpr]) = e match {
+      case a @ FiniteArray(elems) =>
+        val tpe @ ArrayType(base) = normalizeType(a.getType)
+        declareSort(tpe)
+
+        var ar = SList(SList(SSymbol("as"), SSymbol("const"), declareSort(RawArrayType(Int32Type, base))), toSMT(simplestValue(base)))
+
+        for ((e, i) <- elems.zipWithIndex) {
+          ar = SList(SSymbol("store"), ar, toSMT(IntLiteral(i)), toSMT(e))
+        }
+
+        SList(constructors.toB(tpe), toSMT(IntLiteral(elems.size)), ar)
+
+      /**
+       * ===== Map operations =====
+       */
+      case MapGet(m, k) =>
+        declareSort(m.getType)
+        SList(SSymbol("Some_v"), SList(SSymbol("select"), toSMT(m), toSMT(k)))
+
+      case MapIsDefinedAt(m, k) =>
+        declareSort(m.getType)
+        SList(SSymbol("is-Some"), SList(SSymbol("select"), toSMT(m), toSMT(k)))
+
+      case m @ FiniteMap(elems) =>
+        val ms = declareSort(m.getType)
+
+        var res = SList(SList(SSymbol("as"), SSymbol("const"), ms), SSymbol("None"))
+        for ((k, v) <- elems) {
+          res = SList(SSymbol("store"), res, toSMT(k), SList(SSymbol("Some"), toSMT(v)))
+        }
+
+        res
+
+      /**
+       * ===== Set operations =====
+       */
       case fs @ FiniteSet(elems) =>
         val ss = declareSort(fs.getType)
         var res = SList(SList(SSymbol("as"), SSymbol("const"), ss), toSMT(BooleanLiteral(false)))
@@ -92,7 +171,17 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
 
         res
 
-      case sd @ SetDifference(a, b) =>
+      case SubsetOf(ss, s) =>
+        // a isSubset b   ==>   (a zip b).map(implies) == (* => true)
+        val allTrue    = SList(SList(SSymbol("as"), SSymbol("const"), declareSort(s.getType)), SSymbol("true"))
+        val mapImplies = SList(SList(extSym, SSymbol("map"), SSymbol("implies")), toSMT(ss), toSMT(s))
+
+        SList(SSymbol("="), mapImplies, allTrue)
+
+      case ElementOfSet(e, s) =>
+        SList(SSymbol("select"), toSMT(s), toSMT(e))
+
+      case SetDifference(a, b) =>
         // a -- b
         // becomes:
         // a && not(b)
@@ -107,7 +196,40 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
         super.toSMT(e)
   }
 
-  // We use get-model instead
+  def extractRawArray(s: SExpr)(implicit letDefs: Map[SSymbol, SExpr]): RawArrayValue = s match {
+    case SList(List(SSymbol("define-fun"), a: SSymbol, SList(SList(List(arg, akind)) :: Nil), rkind, body)) =>
+      val argTpe = sorts.toA(akind)
+      val retTpe = sorts.toA(rkind)
+
+      def extractCases(e: SExpr): (Map[Expr, Expr], Expr) = e match {
+        case SList(SSymbol("ite") :: SList(SSymbol("=") :: `arg` :: k :: Nil) :: v :: e :: Nil) =>
+          val (cs, d) = extractCases(e)
+          (Map(fromSMT(k, argTpe) -> fromSMT(v, retTpe)) ++ cs, d)
+        case e =>
+          (Map(),fromSMT(e, retTpe))
+      }
+
+      val (cases, default) = extractCases(body)
+
+      RawArrayValue(argTpe, cases, default)
+    case _ =>
+      unsupported("Unable to extract "+s)
+  }
+
+  def fromRawArray(r: RawArrayValue, tpe: TypeTree): Expr = tpe match {
+    case SetType(base) =>
+      assert(r.default == BooleanLiteral(false) && r.keyTpe == base)
+
+      FiniteSet(r.elems.keySet.toSeq).setType(tpe)
+
+    case RawArrayType(from, to) =>
+      r
+
+    case _ =>
+      unsupported("Unable to extract from raw array for "+tpe)
+  }
+
+  // EK: We use get-model instead in order to extract models for arrays
   override def getModel: Map[Identifier, Expr] = {
 
     val cmd = NonStandardCommand(SList(SSymbol("get-model")))
@@ -119,40 +241,12 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
       case _ => Nil
     }
 
-    var maps = Map[SSymbol, TypeTree]()
+    var modelFunDefs = Map[SSymbol, SExpr]()
 
     // First pass to gather functions (arrays defs)
     for (me <- smodel) me match {
-      case SList(List(SSymbol("define-fun"), a: SSymbol, SList(Nil), _, SList(List(`extSym`, SSymbol("as-array"), k: SSymbol)))) =>
-        maps += k -> variables.toA(a).getType
-      case _ =>
-    }
-
-    var bindings = Map[SSymbol, Expr]()
-
-    // Second pass to gather functions (arrays defs)
-    for (me <- smodel) me match {
-      case SList(List(SSymbol("define-fun"), s: SSymbol, SList(SList(List(arg, _)) :: Nil), _, e)) if maps contains s =>
-        def extractCases(e: SExpr): (Map[Expr, Expr], Expr) = e match {
-          case SList(SSymbol("ite") :: SList(SSymbol("=") :: `arg` :: k :: Nil) :: v :: e :: Nil) =>
-            val (cs, d) = extractCases(e)
-            (Map(fromSMT(k)(Map()) -> fromSMT(v)(Map())) ++ cs, d)
-          case e =>
-            (Map(),fromSMT(e)(Map()))
-        }
-
-        def buildValue(cases: Map[Expr, Expr], default: Expr, tpe: TypeTree): Expr = tpe match {
-          case SetType(base) =>
-            assert(default == BooleanLiteral(false))
-            FiniteSet(cases.keySet.toSeq).setType(tpe)
-          case _ =>
-            unsupported("Cannot build array/map model to "+tpe)
-        }
-
-        val tpe = maps(s)
-        val (cases, default) = extractCases(e)
-
-        bindings += s -> buildValue(cases, default, tpe)
+      case SList(List(SSymbol("define-fun"), a: SSymbol, SList(args), _, _)) if args.nonEmpty =>
+        modelFunDefs += a -> me
       case _ =>
     }
 
@@ -161,7 +255,9 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
     for (me <- smodel) me match {
       case SList(List(SSymbol("define-fun"), s: SSymbol, SList(args), kind, e)) =>
         if (args.isEmpty) {
-          model += variables.toA(s) -> fromSMT(e)(bindings)
+          val id = variables.toA(s)
+          // EK: this is a little hack, we pass models for array functions as let-defs
+          model += id -> fromSMT(e, id.getType)(modelFunDefs)
         }
 
       case SList(SSymbol("forall") :: _) => // no body
diff --git a/src/test/scala/leon/test/verification/PureScalaVerificationRegression.scala b/src/test/scala/leon/test/verification/PureScalaVerificationRegression.scala
index 3a52f45070b48c057b90027daebbbfed8966c8a8..878bc19da64fa437ea43873778074caa9081dbbe 100644
--- a/src/test/scala/leon/test/verification/PureScalaVerificationRegression.scala
+++ b/src/test/scala/leon/test/verification/PureScalaVerificationRegression.scala
@@ -10,6 +10,8 @@ import leon.verification.{AnalysisPhase,VerificationReport}
 import leon.frontends.scalac.ExtractionPhase
 import leon.utils.PreprocessingPhase
 
+import _root_.smtlib.interpreters._
+
 import java.io.File
 
 class PureScalaVerificationRegression extends LeonTestSuite {
@@ -48,7 +50,6 @@ class PureScalaVerificationRegression extends LeonTestSuite {
           pipeline.run(ctx)(file.getPath :: Nil)
         }
       } else {
-
         val report = pipeline.run(ctx)(file.getPath :: Nil)
 
         block(Output(report, ctx.reporter))
@@ -61,11 +62,33 @@ class PureScalaVerificationRegression extends LeonTestSuite {
       "regression/verification/purescala/" + cat,
       _.endsWith(".scala"))
 
+    val isZ3Available = try {
+      new Z3Interpreter()
+      true
+    } catch {
+      case e: java.io.IOException =>
+        false
+    }
+
+    val isCVC4Available = try {
+      //new CVC4Interpreter()
+      // @EK: CVC4 works on most testcases already, but not all and thus cannot be used in regression.
+      false
+    } catch {
+      case e: java.io.IOException =>
+        false
+    }
+
     for(f <- fs) {
       mkTest(f, List("--feelinglucky", "--library=no"), forError)(block)
       mkTest(f, List("--codegen", "--evalground", "--feelinglucky", "--library=no"), forError)(block)
       mkTest(f, List("--solvers=fairz3,enum", "--codegen", "--evalground", "--feelinglucky", "--library=no"), forError)(block)
-      mkTest(f, List("--solvers=smt-z3", "--library=no"), forError)(block)
+      if (isZ3Available) {
+        mkTest(f, List("--solvers=smt-z3", "--feelinglucky", "--library=no"), forError)(block)
+      }
+      if (isCVC4Available) {
+        mkTest(f, List("--solvers=smt-cvc4", "--feelinglucky", "--library=no"), forError)(block)
+      }
     }
   }