diff --git a/src/main/scala/leon/purescala/CheckForalls.scala b/src/main/scala/leon/purescala/CheckForalls.scala
new file mode 100644
index 0000000000000000000000000000000000000000..600b0ea26e8831779af4418a9c325692870e5fde
--- /dev/null
+++ b/src/main/scala/leon/purescala/CheckForalls.scala
@@ -0,0 +1,93 @@
+/* Copyright 2009-2015 EPFL, Lausanne */
+
+package leon
+package purescala
+
+import Common._
+import Definitions._
+import Expressions._
+import Extractors._
+import ExprOps._
+
+object CheckForalls extends UnitPhase[Program] {
+  
+  val name = "Foralls"
+  val description = "Check syntax of foralls to guarantee sound instantiations"
+
+  def apply(ctx: LeonContext, program: Program) = {
+    program.definedFunctions.foreach { fd =>
+      if (fd.body.exists(b => exists {
+        case f: Forall => true
+        case _ => false
+      } (b))) ctx.reporter.warning("Universal quantification in function bodies is not supported in " + fd)
+
+      val foralls = (fd.precondition.toSeq ++ fd.postcondition.toSeq).flatMap { prec =>
+        collect[Forall] {
+          case f: Forall => Set(f)
+          case _ => Set.empty
+        } (prec)
+      }
+
+      val free = fd.params.map(_.id).toSet ++ (fd.postcondition match {
+        case Some(Lambda(args, _)) => args.map(_.id)
+        case _ => Seq.empty
+      })
+
+      object Matcher {
+        def unapply(e: Expr): Option[(Identifier, Seq[Expr])] = e match {
+          case Application(Variable(id), args) if free(id) => Some(id -> args)
+          case ArraySelect(Variable(id), index) if free(id) => Some(id -> Seq(index))
+          case MapGet(Variable(id), key) if free(id) => Some(id -> Seq(key))
+          case _ => None
+        }
+      }
+
+      for (Forall(args, TopLevelAnds(conjuncts)) <- foralls) {
+        val quantified = args.map(_.id).toSet
+
+        for (conjunct <- conjuncts) {
+          val matchers = collect[(Identifier, Seq[Expr])] {
+            case Matcher(id, args) => Set(id -> args)
+            case _ => Set.empty
+          } (conjunct)
+
+          if (matchers.exists { case (id, args) =>
+            args.exists(arg => arg match {
+              case Matcher(_, _) => false
+              case Variable(id) => false
+              case _ if (variablesOf(arg) & quantified).nonEmpty => true
+              case _ => false
+            })
+          }) ctx.reporter.warning("Matcher arguments must have simple form in " + conjunct)
+
+          if (matchers.map(_._1).toSet.size != 1)
+            ctx.reporter.warning("Quantification conjuncts must contain exactly one matcher in " + conjunct)
+
+          preTraversal {
+            case Matcher(_, _) => // OK
+            case LessThan(_: Variable, _: Variable) => // OK
+            case LessEquals(_: Variable, _: Variable) => // OK
+            case GreaterThan(_: Variable, _: Variable) => // OK
+            case GreaterEquals(_: Variable, _: Variable) => // OK
+            case And(_) => // OK
+            case Or(_) => // OK
+            case Implies(_, _) => // OK
+            case BinaryOperator(Matcher(_, _), _, _) => // OK
+            case BinaryOperator(_, Matcher(_, _), _) => // OK
+            case BinaryOperator(e1, _, _) if (variablesOf(e1) & quantified).isEmpty => // OK
+            case BinaryOperator(_, e2, _) if (variablesOf(e2) & quantified).isEmpty => // OK
+            case FunctionInvocation(_, args) if {
+              val argVars = args.flatMap(variablesOf).toSet
+              (argVars & quantified).size <= 1 && (argVars & free).isEmpty
+            } => // OK
+            case UnaryOperator(_, _) => // OK
+            case BinaryOperator(e1, e2, _) if ((variablesOf(e1) ++ variablesOf(e2)) & quantified).isEmpty => // OK
+            case NAryOperator(es, _) if (es.flatMap(variablesOf).toSet & quantified).isEmpty => // OK
+            case _: Terminal => // OK
+            case e => ctx.reporter.warning("Invalid operation " + e + " on quantified variables")
+          } (conjunct)
+        }
+      }
+    }
+  }
+}
diff --git a/src/main/scala/leon/solvers/templates/QuantificationManager.scala b/src/main/scala/leon/solvers/templates/QuantificationManager.scala
index 3bb4374bdb3ca46e49f2b5742a080b7b783b52da..9d19ea839601d631fe7210786c1c9d49894503af 100644
--- a/src/main/scala/leon/solvers/templates/QuantificationManager.scala
+++ b/src/main/scala/leon/solvers/templates/QuantificationManager.scala
@@ -94,6 +94,10 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
 
   private var knownStack: List[Set[T]] = List(Set.empty)
   private def known(idT: T): Boolean = knownStack.head(idT) || byID.isDefinedAt(idT)
