diff --git a/src/main/scala/leon/evaluators/AbstractEvaluator.scala b/src/main/scala/leon/evaluators/AbstractEvaluator.scala
index 23236cb7317ecc048271094f092109722a09f889..2b8baa99424dbd7de9d4d2c4d87c82293e4de2b1 100644
--- a/src/main/scala/leon/evaluators/AbstractEvaluator.scala
+++ b/src/main/scala/leon/evaluators/AbstractEvaluator.scala
@@ -7,6 +7,7 @@ import purescala.Extractors.Operator
 import purescala.Constructors._
 import purescala.Expressions._
 import purescala.Types._
+import purescala.Common.Identifier
 import purescala.Definitions.{TypedFunDef, Program}
 import purescala.DefOps
 import purescala.TypeOps
@@ -14,10 +15,37 @@ import purescala.ExprOps
 import purescala.Expressions.Expr
 import leon.utils.DebugSectionSynthesis
 
+case class AbstractRecContext(mappings: Map[Identifier, Expr], mappingsAbstract: Map[Identifier, Expr]) extends RecContext[AbstractRecContext] {
+  def newVars(news: Map[Identifier, Expr], newsAbstract: Map[Identifier, Expr]): AbstractRecContext = copy(news, newsAbstract)
+  def newVars(news: Map[Identifier, Expr]): AbstractRecContext = copy(news, news)
+  
+  def withNewVar(id: Identifier, v: (Expr, Expr)): AbstractRecContext = {
+    newVars(mappings + (id -> v._1), mappingsAbstract + (id -> v._2))
+  }
+
+  def withNewVars2(news: Map[Identifier, (Expr, Expr)]): AbstractRecContext = {
+    newVars(mappings ++ news.mapValues(_._1), mappingsAbstract ++ news.mapValues(_._2))
+  }
+  
+  override def withNewVar(id: Identifier, v: Expr): AbstractRecContext = {
+    newVars(mappings + (id -> v), mappingsAbstract + (id -> v))
+  }
+  
+  override def withNewVars(news: Map[Identifier, Expr]): AbstractRecContext = {
+    newVars(mappings ++ news, mappingsAbstract ++ news)
+  }
+}
+
+
+trait HasAbstractRecContext extends ContextualEvaluator {
+  type RC = AbstractRecContext
+  def initRC(mappings: Map[Identifier, Expr]) = AbstractRecContext(mappings, mappings)
+}
+
 /** The evaluation returns a pair (e, t),
  *  where e is the expression evaluated as much as possible, and t is the way the expression has been evaluated.
  *  Caution: If and Match statement require the condition to be non-abstract. */
