diff --git a/library/lang/string/String.scala b/library/lang/string/String.scala
deleted file mode 100644
index 0a3e72bd1a6f234a79eba234a646b2c0844ecfaf..0000000000000000000000000000000000000000
--- a/library/lang/string/String.scala
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright 2009-2015 EPFL, Lausanne */
-
-package leon.lang.string
-
-import leon.annotation._
-import leon.collection._
-
-@library
-case class String(chars: List[Char]) {
-  def +(that: String): String = {
-    String(this.chars ++ that.chars)
-  }
-
-  def size = chars.size
-
-  def length = size
-
-  @ignore
-  override def toString = {
-
-    "\""+charsToString(chars)+"\""
-  }
-  @ignore
-  def charsToString(chars: List[Char]): java.lang.String = chars match {
-    case Cons(h, t) => h + charsToString(t)
-    case Nil() => ""
-  }
-}
diff --git a/library/lang/string/package.scala b/library/lang/string/package.scala
deleted file mode 100644
index d931debe7c587f966aadd30b2860b1793c6ad431..0000000000000000000000000000000000000000
--- a/library/lang/string/package.scala
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright 2009-2015 EPFL, Lausanne */
-
-package leon.lang
-
-import leon.annotation._
-import leon.collection._
-import scala.language.implicitConversions
-
-import scala.collection.immutable.{List => ScalaList}
-
-package object string {
-  /*@ignore
-  implicit def strToStr(s: java.lang.String): leon.lang.string.String = {
-    String(listToList(s.toList))
-  }*/
-
-  @ignore
-  def listToList[A](s: ScalaList[A]): List[A] = s match {
-    case scala.::(h, t) =>
-      Cons(h, listToList(t))
-    case _ =>
-      Nil[A]()
-  }
-}
diff --git a/src/main/scala/leon/codegen/CompilationUnit.scala b/src/main/scala/leon/codegen/CompilationUnit.scala
index 93c8c6d021233a6c5968d7de9a78b7c3d135ced1..26f976c095489f22cbc97dd9ee810d1d71ef9f99 100644
--- a/src/main/scala/leon/codegen/CompilationUnit.scala
+++ b/src/main/scala/leon/codegen/CompilationUnit.scala
@@ -177,6 +177,9 @@ class CompilationUnit(val ctx: LeonContext,
 
     case FractionalLiteral(n, d) =>
       new runtime.Rational(n.toString, d.toString)
+      
+    case StringLiteral(v) =>
+      new java.lang.String(v)
 
     case GenericValue(tp, id) =>
       e
diff --git a/src/main/scala/leon/datagen/VanuatooDataGen.scala b/src/main/scala/leon/datagen/VanuatooDataGen.scala
index 8b4846a3394c3c3ddd2326d24d23ce95e68f6b05..b82dc6a0f256fec3c3cf733addad76f899456f4a 100644
--- a/src/main/scala/leon/datagen/VanuatooDataGen.scala
+++ b/src/main/scala/leon/datagen/VanuatooDataGen.scala
@@ -58,6 +58,8 @@ class VanuatooDataGen(ctx: LeonContext, p: Program) extends DataGenerator {
 
   def stringConstructor(s: String) = strings(s)
 
+  lazy val stubValues = ints.values ++ bigInts.values ++ booleans.values ++ chars.values ++ rationals.values ++ strings.values
+  
   def cPattern(c: Constructor[Expr, TypeTree], args: Seq[VPattern[Expr, TypeTree]]) = {
     ConstructorPattern[Expr, TypeTree](c, args)
   }
@@ -307,7 +309,6 @@ class VanuatooDataGen(ctx: LeonContext, p: Program) extends DataGenerator {
         None
     })
 
-    val stubValues = ints.values ++ bigInts.values ++ booleans.values ++ chars.values ++ rationals.values
     val gen = new StubGenerator[Expr, TypeTree](stubValues.toSeq,
                                                 Some(getConstructors _),
                                                 treatEmptyStubsAsChildless = true)
diff --git a/src/main/scala/leon/purescala/Definitions.scala b/src/main/scala/leon/purescala/Definitions.scala
index d9fd1d1d6696991909ffd5cd9b1f2e95590db7a4..4b89493e10d94d16fe355f9e63bc2e9f44f3714d 100644
--- a/src/main/scala/leon/purescala/Definitions.scala
+++ b/src/main/scala/leon/purescala/Definitions.scala
@@ -84,6 +84,10 @@ object Definitions {
 
     def lookupAll(name: String)  = DefOps.searchWithin(name, this)
     def lookup(name: String)     = lookupAll(name).headOption
+    
+    def lookupCaseClass(name: String) = lookupAll(name).collect{ case c: CaseClassDef => c }.headOption
+    def lookupAbstractClass(name: String) = lookupAll(name).collect{ case c: AbstractClassDef => c }.headOption
+    def lookupFunDef(name: String) = lookupAll(name).collect{ case c: FunDef => c }.headOption
   }
 
   object Program {
diff --git a/src/main/scala/leon/purescala/Expressions.scala b/src/main/scala/leon/purescala/Expressions.scala
index ae93221bfe8313cf8cef20ed084d559a2a472133..13e4efbef15d754765776de6153c9f5a8b65c6c8 100644
--- a/src/main/scala/leon/purescala/Expressions.scala
+++ b/src/main/scala/leon/purescala/Expressions.scala
@@ -584,7 +584,7 @@ object Expressions {
   /** $encodingof `lhs.length` for strings */
   case class StringLength(expr: Expr) extends Expr {
     val getType = {
-      if (expr.getType == StringType) StringType
+      if (expr.getType == StringType) Int32Type
       else Untyped
     }
   }
diff --git a/src/main/scala/leon/purescala/SelfPrettyPrinter.scala b/src/main/scala/leon/purescala/SelfPrettyPrinter.scala
index 35e4d1f61b7213bba3121d1fd4926d054075b717..aa4c204d00187ab211a7164a45ae41d8d77d8f8f 100644
--- a/src/main/scala/leon/purescala/SelfPrettyPrinter.scala
+++ b/src/main/scala/leon/purescala/SelfPrettyPrinter.scala
@@ -18,7 +18,6 @@ import purescala.Types._
 import purescala.Common._
 import purescala.Expressions._
 import purescala.Definitions._
-import purescala.SelfPrettyPrinter
 import leon.solvers.{ HenkinModel, Model, SolverFactory }
 import leon.LeonContext
 import leon.evaluators
diff --git a/src/main/scala/leon/solvers/SolverFactory.scala b/src/main/scala/leon/solvers/SolverFactory.scala
index f59087beed61b5cf9ca9c9b1eac46ce3a7cdcbb6..6b2d4272b37b4a06ba2731c5049bcc043b87c927 100644
--- a/src/main/scala/leon/solvers/SolverFactory.scala
+++ b/src/main/scala/leon/solvers/SolverFactory.scala
@@ -156,6 +156,8 @@ object SolverFactory {
       SolverFactory(() => new SMTLIBCVC4Solver(ctx, program) with TimeoutSolver)
     } else if(names contains "smt-z3") {
       SolverFactory(() => new SMTLIBZ3Solver(ctx, program) with TimeoutSolver)
+    } else if ((names contains "fairz3") && hasNativeZ3) {
+      SolverFactory(() => new UninterpretedZ3Solver(ctx, program) with TimeoutSolver)
     } else {
       ctx.reporter.fatalError("No SMT solver available: native Z3 api could not load and 'cvc4' or 'z3' binaries were not found in PATH.")
     }
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
index f1cf73142d51debaeda0fc5064096e522f049955..87cc849b41d2507d7e0ca53a351b2f605d387b46 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBCVC4Target.scala
@@ -14,6 +14,7 @@ import _root_.smtlib.parser.Terms.{Identifier => SMTIdentifier, Forall => SMTFor
 import _root_.smtlib.parser.Commands._
 import _root_.smtlib.interpreters.CVC4Interpreter
 import _root_.smtlib.theories.experimental.Sets
+import _root_.smtlib.theories.experimental.Strings
 
 trait SMTLIBCVC4Target extends SMTLIBTarget {
 
@@ -30,7 +31,7 @@ trait SMTLIBCVC4Target extends SMTLIBTarget {
       tpe match {
         case SetType(base) =>
           Sets.SetSort(declareSort(base))
-
+        case StringType  => Strings.StringSort()
         case _ =>
           super.declareSort(t)
       }
@@ -109,6 +110,31 @@ trait SMTLIBCVC4Target extends SMTLIBTarget {
           case FiniteSet(elems, _) => elems
         }).toSet, base)
 
+      case (SString(v), Some(StringType)) =>
+        StringLiteral(v)
+        
+      case (Strings.Length(a), _) =>
+        val aa = fromSMT(a)
+        StringLength(aa)
+
+      case (Strings.Concat(a, b, c @ _*), _) =>
+        val aa = fromSMT(a)
+        val bb = fromSMT(b)
+        (StringConcat(aa, bb) /: c.map(fromSMT(_))) {
+          case (s, cc) => StringConcat(s, cc)
+        }
+      
+      case (Strings.Substring(s, start, offset), _) =>
+        val ss = fromSMT(s)
+        val tt = fromSMT(start)
+        val oo = fromSMT(offset)
+        oo match {
+          case Minus(otherEnd, `tt`) => SubString(ss, tt, otherEnd)
+          case _ => SubString(ss, tt, Plus(tt, oo))
+        }
+        
+      case (Strings.At(a, b), _) => fromSMT(Strings.Substring(a, b, SNumeral(1)))
+
       case _ =>
         super.fromSMT(t, otpe)
     }
@@ -138,7 +164,14 @@ trait SMTLIBCVC4Target extends SMTLIBTarget {
     case SetDifference(a, b) => Sets.Setminus(toSMT(a), toSMT(b))
     case SetUnion(a, b) => Sets.Union(toSMT(a), toSMT(b))
     case SetIntersection(a, b) => Sets.Intersection(toSMT(a), toSMT(b))
-
+    case StringLiteral(v)          =>
+        declareSort(StringType)
+        Strings.StringLit(v)
+    case StringLength(a)           => Strings.Length(toSMT(a))
+    case StringConcat(a, b)        => Strings.Concat(toSMT(a), toSMT(b))
+    case SubString(a, start, Plus(start2, length)) if start == start2  =>
+                                      Strings.Substring(toSMT(a),toSMT(start),toSMT(length))
+    case SubString(a, start, end)  => Strings.Substring(toSMT(a),toSMT(start),toSMT(Minus(end, start)))
     case _ =>
       super.toSMT(e)
   }
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
index b97297fb000f12b11972c675535d35a522587703..47017bcf1471770f1b1e9fb574a81bed34f4c515 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBTarget.scala
@@ -241,7 +241,6 @@ trait SMTLIBTarget extends Interruptible {
         case RealType    => Reals.RealSort()
         case Int32Type   => FixedSizeBitVectors.BitVectorSort(32)
         case CharType    => FixedSizeBitVectors.BitVectorSort(32)
-        case StringType  => Strings.StringSort()
 
         case RawArrayType(from, to) =>
           Sort(SMTIdentifier(SSymbol("Array")), Seq(declareSort(from), declareSort(to)))
@@ -379,9 +378,6 @@ trait SMTLIBTarget extends Interruptible {
       case FractionalLiteral(n, d)   => Reals.Div(Reals.NumeralLit(n), Reals.NumeralLit(d))
       case CharLiteral(c)            => FixedSizeBitVectors.BitVectorLit(Hexadecimal.fromInt(c.toInt))
       case BooleanLiteral(v)         => Core.BoolConst(v)
-      case StringLiteral(v)          =>
-        declareSort(StringType)
-        Strings.StringLit(v)
       case Let(b, d, e) =>
         val id = id2sym(b)
         val value = toSMT(d)
@@ -613,12 +609,6 @@ trait SMTLIBTarget extends Interruptible {
       case RealMinus(a, b)           => Reals.Sub(toSMT(a), toSMT(b))
       case RealTimes(a, b)           => Reals.Mul(toSMT(a), toSMT(b))
       case RealDivision(a, b)        => Reals.Div(toSMT(a), toSMT(b))
-      
-      case StringLength(a)           => Strings.Length(toSMT(a))
-      case StringConcat(a, b)        => Strings.Concat(toSMT(a), toSMT(b))
-      case SubString(a, start, Plus(start2, length)) if start == start2  =>
-                                        Strings.Substring(toSMT(a),toSMT(start),toSMT(length))
-      case SubString(a, start, end)  => Strings.Substring(toSMT(a),toSMT(start),toSMT(Minus(end, start)))
 
       case And(sub)                  => Core.And(sub.map(toSMT): _*)
       case Or(sub)                   => Core.Or(sub.map(toSMT): _*)
@@ -764,31 +754,6 @@ trait SMTLIBTarget extends Interruptible {
       case (SNumeral(n), Some(RealType)) =>
         FractionalLiteral(n, 1)
       
-      case (SString(v), Some(StringType)) =>
-        StringLiteral(v)
-        
-      case (Strings.Length(a), _) =>
-        val aa = fromSMT(a)
-        StringLength(aa)
-
-      case (Strings.Concat(a, b, c @ _*), _) =>
-        val aa = fromSMT(a)
-        val bb = fromSMT(b)
-        (StringConcat(aa, bb) /: c.map(fromSMT(_))) {
-          case (s, cc) => StringConcat(s, cc)
-        }
-      
-      case (Strings.Substring(s, start, offset), _) =>
-        val ss = fromSMT(s)
-        val tt = fromSMT(start)
-        val oo = fromSMT(offset)
-        oo match {
-          case Minus(otherEnd, `tt`) => SubString(ss, tt, otherEnd)
-          case _ => SubString(ss, tt, Plus(tt, oo))
-        }
-        
-      case (Strings.At(a, b), _) => fromSMT(Strings.Substring(a, b, SNumeral(1)))
-
       case (FunctionApplication(SimpleSymbol(SSymbol("ite")), Seq(cond, thenn, elze)), t) =>
         IfExpr(
           fromSMT(cond, Some(BooleanType)),
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
index 86cf40f474e62859acfd1fe2c0953e588590d6df..32adcd50f32da267a2663128a3c05759a87be948 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Solver.scala
@@ -15,6 +15,8 @@ import _root_.smtlib.theories.Core.{Equals => _, _}
 
 class SMTLIBZ3Solver(context: LeonContext, program: Program) extends SMTLIBSolver(context, program) with SMTLIBZ3Target {
 
+  def getProgram: Program = program
+  
   // EK: We use get-model instead in order to extract models for arrays
   override def getModel: Model = {
 
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
index 3d4a06a838a5057a693d85754bb5113e1ce7d0ae..1731b94ae5f4f91b87248deddc50db5339915552 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBZ3Target.scala
@@ -8,15 +8,15 @@ import purescala.Common._
 import purescala.Expressions._
 import purescala.Constructors._
 import purescala.Types._
-
+import purescala.Definitions._
 import _root_.smtlib.parser.Terms.{Identifier => SMTIdentifier, _}
 import _root_.smtlib.parser.Commands.{FunDef => SMTFunDef, _}
 import _root_.smtlib.interpreters.Z3Interpreter
 import _root_.smtlib.theories.Core.{Equals => SMTEquals, _}
 import _root_.smtlib.theories.ArraysEx
+import leon.solvers.z3.Z3StringConversion
 
-trait SMTLIBZ3Target extends SMTLIBTarget {
-
+trait SMTLIBZ3Target extends SMTLIBTarget with Z3StringConversion[Term] {
   def targetName = "z3"
 
   def interpreterOps(ctx: LeonContext) = {
@@ -40,11 +40,11 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
   override protected def declareSort(t: TypeTree): Sort = {
     val tpe = normalizeType(t)
     sorts.cachedB(tpe) {
-      tpe match {
+      convertType(tpe) match {
         case SetType(base) =>
           super.declareSort(BooleanType)
           declareSetSort(base)
-        case _ =>
+        case t =>
           super.declareSort(t)
       }
     }
@@ -69,9 +69,13 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
     Sort(SMTIdentifier(setSort.get), Seq(declareSort(of)))
   }
 
-  override protected def fromSMT(t: Term, otpe: Option[TypeTree] = None)
+  override protected def fromSMT(t: Term, expected_otpe: Option[TypeTree] = None)
                                 (implicit lets: Map[SSymbol, Term], letDefs: Map[SSymbol, DefineFun]): Expr = {
-    (t, otpe) match {
+    val otpe = expected_otpe match {
+      case Some(StringType) => Some(listchar)
+      case _ => expected_otpe
+    }
+    val res = (t, otpe) match {
       case (SimpleSymbol(s), Some(tp: TypeParameter)) =>
         val n = s.name.split("!").toList.last
         GenericValue(tp, n.toInt)
@@ -96,6 +100,16 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
       case _ =>
         super.fromSMT(t, otpe)
     }
+    expected_otpe match {
+      case Some(StringType) =>
+        StringLiteral(convertToString(res)(program))
+      case _ => res
+    }
+  }
+  
+  def convertToTarget(e: Expr)(implicit bindings: Map[Identifier, Term]): Term = toSMT(e)
+  def targetApplication(tfd: TypedFunDef, args: Seq[Term])(implicit bindings: Map[Identifier, Term]): Term = {
+    FunctionApplication(declareFunction(tfd), args)
   }
 
   override protected def toSMT(e: Expr)(implicit bindings: Map[Identifier, Term]): Term = e match {
@@ -132,6 +146,7 @@ trait SMTLIBZ3Target extends SMTLIBTarget {
     case SetIntersection(l, r) =>
       ArrayMap(SSymbol("and"), toSMT(l), toSMT(r))
 
+    case StringConverted(result) => result
     case _ =>
       super.toSMT(e)
   }
diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index f0b7d5f91a9f53f32dd6eb9590c988618f0536d4..ac1e8855a4a53ed5ef2f66c34d4b015d9a26ba3f 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -264,311 +264,322 @@ trait AbstractZ3Solver extends Solver {
     case other =>
       throw SolverUnsupportedError(other, this)
   }
+  
+
 
   protected[leon] def toZ3Formula(expr: Expr, initialMap: Map[Identifier, Z3AST] = Map.empty): Z3AST = {
 
-    var z3Vars: Map[Identifier,Z3AST] = if(initialMap.nonEmpty) {
+    implicit var z3Vars: Map[Identifier,Z3AST] = if(initialMap.nonEmpty) {
       initialMap
     } else {
       // FIXME TODO pleeeeeeeease make this cleaner. Ie. decide what set of
       // variable has to remain in a map etc.
       variables.aToB.collect{ case (Variable(id), p2) => id -> p2 }
     }
-
-    def rec(ex: Expr): Z3AST = ex match {
-
-      // TODO: Leave that as a specialization?
-      case LetTuple(ids, e, b) => {
-        z3Vars = z3Vars ++ ids.zipWithIndex.map { case (id, ix) =>
-          val entry = id -> rec(tupleSelect(e, ix + 1, ids.size))
-          entry
+     new Z3StringConversion[Z3AST] {
+        def getProgram = AbstractZ3Solver.this.program
+        def convertToTarget(e: Expr)(implicit bindings: Map[Identifier, Z3AST]): Z3AST = {
+          rec(e)
         }
-        val rb = rec(b)
-        z3Vars = z3Vars -- ids
-        rb
-      }
-
-      case p @ Passes(_, _, _) =>
-        rec(p.asConstraint)
-
-      case me @ MatchExpr(s, cs) =>
-        rec(matchToIfThenElse(me))
-
-      case Let(i, e, b) => {
-        val re = rec(e)
-        z3Vars = z3Vars + (i -> re)
-        val rb = rec(b)
-        z3Vars = z3Vars - i
-        rb
-      }
-
-      case Waypoint(_, e, _) => rec(e)
-      case a @ Assert(cond, err, body) =>
-        rec(IfExpr(cond, body, Error(a.getType, err.getOrElse("Assertion failed")).setPos(a.getPos)).setPos(a.getPos))
-
-      case e @ Error(tpe, _) => {
-        val newAST = z3.mkFreshConst("errorValue", typeToSort(tpe))
-        // Might introduce dupplicates (e), but no worries here
-        variables += (e -> newAST)
-        newAST
-      }
-      case v @ Variable(id) => z3Vars.get(id) match {
-        case Some(ast) => 
-          ast
-        case None => {
-          variables.getB(v) match {
-            case Some(ast) =>
-              ast
-
-            case None =>
-          val newAST = z3.mkFreshConst(id.uniqueName, typeToSort(v.getType))
-          z3Vars = z3Vars + (id -> newAST)
-          variables += (v -> newAST)
-          newAST
-        }
-      }
-      }
-
-      case ite @ IfExpr(c, t, e) => z3.mkITE(rec(c), rec(t), rec(e))
-      case And(exs) => z3.mkAnd(exs.map(rec): _*)
-      case Or(exs) => z3.mkOr(exs.map(rec): _*)
-      case Implies(l, r) => z3.mkImplies(rec(l), rec(r))
-      case Not(Equals(l, r)) => z3.mkDistinct(rec(l), rec(r))
-      case Not(e) => z3.mkNot(rec(e))
-      case IntLiteral(v) => z3.mkInt(v, typeToSort(Int32Type))
-      case InfiniteIntegerLiteral(v) => z3.mkNumeral(v.toString, typeToSort(IntegerType))
-      case FractionalLiteral(n, d) => z3.mkNumeral(s"$n / $d", typeToSort(RealType))
-      case CharLiteral(c) => z3.mkInt(c, typeToSort(CharType))
-      case BooleanLiteral(v) => if (v) z3.mkTrue() else z3.mkFalse()
-      case Equals(l, r) => z3.mkEq(rec( l ), rec( r ) )
-      case Plus(l, r) => z3.mkAdd(rec(l), rec(r))
-      case Minus(l, r) => z3.mkSub(rec(l), rec(r))
-      case Times(l, r) => z3.mkMul(rec(l), rec(r))
-      case Division(l, r) => {
-        val rl = rec(l)
-        val rr = rec(r)
-        z3.mkITE(
-          z3.mkGE(rl, z3.mkNumeral("0", typeToSort(IntegerType))),
-          z3.mkDiv(rl, rr),
-          z3.mkUnaryMinus(z3.mkDiv(z3.mkUnaryMinus(rl), rr))
-        )
-      }
-      case Remainder(l, r) => {
-        val q = rec(Division(l, r))
-        z3.mkSub(rec(l), z3.mkMul(rec(r), q))
-      }
-      case Modulo(l, r) => {
-        z3.mkMod(rec(l), rec(r))
-      }
-      case UMinus(e) => z3.mkUnaryMinus(rec(e))
-
-      case RealPlus(l, r) => z3.mkAdd(rec(l), rec(r))
-      case RealMinus(l, r) => z3.mkSub(rec(l), rec(r))
-      case RealTimes(l, r) => z3.mkMul(rec(l), rec(r))
-      case RealDivision(l, r) => z3.mkDiv(rec(l), rec(r))
-      case RealUMinus(e) => z3.mkUnaryMinus(rec(e))
-
-      case BVPlus(l, r) => z3.mkBVAdd(rec(l), rec(r))
-      case BVMinus(l, r) => z3.mkBVSub(rec(l), rec(r))
-      case BVTimes(l, r) => z3.mkBVMul(rec(l), rec(r))
-      case BVDivision(l, r) => z3.mkBVSdiv(rec(l), rec(r))
-      case BVRemainder(l, r) => z3.mkBVSrem(rec(l), rec(r))
-      case BVUMinus(e) => z3.mkBVNeg(rec(e))
-      case BVNot(e) => z3.mkBVNot(rec(e))
-      case BVAnd(l, r) => z3.mkBVAnd(rec(l), rec(r))
-      case BVOr(l, r) => z3.mkBVOr(rec(l), rec(r))
-      case BVXOr(l, r) => z3.mkBVXor(rec(l), rec(r))
-      case BVShiftLeft(l, r) => z3.mkBVShl(rec(l), rec(r))
-      case BVAShiftRight(l, r) => z3.mkBVAshr(rec(l), rec(r))
-      case BVLShiftRight(l, r) => z3.mkBVLshr(rec(l), rec(r))
-      case LessThan(l, r) => l.getType match {
-        case IntegerType => z3.mkLT(rec(l), rec(r))
-        case RealType => z3.mkLT(rec(l), rec(r))
-        case Int32Type => z3.mkBVSlt(rec(l), rec(r))
-        case CharType => z3.mkBVSlt(rec(l), rec(r))
-      }
-      case LessEquals(l, r) => l.getType match {
-        case IntegerType => z3.mkLE(rec(l), rec(r))
-        case RealType => z3.mkLE(rec(l), rec(r))
-        case Int32Type => z3.mkBVSle(rec(l), rec(r))
-        case CharType => z3.mkBVSle(rec(l), rec(r))
-        //case _ => throw new IllegalStateException(s"l: $l, Left type: ${l.getType} Expr: $ex")
-      }
-      case GreaterThan(l, r) => l.getType match {
-        case IntegerType => z3.mkGT(rec(l), rec(r))
-        case RealType => z3.mkGT(rec(l), rec(r))
-        case Int32Type => z3.mkBVSgt(rec(l), rec(r))
-        case CharType => z3.mkBVSgt(rec(l), rec(r))
-      }
-      case GreaterEquals(l, r) => l.getType match {
-        case IntegerType => z3.mkGE(rec(l), rec(r))
-        case RealType => z3.mkGE(rec(l), rec(r))
-        case Int32Type => z3.mkBVSge(rec(l), rec(r))
-        case CharType => z3.mkBVSge(rec(l), rec(r))
-      }
-
-      case u : UnitLiteral =>
-        val tpe = normalizeType(u.getType)
-        typeToSort(tpe)
-        val constructor = constructors.toB(tpe)
-        constructor()
-
-      case t @ Tuple(es) =>
-        val tpe = normalizeType(t.getType)
-        typeToSort(tpe)
-        val constructor = constructors.toB(tpe)
-        constructor(es.map(rec): _*)
-
-      case ts @ TupleSelect(t, i) =>
-        val tpe = normalizeType(t.getType)
-        typeToSort(tpe)
-        val selector = selectors.toB((tpe, i-1))
-        selector(rec(t))
-
-      case c @ CaseClass(ct, args) =>
-        typeToSort(ct) // Making sure the sort is defined
-        val constructor = constructors.toB(ct)
-        constructor(args.map(rec): _*)
-
-      case c @ CaseClassSelector(cct, cc, sel) =>
-        typeToSort(cct) // Making sure the sort is defined
-        val selector = selectors.toB(cct, c.selectorIndex)
-        selector(rec(cc))
-
-      case AsInstanceOf(expr, ct) =>
-        rec(expr)
-
-      case IsInstanceOf(e, act: AbstractClassType) =>
-        act.knownCCDescendants match {
-          case Seq(cct) =>
-            rec(IsInstanceOf(e, cct))
-          case more =>
-            val i = FreshIdentifier("e", act, alwaysShowUniqueID = true)
-            rec(Let(i, e, orJoin(more map(IsInstanceOf(Variable(i), _)))))
+        def targetApplication(tfd: TypedFunDef, args: Seq[Z3AST])(implicit bindings: Map[Identifier, Z3AST]): Z3AST = {
+          z3.mkApp(functionDefToDecl(tfd), args: _*)
         }
-
-      case IsInstanceOf(e, cct: CaseClassType) =>
-        typeToSort(cct) // Making sure the sort is defined
-        val tester = testers.toB(cct)
-        tester(rec(e))
-
-      case al @ ArraySelect(a, i) =>
-        val tpe = normalizeType(a.getType)
-
-        val sa = rec(a)
-        val content = selectors.toB((tpe, 1))(sa)
-
-        z3.mkSelect(content, rec(i))
-
-      case al @ ArrayUpdated(a, i, e) =>
-        val tpe = normalizeType(a.getType)
-
-        val sa = rec(a)
-        val ssize    = selectors.toB((tpe, 0))(sa)
-        val scontent = selectors.toB((tpe, 1))(sa)
-
-        val newcontent = z3.mkStore(scontent, rec(i), rec(e))
-
-        val constructor = constructors.toB(tpe)
-
-        constructor(ssize, newcontent)
-
-      case al @ ArrayLength(a) =>
-        val tpe = normalizeType(a.getType)
-        val sa = rec(a)
-        selectors.toB((tpe, 0))(sa)
-
-      case arr @ FiniteArray(elems, oDefault, length) =>
-        val at @ ArrayType(base) = normalizeType(arr.getType)
-        typeToSort(at)
-
-        val default = oDefault.getOrElse(simplestValue(base))
-
-        val ar = rec(RawArrayValue(Int32Type, elems.map {
-          case (i, e) => IntLiteral(i) -> e
-        }, default))
-
-        constructors.toB(at)(rec(length), ar)
-
-      case f @ FunctionInvocation(tfd, args) =>
-        z3.mkApp(functionDefToDecl(tfd), args.map(rec): _*)
-
-      case fa @ Application(caller, args) =>
-        val ft @ FunctionType(froms, to) = normalizeType(caller.getType)
-        val funDecl = lambdas.cachedB(ft) {
-          val sortSeq    = (ft +: froms).map(tpe => typeToSort(tpe))
-          val returnSort = typeToSort(to)
-
-          val name = FreshIdentifier("dynLambda").uniqueName
-          z3.mkFreshFuncDecl(name, sortSeq, returnSort)
-        }
-        z3.mkApp(funDecl, (caller +: args).map(rec): _*)
-
-      case ElementOfSet(e, s) => z3.mkSetMember(rec(e), rec(s))
-      case SubsetOf(s1, s2) => z3.mkSetSubset(rec(s1), rec(s2))
-      case SetIntersection(s1, s2) => z3.mkSetIntersect(rec(s1), rec(s2))
-      case SetUnion(s1, s2) => z3.mkSetUnion(rec(s1), rec(s2))
-      case SetDifference(s1, s2) => z3.mkSetDifference(rec(s1), rec(s2))
-      case f @ FiniteSet(elems, base) => elems.foldLeft(z3.mkEmptySet(typeToSort(base)))((ast, el) => z3.mkSetAdd(ast, rec(el)))
-
-      case RawArrayValue(keyTpe, elems, default) =>
-        val ar = z3.mkConstArray(typeToSort(keyTpe), rec(default))
-
-        elems.foldLeft(ar) {
-          case (array, (k, v)) => z3.mkStore(array, rec(k), rec(v))
-        }
-
-      /**
-       * ===== Map operations =====
-       */
-      case m @ FiniteMap(elems, from, to) =>
-        val MapType(_, t) = normalizeType(m.getType)
-
-        rec(RawArrayValue(from, elems.map{
-          case (k, v) => (k, CaseClass(library.someType(t), Seq(v)))
-        }.toMap, CaseClass(library.noneType(t), Seq())))
-
-      case MapApply(m, k) =>
-        val mt @ MapType(_, t) = normalizeType(m.getType)
-        typeToSort(mt)
-
-        val el = z3.mkSelect(rec(m), rec(k))
-
-        // Really ?!? We don't check that it is actually != None?
-        selectors.toB(library.someType(t), 0)(el)
-
-      case MapIsDefinedAt(m, k) =>
-        val mt @ MapType(_, t) = normalizeType(m.getType)
-        typeToSort(mt)
-
-        val el = z3.mkSelect(rec(m), rec(k))
-
-        testers.toB(library.someType(t))(el)
-
-      case MapUnion(m1, FiniteMap(elems, _, _)) =>
-        val mt @ MapType(_, t) = normalizeType(m1.getType)
-        typeToSort(mt)
-
-        elems.foldLeft(rec(m1)) { case (m, (k,v)) =>
-          z3.mkStore(m, rec(k), rec(CaseClass(library.someType(t), Seq(v))))
+        def rec(ex: Expr): Z3AST = ex match {
+    
+          // TODO: Leave that as a specialization?
+          case LetTuple(ids, e, b) => {
+            z3Vars = z3Vars ++ ids.zipWithIndex.map { case (id, ix) =>
+              val entry = id -> rec(tupleSelect(e, ix + 1, ids.size))
+              entry
+            }
+            val rb = rec(b)
+            z3Vars = z3Vars -- ids
+            rb
+          }
+    
+          case p @ Passes(_, _, _) =>
+            rec(p.asConstraint)
+    
+          case me @ MatchExpr(s, cs) =>
+            rec(matchToIfThenElse(me))
+    
+          case Let(i, e, b) => {
+            val re = rec(e)
+            z3Vars = z3Vars + (i -> re)
+            val rb = rec(b)
+            z3Vars = z3Vars - i
+            rb
+          }
+    
+          case Waypoint(_, e, _) => rec(e)
+          case a @ Assert(cond, err, body) =>
+            rec(IfExpr(cond, body, Error(a.getType, err.getOrElse("Assertion failed")).setPos(a.getPos)).setPos(a.getPos))
+    
+          case e @ Error(tpe, _) => {
+            val newAST = z3.mkFreshConst("errorValue", typeToSort(tpe))
+            // Might introduce dupplicates (e), but no worries here
+            variables += (e -> newAST)
+            newAST
+          }
+          case v @ Variable(id) => z3Vars.get(id) match {
+            case Some(ast) => 
+              ast
+            case None => {
+              variables.getB(v) match {
+                case Some(ast) =>
+                  ast
+    
+                case None =>
+              val newAST = z3.mkFreshConst(id.uniqueName, typeToSort(v.getType))
+              z3Vars = z3Vars + (id -> newAST)
+              variables += (v -> newAST)
+              newAST
+            }
+          }
+          }
+    
+          case ite @ IfExpr(c, t, e) => z3.mkITE(rec(c), rec(t), rec(e))
+          case And(exs) => z3.mkAnd(exs.map(rec): _*)
+          case Or(exs) => z3.mkOr(exs.map(rec): _*)
+          case Implies(l, r) => z3.mkImplies(rec(l), rec(r))
+          case Not(Equals(l, r)) => z3.mkDistinct(rec(l), rec(r))
+          case Not(e) => z3.mkNot(rec(e))
+          case IntLiteral(v) => z3.mkInt(v, typeToSort(Int32Type))
+          case InfiniteIntegerLiteral(v) => z3.mkNumeral(v.toString, typeToSort(IntegerType))
+          case FractionalLiteral(n, d) => z3.mkNumeral(s"$n / $d", typeToSort(RealType))
+          case CharLiteral(c) => z3.mkInt(c, typeToSort(CharType))
+          case BooleanLiteral(v) => if (v) z3.mkTrue() else z3.mkFalse()
+          case Equals(l, r) => z3.mkEq(rec( l ), rec( r ) )
+          case Plus(l, r) => z3.mkAdd(rec(l), rec(r))
+          case Minus(l, r) => z3.mkSub(rec(l), rec(r))
+          case Times(l, r) => z3.mkMul(rec(l), rec(r))
+          case Division(l, r) => {
+            val rl = rec(l)
+            val rr = rec(r)
+            z3.mkITE(
+              z3.mkGE(rl, z3.mkNumeral("0", typeToSort(IntegerType))),
+              z3.mkDiv(rl, rr),
+              z3.mkUnaryMinus(z3.mkDiv(z3.mkUnaryMinus(rl), rr))
+            )
+          }
+          case Remainder(l, r) => {
+            val q = rec(Division(l, r))
+            z3.mkSub(rec(l), z3.mkMul(rec(r), q))
+          }
+          case Modulo(l, r) => {
+            z3.mkMod(rec(l), rec(r))
+          }
+          case UMinus(e) => z3.mkUnaryMinus(rec(e))
+    
+          case RealPlus(l, r) => z3.mkAdd(rec(l), rec(r))
+          case RealMinus(l, r) => z3.mkSub(rec(l), rec(r))
+          case RealTimes(l, r) => z3.mkMul(rec(l), rec(r))
+          case RealDivision(l, r) => z3.mkDiv(rec(l), rec(r))
+          case RealUMinus(e) => z3.mkUnaryMinus(rec(e))
+    
+          case BVPlus(l, r) => z3.mkBVAdd(rec(l), rec(r))
+          case BVMinus(l, r) => z3.mkBVSub(rec(l), rec(r))
+          case BVTimes(l, r) => z3.mkBVMul(rec(l), rec(r))
+          case BVDivision(l, r) => z3.mkBVSdiv(rec(l), rec(r))
+          case BVRemainder(l, r) => z3.mkBVSrem(rec(l), rec(r))
+          case BVUMinus(e) => z3.mkBVNeg(rec(e))
+          case BVNot(e) => z3.mkBVNot(rec(e))
+          case BVAnd(l, r) => z3.mkBVAnd(rec(l), rec(r))
+          case BVOr(l, r) => z3.mkBVOr(rec(l), rec(r))
+          case BVXOr(l, r) => z3.mkBVXor(rec(l), rec(r))
+          case BVShiftLeft(l, r) => z3.mkBVShl(rec(l), rec(r))
+          case BVAShiftRight(l, r) => z3.mkBVAshr(rec(l), rec(r))
+          case BVLShiftRight(l, r) => z3.mkBVLshr(rec(l), rec(r))
+          case LessThan(l, r) => l.getType match {
+            case IntegerType => z3.mkLT(rec(l), rec(r))
+            case RealType => z3.mkLT(rec(l), rec(r))
+            case Int32Type => z3.mkBVSlt(rec(l), rec(r))
+            case CharType => z3.mkBVSlt(rec(l), rec(r))
+          }
+          case LessEquals(l, r) => l.getType match {
+            case IntegerType => z3.mkLE(rec(l), rec(r))
+            case RealType => z3.mkLE(rec(l), rec(r))
+            case Int32Type => z3.mkBVSle(rec(l), rec(r))
+            case CharType => z3.mkBVSle(rec(l), rec(r))
+            //case _ => throw new IllegalStateException(s"l: $l, Left type: ${l.getType} Expr: $ex")
+          }
+          case GreaterThan(l, r) => l.getType match {
+            case IntegerType => z3.mkGT(rec(l), rec(r))
+            case RealType => z3.mkGT(rec(l), rec(r))
+            case Int32Type => z3.mkBVSgt(rec(l), rec(r))
+            case CharType => z3.mkBVSgt(rec(l), rec(r))
+          }
+          case GreaterEquals(l, r) => l.getType match {
+            case IntegerType => z3.mkGE(rec(l), rec(r))
+            case RealType => z3.mkGE(rec(l), rec(r))
+            case Int32Type => z3.mkBVSge(rec(l), rec(r))
+            case CharType => z3.mkBVSge(rec(l), rec(r))
+          }
+          
+          case StringConverted(result) =>
+            result
+    
+          case u : UnitLiteral =>
+            val tpe = normalizeType(u.getType)
+            typeToSort(tpe)
+            val constructor = constructors.toB(tpe)
+            constructor()
+    
+          case t @ Tuple(es) =>
+            val tpe = normalizeType(t.getType)
+            typeToSort(tpe)
+            val constructor = constructors.toB(tpe)
+            constructor(es.map(rec): _*)
+    
+          case ts @ TupleSelect(t, i) =>
+            val tpe = normalizeType(t.getType)
+            typeToSort(tpe)
+            val selector = selectors.toB((tpe, i-1))
+            selector(rec(t))
+    
+          case c @ CaseClass(ct, args) =>
+            typeToSort(ct) // Making sure the sort is defined
+            val constructor = constructors.toB(ct)
+            constructor(args.map(rec): _*)
+    
+          case c @ CaseClassSelector(cct, cc, sel) =>
+            typeToSort(cct) // Making sure the sort is defined
+            val selector = selectors.toB(cct, c.selectorIndex)
+            selector(rec(cc))
+    
+          case AsInstanceOf(expr, ct) =>
+            rec(expr)
+    
+          case IsInstanceOf(e, act: AbstractClassType) =>
+            act.knownCCDescendants match {
+              case Seq(cct) =>
+                rec(IsInstanceOf(e, cct))
+              case more =>
+                val i = FreshIdentifier("e", act, alwaysShowUniqueID = true)
+                rec(Let(i, e, orJoin(more map(IsInstanceOf(Variable(i), _)))))
+            }
+    
+          case IsInstanceOf(e, cct: CaseClassType) =>
+            typeToSort(cct) // Making sure the sort is defined
+            val tester = testers.toB(cct)
+            tester(rec(e))
+    
+          case al @ ArraySelect(a, i) =>
+            val tpe = normalizeType(a.getType)
+    
+            val sa = rec(a)
+            val content = selectors.toB((tpe, 1))(sa)
+    
+            z3.mkSelect(content, rec(i))
+    
+          case al @ ArrayUpdated(a, i, e) =>
+            val tpe = normalizeType(a.getType)
+    
+            val sa = rec(a)
+            val ssize    = selectors.toB((tpe, 0))(sa)
+            val scontent = selectors.toB((tpe, 1))(sa)
+    
+            val newcontent = z3.mkStore(scontent, rec(i), rec(e))
+    
+            val constructor = constructors.toB(tpe)
+    
+            constructor(ssize, newcontent)
+    
+          case al @ ArrayLength(a) =>
+            val tpe = normalizeType(a.getType)
+            val sa = rec(a)
+            selectors.toB((tpe, 0))(sa)
+    
+          case arr @ FiniteArray(elems, oDefault, length) =>
+            val at @ ArrayType(base) = normalizeType(arr.getType)
+            typeToSort(at)
+    
+            val default = oDefault.getOrElse(simplestValue(base))
+    
+            val ar = rec(RawArrayValue(Int32Type, elems.map {
+              case (i, e) => IntLiteral(i) -> e
+            }, default))
+    
+            constructors.toB(at)(rec(length), ar)
+    
+          case f @ FunctionInvocation(tfd, args) =>
+            z3.mkApp(functionDefToDecl(tfd), args.map(rec): _*)
+    
+          case fa @ Application(caller, args) =>
+            val ft @ FunctionType(froms, to) = normalizeType(caller.getType)
+            val funDecl = lambdas.cachedB(ft) {
+              val sortSeq    = (ft +: froms).map(tpe => typeToSort(tpe))
+              val returnSort = typeToSort(to)
+    
+              val name = FreshIdentifier("dynLambda").uniqueName
+              z3.mkFreshFuncDecl(name, sortSeq, returnSort)
+            }
+            z3.mkApp(funDecl, (caller +: args).map(rec): _*)
+    
+          case ElementOfSet(e, s) => z3.mkSetMember(rec(e), rec(s))
+          case SubsetOf(s1, s2) => z3.mkSetSubset(rec(s1), rec(s2))
+          case SetIntersection(s1, s2) => z3.mkSetIntersect(rec(s1), rec(s2))
+          case SetUnion(s1, s2) => z3.mkSetUnion(rec(s1), rec(s2))
+          case SetDifference(s1, s2) => z3.mkSetDifference(rec(s1), rec(s2))
+          case f @ FiniteSet(elems, base) => elems.foldLeft(z3.mkEmptySet(typeToSort(base)))((ast, el) => z3.mkSetAdd(ast, rec(el)))
+    
+          case RawArrayValue(keyTpe, elems, default) =>
+            val ar = z3.mkConstArray(typeToSort(keyTpe), rec(default))
+    
+            elems.foldLeft(ar) {
+              case (array, (k, v)) => z3.mkStore(array, rec(k), rec(v))
+            }
+    
+          /**
+           * ===== Map operations =====
+           */
+          case m @ FiniteMap(elems, from, to) =>
+            val MapType(_, t) = normalizeType(m.getType)
+    
+            rec(RawArrayValue(from, elems.map{
+              case (k, v) => (k, CaseClass(library.someType(t), Seq(v)))
+            }.toMap, CaseClass(library.noneType(t), Seq())))
+    
+          case MapApply(m, k) =>
+            val mt @ MapType(_, t) = normalizeType(m.getType)
+            typeToSort(mt)
+    
+            val el = z3.mkSelect(rec(m), rec(k))
+    
+            // Really ?!? We don't check that it is actually != None?
+            selectors.toB(library.someType(t), 0)(el)
+    
+          case MapIsDefinedAt(m, k) =>
+            val mt @ MapType(_, t) = normalizeType(m.getType)
+            typeToSort(mt)
+    
+            val el = z3.mkSelect(rec(m), rec(k))
+    
+            testers.toB(library.someType(t))(el)
+    
+          case MapUnion(m1, FiniteMap(elems, _, _)) =>
+            val mt @ MapType(_, t) = normalizeType(m1.getType)
+            typeToSort(mt)
+    
+            elems.foldLeft(rec(m1)) { case (m, (k,v)) =>
+              z3.mkStore(m, rec(k), rec(CaseClass(library.someType(t), Seq(v))))
+            }
+    
+    
+          case gv @ GenericValue(tp, id) =>
+            z3.mkApp(genericValueToDecl(gv))
+    
+          case other =>
+            unsupported(other)
         }
-
-
-      case gv @ GenericValue(tp, id) =>
-        z3.mkApp(genericValueToDecl(gv))
-
-      case other =>
-        unsupported(other)
-    }
-
-    rec(expr)
+     }.rec(expr)
   }
 
   protected[leon] def fromZ3Formula(model: Z3Model, tree: Z3AST, tpe: TypeTree): Expr = {
-
-    def rec(t: Z3AST, tpe: TypeTree): Expr = {
+    def rec(t: Z3AST, expected_tpe: TypeTree): Expr = {
       val kind = z3.getASTKind(t)
-      kind match {
+      val tpe = Z3StringTypeConversion.convert(expected_tpe)(program)
+      val res = kind match {
         case Z3NumeralIntAST(Some(v)) =>
           val leading = t.toString.substring(0, 2 min t.toString.length)
           if(leading == "#x") {
@@ -758,6 +769,11 @@ trait AbstractZ3Solver extends Solver {
           }
         case _ => unsound(t, "unexpected AST")
       }
+      expected_tpe match {
+        case StringType =>
+          StringLiteral(Z3StringTypeConversion.convertToString(res)(program))
+        case _ => res
+      }
     }
 
     rec(tree, normalizeType(tpe))
@@ -774,7 +790,8 @@ trait AbstractZ3Solver extends Solver {
   }
 
   def idToFreshZ3Id(id: Identifier): Z3AST = {
-    z3.mkFreshConst(id.uniqueName, typeToSort(id.getType))
+    val correctType = Z3StringTypeConversion.convert(id.getType)(program)
+    z3.mkFreshConst(id.uniqueName, typeToSort(correctType))
   }
 
   def reset() = {
diff --git a/src/main/scala/leon/solvers/z3/Z3StringConversion.scala b/src/main/scala/leon/solvers/z3/Z3StringConversion.scala
new file mode 100644
index 0000000000000000000000000000000000000000..3daf1ad4964ad73e8c4d9701ae4e65d0f4170897
--- /dev/null
+++ b/src/main/scala/leon/solvers/z3/Z3StringConversion.scala
@@ -0,0 +1,94 @@
+package leon
+package solvers
+package z3
+
+import purescala.Common._
+import purescala.Expressions._
+import purescala.Constructors._
+import purescala.Types._
+import purescala.Definitions._
+import _root_.smtlib.parser.Terms.{Identifier => SMTIdentifier, _}
+import _root_.smtlib.parser.Commands.{FunDef => SMTFunDef, _}
+import _root_.smtlib.interpreters.Z3Interpreter
+import _root_.smtlib.theories.Core.{Equals => SMTEquals, _}
+import _root_.smtlib.theories.ArraysEx
+import leon.utils.Bijection
+
+object Z3StringTypeConversion {
+  def convert(t: TypeTree)(implicit p: Program) = new Z3StringTypeConversion { def getProgram = p }.convertType(t)
+  def convertToString(e: Expr)(implicit p: Program) = new Z3StringTypeConversion{ def getProgram = p }.convertToString(e)
+}
+
+trait Z3StringTypeConversion {
+  val stringBijection = new Bijection[String, Expr]()
+  
+  lazy val conschar = program.lookupCaseClass("leon.collection.Cons") match {
+    case Some(cc) => cc.typed(Seq(CharType))
+    case _ => throw new Exception("Could not find Cons in Z3 solver")
+  }
+  lazy val nilchar = program.lookupCaseClass("leon.collection.Nil") match {
+    case Some(cc) => cc.typed(Seq(CharType))
+    case _ => throw new Exception("Could not find Nil in Z3 solver")
+  }
+  lazy val listchar = program.lookupAbstractClass("leon.collection.List") match {
+    case Some(cc) => cc.typed(Seq(CharType))
+    case _ => throw new Exception("Could not find List in Z3 solver")
+  }
+  def lookupFunDef(s: String): FunDef = program.lookupFunDef(s) match {
+    case Some(fd) => fd
+    case _ => throw new Exception("Could not find function "+s+" in program")
+  }
+  lazy val list_size = lookupFunDef("leon.collection.List.size").typed(Seq(CharType))
+  lazy val list_++ = lookupFunDef("leon.collection.List.++").typed(Seq(CharType))
+  lazy val list_take = lookupFunDef("leon.collection.List.take").typed(Seq(CharType))
+  lazy val list_drop = lookupFunDef("leon.collection.List.drop").typed(Seq(CharType))
+  lazy val list_slice = lookupFunDef("leon.collection.List.slice").typed(Seq(CharType))
+  
+  private lazy val program = getProgram
+  
+  def getProgram: Program
+  
+  def convertType(t: TypeTree): TypeTree = t match {
+    case StringType => listchar
+    case _ => t
+  }
+  def convertToString(e: Expr)(implicit p: Program): String  = 
+    stringBijection.cachedA(e) {
+      e match {
+        case CaseClass(_, Seq(CharLiteral(c), l)) => c + convertToString(l)
+        case CaseClass(_, Seq()) => ""
+      }
+    }
+  def convertFromString(v: String) =
+    stringBijection.cachedB(v) {
+      v.toList.foldRight(CaseClass(nilchar, Seq())){
+        case (char, l) => CaseClass(conschar, Seq(CharLiteral(char), l))
+      }
+    }
+}
+
+trait Z3StringConversion[TargetType] extends Z3StringTypeConversion {
+  def convertToTarget(e: Expr)(implicit bindings: Map[Identifier, TargetType]): TargetType
+  def targetApplication(fd: TypedFunDef, args: Seq[TargetType])(implicit bindings: Map[Identifier, TargetType]): TargetType
+  
+  object StringConverted {
+    def unapply(e: Expr)(implicit bindings: Map[Identifier, TargetType]): Option[TargetType] = e match {
+      case StringLiteral(v)          =>
+        // No string support for z3 at this moment.
+        val stringEncoding = convertFromString(v)
+        Some(convertToTarget(stringEncoding))
+      case StringLength(a)           =>
+        Some(targetApplication(list_size, Seq(convertToTarget(a))))
+      case StringConcat(a, b)        =>
+        Some(targetApplication(list_++, Seq(convertToTarget(a), convertToTarget(b))))
+      case SubString(a, start, Plus(start2, length)) if start == start2  =>
+        Some(targetApplication(list_take,
+            Seq(targetApplication(list_drop, Seq(convertToTarget(a), convertToTarget(start))), convertToTarget(length))))
+      case SubString(a, start, end)  => 
+        Some(targetApplication(list_slice, Seq(convertToTarget(a), convertToTarget(start), convertToTarget(end))))
+      case _ => None
+    }
+    
+    def apply(t: TypeTree): TypeTree = convertType(t)
+  }
+}
\ No newline at end of file
diff --git a/src/main/scala/leon/utils/Library.scala b/src/main/scala/leon/utils/Library.scala
index 4d100210911734504a96bd005d0299ae0f1b8906..0ddd21078ffe772986bd5487d964d352184cd2e6 100644
--- a/src/main/scala/leon/utils/Library.scala
+++ b/src/main/scala/leon/utils/Library.scala
@@ -16,7 +16,6 @@ case class Library(pgm: Program) {
   lazy val Some   = lookup("leon.lang.Some").collectFirst { case ccd : CaseClassDef => ccd }
   lazy val None   = lookup("leon.lang.None").collectFirst { case ccd : CaseClassDef => ccd }
 
-  //lazy val String = lookup("leon.lang.string.String").collectFirst { case ccd : CaseClassDef => ccd }
   lazy val StrOps = lookup("leon.lang.StrOps").collectFirst { case md: ModuleDef => md }
 
   lazy val Dummy  = lookup("leon.lang.Dummy").collectFirst { case ccd : CaseClassDef => ccd }
diff --git a/src/test/scala/leon/integration/solvers/SolversSuite.scala b/src/test/scala/leon/integration/solvers/SolversSuite.scala
index 24ebf35916d9abce077fdd7d8ee5752fd3c1e0d3..d568e471f08eb4cf1a558675419daabd9e9c940a 100644
--- a/src/test/scala/leon/integration/solvers/SolversSuite.scala
+++ b/src/test/scala/leon/integration/solvers/SolversSuite.scala
@@ -72,13 +72,13 @@ class SolversSuite extends LeonTestSuiteWithProgram {
             val model = solver.getModel
             for (v <- vs) {
               if (model.isDefinedAt(v.id)) {
-                assert(model(v.id).getType === v.getType, "Extracting value of type "+v.getType)
+                assert(model(v.id).getType === v.getType, s"Solver $solver - Extracting value of type "+v.getType)
               } else {
-                fail("Model does not contain "+v.id+" of type "+v.getType)
+                fail(s"Solver $solver - Model does not contain "+v.id.uniqueName+" of type "+v.getType)
               }
             }
           case _ =>
-            fail("Constraint "+cnstr.asString+" is unsat!?")
+            fail(s"Solver $solver - Constraint "+cnstr.asString+" is unsat!?")
         }
       } finally {
         solver.free()
diff --git a/src/test/scala/leon/integration/solvers/StringSolverSuite.scala b/src/test/scala/leon/integration/solvers/StringSolverSuite.scala
index d64df7f8c43b1f5f77bb93bce85d8a69cbf230ed..7c0d3e13c044f4cd2491041cf28319986a6df42b 100644
--- a/src/test/scala/leon/integration/solvers/StringSolverSuite.scala
+++ b/src/test/scala/leon/integration/solvers/StringSolverSuite.scala
@@ -199,7 +199,6 @@ class StringSolverSuite extends FunSuite with Matchers with ScalaFutures {
     val solution = solve(problem) 
     solution should not be 'empty
     val firstSolution = solution(0)
-    println("First solution " + firstSolution)
     firstSolution(idMap("const8")) should equal("List(")
     firstSolution(idMap("const4")) should equal("")
   }
@@ -216,7 +215,6 @@ T2: internal
 T2: ret Pop() -> 5"""
     
     val problem: Problem = List(lhs === expected)
-    println("Problem to solve:" + StringSolver.renderProblem(problem))
     
     solve(problem) should not be 'empty
   }
diff --git a/src/test/scala/leon/regression/termination/TerminationSuite.scala b/src/test/scala/leon/regression/termination/TerminationSuite.scala
index c58a4b0aceab03a00257ed48429028412e9cf643..6c2df0820a2b0f0c19ee393c12e1d70b36bbf233 100644
--- a/src/test/scala/leon/regression/termination/TerminationSuite.scala
+++ b/src/test/scala/leon/regression/termination/TerminationSuite.scala
@@ -38,7 +38,7 @@ class TerminationSuite extends LeonRegressionSuite {
       "verification/purescala/valid/InductiveQuantification.scala"
     )
 
-    val t = if (ignored.exists(displayName.endsWith)) {
+    val t = if (ignored.exists(displayName.replaceAll("\\\\","/").endsWith)) {
       ignore _
     } else {
       test _
diff --git a/src/test/scala/leon/test/LeonRegressionSuite.scala b/src/test/scala/leon/test/LeonRegressionSuite.scala
index 58fdce2c6b789ddae0bbaee845f54ad6fe09de2c..4181fee97e7a4a38e3f30349458366ba62138d12 100644
--- a/src/test/scala/leon/test/LeonRegressionSuite.scala
+++ b/src/test/scala/leon/test/LeonRegressionSuite.scala
@@ -33,7 +33,7 @@ trait LeonRegressionSuite extends FunSuite with Timeouts {
         body
       } catch {
         case fe: LeonFatalError =>
-          throw new TestFailedException("Uncaught LeonFatalError", fe, 5)
+          throw new TestFailedException("Uncaught LeonFatalError" + fe.msg.map(": " + _).getOrElse(""), fe, 5)
       }
     }
   }
diff --git a/testcases/verification/case-studies/LambdaSound.scala b/testcases/verification/case-studies/LambdaSound.scala
index 6208d2039eaf16ba1dbeae614bf6432e2309ee1e..fa59efbc001614acbd338b83883248d07a736a2d 100644
--- a/testcases/verification/case-studies/LambdaSound.scala
+++ b/testcases/verification/case-studies/LambdaSound.scala
@@ -3,7 +3,6 @@ import leon.annotation._
 import leon.collection._
 import leon.lang.synthesis._
 import leon._
-import leon.lang.string._
 
 object Lambda {
   case class Id(v: BigInt)
diff --git a/testcases/verification/editor/AsciiToPos.scala b/testcases/verification/editor/AsciiToPos.scala
index 4ec536ce71c8f684dc1a2329c51de19cf575269f..1514ccc13733e6e3571a51081a89a2c490a72f30 100644
--- a/testcases/verification/editor/AsciiToPos.scala
+++ b/testcases/verification/editor/AsciiToPos.scala
@@ -1,6 +1,5 @@
 import leon.lang._
 import leon.lang.synthesis._
-import leon.lang.string._
 import leon.collection._
 
 object Justify {
@@ -14,7 +13,7 @@ object Justify {
         Cons(wordAcc, tokenize0(t, ""))
       }
     } else {
-      tokenize0(t, String(List(h)) + wordAcc)
+      tokenize0(t, h + wordAcc)
     }
   }
 
diff --git a/testcases/verification/higher-order/valid/MonadsException.scala b/testcases/verification/higher-order/valid/MonadsException.scala
index 2c80332435b1fb65653932fb93906d6540685e13..27c87d26177ef8c0d42f49766ab56a2c1e68b13c 100644
--- a/testcases/verification/higher-order/valid/MonadsException.scala
+++ b/testcases/verification/higher-order/valid/MonadsException.scala
@@ -1,5 +1,4 @@
 import leon.lang._
-import leon.lang.string._
 
 object TryMonad {
   
diff --git a/testcases/verification/monads/Freshen.scala b/testcases/verification/monads/Freshen.scala
index de8c7eda592ba211a948c4beb5f2925d6a53974f..6fe0ef38f7e673f4e0f9ffbee8bbf0e7e7a5eafa 100644
--- a/testcases/verification/monads/Freshen.scala
+++ b/testcases/verification/monads/Freshen.scala
@@ -6,7 +6,6 @@ import leon.lang._
 object Freshen {
 
   import State._
-  import leon.lang.string._
 
   case class Id(name: String, id: BigInt)
 
diff --git a/testcases/web/demos/005_Tutorial-Monad.scala b/testcases/web/demos/005_Tutorial-Monad.scala
index 093e4a2d805a9e8e3ee07dc79eb1adfecc81acdb..ba08a0e1f3f18af7c954c2a06b7c06cc26522369 100644
--- a/testcases/web/demos/005_Tutorial-Monad.scala
+++ b/testcases/web/demos/005_Tutorial-Monad.scala
@@ -1,4 +1,3 @@
-import leon.lang.string._
 import leon.annotation._
 
 sealed abstract class Outcome[T] {
diff --git a/testcases/web/synthesis/24_String_DoubleList.scala b/testcases/web/synthesis/24_String_DoubleList.scala
index 0d89d3f233b310f9968ba36206623b75bb44f7c7..652f5e4b84ed8837dc56cdce10393a480232c1b0 100644
--- a/testcases/web/synthesis/24_String_DoubleList.scala
+++ b/testcases/web/synthesis/24_String_DoubleList.scala
@@ -26,7 +26,7 @@ object DoubleListRender {
     (res : String) => (a, res) passes {
       case N() =>
         "[]"
-      case B(NN()) =>
+      case B(NN(), N()) =>
         "[()]"
     }
   }