+  private def correspond(qm: Matcher[T], m: Matcher[T]): Boolean = qm.tpe match {
+    case _: FunctionType => qm.tpe == m.tpe && (qm.caller == m.caller || !known(m.caller))
+    case _ => qm.tpe == m.tpe
+  }
 
   override def push(): Unit = {
     quantificationsStack = quantifications :: quantificationsStack
@@ -156,7 +160,6 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
     }
 
     def instantiate(blocker: T, matcher: Matcher[T]): Instantiation[T] = {
-      val Matcher(caller, tpe, args) = matcher
 
       // Build a mapping from applications in the quantified statement to all potential concrete
       // applications previously encountered. Also make sure the current `app` is in the mapping
@@ -165,25 +168,21 @@ class QuantificationManager[T](encoder: TemplateEncoder[T]) extends LambdaManage
       val matcherMappings: Set[Set[(T, Matcher[T], Matcher[T])]] = matchers
         // 1. select an application in the quantified proposition for which the current app can
         //    be bound when generating the new constraints
-        .filter(_.tpe == tpe)
+        .filter(qm => correspond(qm, matcher))
         // 2. build the instantiation mapping associated to the chosen current application binding
         .flatMap { bindingMatcher => matchers
           // 2.1. select all potential matches for each quantified application
-          .map { case qm @ Matcher(qcaller, qtpe, qargs) =>
-            if (qm == bindingMatcher) {
-              bindingMatcher -> Set(blocker -> matcher)
-            } else {
-              val instances: Set[(T, Matcher[T])] = instantiated.filter {
-                case (b, m @ Matcher(caller, tpe, _)) => tpe == qtpe
-              }
-
-              // concrete applications can appear multiple times in the constraint, and this is also the case
-              // for the current application for which we are generating the constraints
-              val withCurrent = if (tpe == qtpe) instances + (blocker -> matcher) else instances
-
-              qm -> withCurrent
-            }
-          }
+          .map(qm => if (qm == bindingMatcher) {
+            bindingMatcher -> Set(blocker -> matcher)
+          } else {
+            val instances: Set[(T, Matcher[T])] = instantiated.filter { case (b, m) => correspond(qm, m) }
+
+            // concrete applications can appear multiple times in the constraint, and this is also the case
+            // for the current application for which we are generating the constraints
+            val withCurrent = if (correspond(qm, matcher)) instances + (blocker -> matcher) else instances
+
+            qm -> withCurrent
+          })
           // 2.2. based on the possible bindings for each quantified application, build a set of
           //      instantiation mappings that can be used to instantiate all necessary constraints
           .foldLeft[Set[Set[(T, Matcher[T], Matcher[T])]]] (Set(Set.empty)) {
diff --git a/src/main/scala/leon/solvers/templates/Templates.scala b/src/main/scala/leon/solvers/templates/Templates.scala
index 376c411c2fcbb9fbfc53be6549ae60f624c34cc0..d727a2b9f0000eb17fe6b1173e7cdab07dc225ef 100644
--- a/src/main/scala/leon/solvers/templates/Templates.scala
+++ b/src/main/scala/leon/solvers/templates/Templates.scala
@@ -126,6 +126,8 @@ object Template {
 
   private def matchersOf[T](encodeExpr: Expr => T)(expr: Expr): Set[Matcher[T]] = collect[Matcher[T]] {
     case Application(caller, args) => Set(Matcher(encodeExpr(caller), caller.getType, args.map(encodeExpr)))
+    case ArraySelect(arr, index) => Set(Matcher(encodeExpr(arr), arr.getType, Seq(encodeExpr(index))))
+    case MapGet(map, key) => Set(Matcher(encodeExpr(map), map.getType, Seq(encodeExpr(key))))
     case _ => Set.empty
   }(expr)
 
diff --git a/src/main/scala/leon/utils/PreprocessingPhase.scala b/src/main/scala/leon/utils/PreprocessingPhase.scala
index fb08be9ce3bc4426997c64ae00f2a1b77fcb727a..7c91fa436fd5e804fb35830e113913264e27d235 100644
--- a/src/main/scala/leon/utils/PreprocessingPhase.scala
+++ b/src/main/scala/leon/utils/PreprocessingPhase.scala
@@ -34,7 +34,8 @@ class PreprocessingPhase(private val desugarXLang: Boolean = false) extends Tran
       CompleteAbstractDefinitions            andThen
       CheckADTFieldsTypes                    andThen
       InjectAsserts                          andThen
-      InliningPhase
+      InliningPhase                          andThen
+      CheckForalls
 
     val pipeX = if(desugarXLang) {
       XLangDesugaringPhase andThen