-class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvaluator(ctx, prog, 50000) with HasDefaultGlobalContext with HasDefaultRecContext {
+class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvaluator(ctx, prog, 50000) with HasDefaultGlobalContext with HasAbstractRecContext {
   lazy val scalaEv = new ScalacEvaluator(underlying, ctx, prog)
   
   /** Evaluates resuts which can be evaluated directly
@@ -26,14 +54,21 @@ class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvalu
   underlying.setEvaluationFailOnChoose(true)
   override type Value = (Expr, Expr)
 
-  override val description: String = "Evaluates string programs but keeps the formula which generated the string"
-  override val name: String = "String Tracing evaluator"
-
-  protected def e(expr: Expr)(implicit rctx: RC, gctx: GC): (Expr, Expr) = expr match {
+  override val description: String = "Evaluates string programs but keeps the formula which generated the value"
+  override val name: String = "Abstract evaluator"
+ 
+  
+  protected def e(expr: Expr)(implicit rctx: RC, gctx: GC): (Expr, Expr) = {
+    implicit def aToC: AbstractEvaluator.this.underlying.RC = DefaultRecContext(rctx.mappings)
+    expr match {
     case Variable(id) =>
-      rctx.mappings.get(id) match {
-        case Some(v) if v != expr =>
+      (rctx.mappings.get(id), rctx.mappingsAbstract.get(id)) match {
+        case (Some(v), None) if v != expr => // We further evaluate v to make sure it is a value
           e(v)
+        case (Some(v), Some(va)) if v != expr =>
+          (e(v)._1, va)
+        case (Some(v), Some(va)) =>
+          (v, va)
         case _ =>
           (expr, expr)
       }
@@ -53,12 +88,11 @@ class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvalu
       
     case MatchExpr(scrut, cases) =>
       val (escrut, tscrut) = e(scrut)
-      val rscrut = escrut
-      cases.toStream.map(c => underlying.matchesCase(rscrut, c)).find(_.nonEmpty) match {
+      cases.toStream.map(c => underlying.matchesCase(escrut, c)).find(_.nonEmpty) match {
         case Some(Some((c, mappings))) =>
           e(c.rhs)(rctx.withNewVars(mappings), gctx)
         case _ =>
-          throw RuntimeError("MatchError(Abstract evaluation): "+rscrut.asString+" did not match any of the cases :\n" + cases.mkString("\n"))
+          throw RuntimeError("MatchError(Abstract evaluation): "+escrut.asString+" did not match any of the cases :\n" + cases.mkString("\n"))
       }
 
     case FunctionInvocation(tfd, args) =>
@@ -88,6 +122,9 @@ class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvalu
         }
       }
       callResult
+    case Let(i, ex, b) =>
+      val (first, second) = e(ex)
+      e(b)(rctx.withNewVar(i, (first, second)), gctx)
     case Operator(es, builder) =>
       val (ees, ts) = es.map(e).unzip
       if(ees forall ExprOps.isValue) {
@@ -95,6 +132,7 @@ class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvalu
       } else {
         (builder(ees), builder(ts))
       }
+    }
   }
 
 
diff --git a/src/test/scala/leon/integration/evaluators/AbstractEvaluatorSuite.scala b/src/test/scala/leon/integration/evaluators/AbstractEvaluatorSuite.scala
new file mode 100644
index 0000000000000000000000000000000000000000..99678f887250e717f6cbb24071240c03c38f7ba1
--- /dev/null
+++ b/src/test/scala/leon/integration/evaluators/AbstractEvaluatorSuite.scala
@@ -0,0 +1,92 @@
+/* Copyright 2009-2016 EPFL, Lausanne */
+
+package leon.integration.evaluators
+
+import leon.test._
+import helpers.ExpressionsDSLProgram
+import leon.evaluators._
+import leon.purescala.Definitions._
+import leon.purescala.Expressions._
+import leon.purescala.Types._
+import org.scalatest.Matchers
+
+class AbstractEvaluatorSuite  extends LeonTestSuiteWithProgram with ExpressionsDSLProgram with Matchers {
+  //override def a = super[ExpressionsDSL].a
+  
+  val sources = List("""
+import leon.lang._
+
+object AbstractTests {
+  abstract class Tree
+  case class Node(w: Tree, x: Int, y: Tree) extends Tree
+  case class Leaf() extends Tree
+
+  def param(x: String) = x + x
+ 
+  def test() = {
+    val x = "19"
+    val w = 9
+    val y = w*w+5
+    val z = y.toString
+    val res = param(x) + z
+    res
+  }
+  
+  def test2(right: Boolean, c: Tree): Int = {
+    if(right) {
+      c match {
+        case Leaf() => 0
+        case Node(_, a, Leaf()) => a
+        case Node(_, _, n) => test2(right, n)
+      }
+    } else {
+      c match {
+        case Leaf() => 0
+        case Node(Leaf(), a, _) => a
+        case Node(n, _, _) => test2(right, n)
+      }
+    }
+  }
+}""")
+  
+  test("Abstract evaluator should keep track of variables") { implicit fix =>
+    val testFd = funDef("AbstractTests.test")
+
+    val ae = new AbstractEvaluator(fix._1, fix._2)
+    
+    val res = ae.eval(FunctionInvocation(testFd.typed, Seq()))
+    
+    res.result match {
+      case Some((e, expr)) =>
+        e should equal (StringLiteral("191986"))
+        expr should equal (StringConcat(StringConcat(StringLiteral("19"), StringLiteral("19")), Int32ToString(BVPlus(BVTimes(IntLiteral(9), IntLiteral(9)), IntLiteral(5)))))
+      case None =>
+        fail("No result!")
+    }
+  }
+  
+  test("Abstract evaluator should correctly handle boolean and recursive") { implicit fix =>
+    val testFd = funDef("AbstractTests.test2")
+    val Leaf = cc("AbstractTests.Leaf")()
+    def Node(left: Expr, n: Expr, right: Expr) = cc("AbstractTests.Node")(left, n, right)
+    
+    val ae = new AbstractEvaluator(fix._1, fix._2)
+    
+    val res = ae.eval(FunctionInvocation(testFd.typed, Seq(BooleanLiteral(true), Node(Leaf, IntLiteral(5), Leaf)))).result match {
+      case Some((e, expr)) =>
+        e should equal (IntLiteral(5))
+        expr should equal (IntLiteral(5))
+      case None =>
+        fail("No result!")
+    }
+    val a = id("a", Int32Type)
+    ae.eval(FunctionInvocation(testFd.typed, Seq(BooleanLiteral(true), Node(Leaf, Variable(a), Leaf)))).result match {
+      case Some((e, expr)) =>
+        e should equal (Variable(a))
+        expr should equal (Variable(a))
+      case None =>
+        fail("No result!")
+    }
+  }
+    
+}
\ No newline at end of file
diff --git a/src/test/scala/leon/test/helpers/ExpressionsDSL.scala b/src/test/scala/leon/test/helpers/ExpressionsDSL.scala
index fa118cbcc94a14bce81ffdacd9af4c5f154f8c6e..63469ead59c6c4441ce12a92fc92c4349ae99d5b 100644
--- a/src/test/scala/leon/test/helpers/ExpressionsDSL.scala
+++ b/src/test/scala/leon/test/helpers/ExpressionsDSL.scala
@@ -9,9 +9,7 @@ import leon.purescala.Common._
 import leon.purescala.Types._
 import leon.purescala.Expressions._
 
-trait ExpressionsDSL {
-  self: Assertions =>
-
+trait ExpressionsDSLVariables {
   val F = BooleanLiteral(false)
   val T = BooleanLiteral(true)
 
@@ -35,6 +33,11 @@ trait ExpressionsDSL {
   val p = FreshIdentifier("p", BooleanType).toVariable
   val q = FreshIdentifier("q", BooleanType).toVariable
   val r = FreshIdentifier("r", BooleanType).toVariable
+}
+
+trait ExpressionsDSLProgram {
+self: Assertions =>
+
 
   def id(name: String, tpe: TypeTree)(implicit pgm: Program): Identifier = {
     FreshIdentifier(name, tpe)
@@ -93,3 +96,8 @@ trait ExpressionsDSL {
     FunctionInvocation(tfd, args.toSeq)
   }
 }
+
+trait ExpressionsDSL extends ExpressionsDSLVariables with ExpressionsDSLProgram {
+  self: Assertions =>
+  
+}