From 572d4125135deea75f0cf3683fc40c750dac5162 Mon Sep 17 00:00:00 2001
From: Manos Koukoutos <emmanouil.koukoutos@epfl.ch>
Date: Wed, 3 Feb 2016 19:15:39 +0100
Subject: [PATCH] Improve value generation with generic types

ValueGrammar only generates one generic value.
GrammarDataGen will expand to all non-redundant value combinations.

Use GrammarDataGen instead of bonsai everywhere in Leon (except TEGISLike)
---
 .../scala/leon/datagen/GrammarDataGen.scala   | 42 ++++++++++++++++-
 .../scala/leon/grammars/EqualityGrammar.scala |  2 -
 .../scala/leon/grammars/ValueGrammar.scala    |  6 +--
 src/main/scala/leon/purescala/DefOps.scala    |  7 ---
 src/main/scala/leon/purescala/ExprOps.scala   |  8 ++--
 .../scala/leon/purescala/ScalaPrinter.scala   |  4 +-
 src/main/scala/leon/repair/Repairman.scala    | 28 ++---------
 .../scala/leon/synthesis/ExamplesFinder.scala | 39 +++++-----------
 .../disambiguation/ExamplesAdder.scala        |  5 +-
 .../disambiguation/QuestionBuilder.scala      | 46 ++++++++-----------
 .../leon/synthesis/rules/BottomUpTegis.scala  |  1 -
 .../leon/synthesis/rules/CEGISLike.scala      | 10 +++-
 .../leon/synthesis/rules/StringRender.scala   | 31 +++++--------
 .../scala/leon/synthesis/rules/TEGIS.scala    |  1 -
 src/main/scala/leon/utils/UniqueCounter.scala |  1 +
 .../etienne-thesis/BatchedQueue/Enqueue.scala | 15 ++----
 16 files changed, 111 insertions(+), 135 deletions(-)

diff --git a/src/main/scala/leon/datagen/GrammarDataGen.scala b/src/main/scala/leon/datagen/GrammarDataGen.scala
index 23c1ed5b8..04541e78a 100644
--- a/src/main/scala/leon/datagen/GrammarDataGen.scala
+++ b/src/main/scala/leon/datagen/GrammarDataGen.scala
@@ -4,14 +4,17 @@ package leon
 package datagen
 
 import purescala.Expressions._
-import purescala.Types.TypeTree
+import purescala.Types._
 import purescala.Common._
 import purescala.Constructors._
 import purescala.Extractors._
+import purescala.ExprOps._
 import evaluators._
 import bonsai.enumerators._
 
 import grammars._
+import utils.UniqueCounter
+import utils.SeqUtils.cartesianProduct
 
 /** Utility functions to generate values of a given type.
   * In fact, it could be used to generate *terms* of a given type,
@@ -19,9 +22,40 @@ import grammars._
 class GrammarDataGen(evaluator: Evaluator, grammar: ExpressionGrammar[TypeTree] = ValueGrammar) extends DataGenerator {
   implicit val ctx = evaluator.context
 
+  // Assume e contains generic values with index 0.
+  // Return a series of expressions with all normalized combinations of generic values.
+  private def expandGenerics(e: Expr): Seq[Expr] = {
+    val c = new UniqueCounter[TypeParameter]
+    val withUniqueCounters: Expr = postMap {
+      case GenericValue(t, _) =>
+        Some(GenericValue(t, c.next(t)))
+      case _ => None
+    }(e)
+
+    val indices = c.current
+
+    val (tps, substInt) = (for {
+      tp <- indices.keySet.toSeq
+    } yield tp -> (for {
+      from <- 0 to indices(tp)
+      to <- 0 to from
+    } yield (from, to))).unzip
+
+    val combos = cartesianProduct(substInt)
+
+    val substitutions = combos map { subst =>
+      tps.zip(subst).map { case (tp, (from, to)) =>
+        (GenericValue(tp, from): Expr) -> (GenericValue(tp, to): Expr)
+      }.toMap
+    }
+
+    substitutions map (replace(_, withUniqueCounters))
+
+  }
+
   def generate(tpe: TypeTree): Iterator[Expr] = {
     val enum = new MemoizedEnumerator[TypeTree, Expr, ProductionRule[TypeTree, Expr]](grammar.getProductions)
-    enum.iterator(tpe)
+    enum.iterator(tpe).flatMap(expandGenerics)
   }
 
   def generateFor(ins: Seq[Identifier], satisfying: Expr, maxValid: Int, maxEnumerated: Int): Iterator[Seq[Expr]] = {
@@ -51,4 +85,8 @@ class GrammarDataGen(evaluator: Evaluator, grammar: ExpressionGrammar[TypeTree]
     }
   }
 
+  def generateMapping(ins: Seq[Identifier], satisfying: Expr, maxValid: Int, maxEnumerated: Int) = {
+    generateFor(ins, satisfying, maxValid, maxEnumerated) map (ins zip _)
+  }
+
 }
diff --git a/src/main/scala/leon/grammars/EqualityGrammar.scala b/src/main/scala/leon/grammars/EqualityGrammar.scala
index fdcf079fa..a2f9c4136 100644
--- a/src/main/scala/leon/grammars/EqualityGrammar.scala
+++ b/src/main/scala/leon/grammars/EqualityGrammar.scala
@@ -6,8 +6,6 @@ package grammars
 import purescala.Types._
 import purescala.Constructors._
 
-import bonsai._
-
 /** A grammar of equalities
   *
   * @param types The set of types for which equalities will be generated
diff --git a/src/main/scala/leon/grammars/ValueGrammar.scala b/src/main/scala/leon/grammars/ValueGrammar.scala
index 8548c1a95..d3c422017 100644
--- a/src/main/scala/leon/grammars/ValueGrammar.scala
+++ b/src/main/scala/leon/grammars/ValueGrammar.scala
@@ -35,9 +35,9 @@ case object ValueGrammar extends ExpressionGrammar[TypeTree] {
       )
 
     case tp: TypeParameter =>
-      for (ind <- (1 to 3).toList) yield {
-        terminal(GenericValue(tp, ind))
-      }
+      List(
+        terminal(GenericValue(tp, 0))
+      )
 
     case TupleType(stps) =>
       List(
diff --git a/src/main/scala/leon/purescala/DefOps.scala b/src/main/scala/leon/purescala/DefOps.scala
index 4085050d2..578f52bff 100644
--- a/src/main/scala/leon/purescala/DefOps.scala
+++ b/src/main/scala/leon/purescala/DefOps.scala
@@ -275,13 +275,6 @@ object DefOps {
       None
   }
 
-  /** 
-   *
-   * @param p
-   * @param fdMapF
-   * @param fiMapF
-   * @return
-   */
 
   def replaceFunDefs(p: Program)(fdMapF: FunDef => Option[FunDef],
                                  fiMapF: (FunctionInvocation, FunDef) => Option[Expr] = defaultFiMap) = {
diff --git a/src/main/scala/leon/purescala/ExprOps.scala b/src/main/scala/leon/purescala/ExprOps.scala
index ed86c1806..73fcb4849 100644
--- a/src/main/scala/leon/purescala/ExprOps.scala
+++ b/src/main/scala/leon/purescala/ExprOps.scala
@@ -442,7 +442,7 @@ object ExprOps {
 
       case l @ Let(i,e,b) =>
         val newID = FreshIdentifier(i.name, i.getType, alwaysShowUniqueID = true).copiedFrom(i)
-        Some(Let(newID, e, replace(Map(Variable(i) -> Variable(newID)), b)))
+        Some(Let(newID, e, replaceFromIDs(Map(i -> Variable(newID)), b)))
 
       case _ => None
     }(expr)
@@ -597,7 +597,7 @@ object ExprOps {
     def simplerLet(t: Expr) : Option[Expr] = t match {
 
       case letExpr @ Let(i, t: Terminal, b) if isDeterministic(b) =>
-        Some(replace(Map(Variable(i) -> t), b))
+        Some(replaceFromIDs(Map(i -> t), b))
 
       case letExpr @ Let(i,e,b) if isDeterministic(b) => {
         val occurrences = count {
@@ -608,7 +608,7 @@ object ExprOps {
         if(occurrences == 0) {
           Some(b)
         } else if(occurrences == 1) {
-          Some(replace(Map(Variable(i) -> e), b))
+          Some(replaceFromIDs(Map(i -> e), b))
         } else {
           None
         }
@@ -619,7 +619,7 @@ object ExprOps {
 
         val (remIds, remExprs) = (ids zip exprs).filter {
           case (id, value: Terminal) =>
-            newBody = replace(Map(Variable(id) -> value), newBody)
+            newBody = replaceFromIDs(Map(id -> value), newBody)
             //we replace, so we drop old
             false
           case (id, value) =>
diff --git a/src/main/scala/leon/purescala/ScalaPrinter.scala b/src/main/scala/leon/purescala/ScalaPrinter.scala
index 67cc99464..11f0c187e 100644
--- a/src/main/scala/leon/purescala/ScalaPrinter.scala
+++ b/src/main/scala/leon/purescala/ScalaPrinter.scala
@@ -9,14 +9,12 @@ import Common._
 import Expressions._
 import Types._
 import Definitions._
-import org.apache.commons.lang3.StringEscapeUtils
 
-/** This pretty-printer only print valid scala syntax */
+/** This pretty-printer only prints valid scala syntax */
 class ScalaPrinter(opts: PrinterOptions,
                    opgm: Option[Program],
                    sb: StringBuffer = new StringBuffer) extends PrettyPrinter(opts, opgm, sb) {
 
-  private val dbquote = "\""
   override def pp(tree: Tree)(implicit ctx: PrinterContext): Unit = {
 
     tree match {
diff --git a/src/main/scala/leon/repair/Repairman.scala b/src/main/scala/leon/repair/Repairman.scala
index 19095f6f4..4f308e279 100644
--- a/src/main/scala/leon/repair/Repairman.scala
+++ b/src/main/scala/leon/repair/Repairman.scala
@@ -3,6 +3,7 @@
 package leon
 package repair
 
+import leon.datagen.GrammarDataGen
 import purescala.Common._
 import purescala.Definitions._
 import purescala.Expressions._
@@ -236,29 +237,10 @@ class Repairman(ctx0: LeonContext, initProgram: Program, fd: FunDef, verifTimeou
 
   def discoverTests(): ExamplesBank = {
 
-    import bonsai.enumerators._
-
     val maxEnumerated = 1000
     val maxValid      = 400
 
     val evaluator = new CodeGenEvaluator(ctx, program, CodeGenParams.default)
-    val enum      = new MemoizedEnumerator[TypeTree, Expr, ProductionRule[TypeTree, Expr]](ValueGrammar.getProductions)
-
-    val inputs = enum.iterator(tupleTypeWrap(fd.params map { _.getType})).map(unwrapTuple(_, fd.params.size))
-
-    val filtering: Seq[Expr] => Boolean = fd.precondition match {
-      case None =>
-        _ => true
-      case Some(pre) =>
-        val argIds = fd.paramIds
-        evaluator.compile(pre, argIds) match {
-          case Some(evalFun) =>
-            val sat = EvaluationResults.Successful(BooleanLiteral(true));
-            { (es: Seq[Expr]) => evalFun(new solvers.Model((argIds zip es).toMap)) == sat }
-          case None =>
-            { _ => false }
-        }
-    }
 
     val inputsToExample: Seq[Expr] => Example = { ins =>
       evaluator.eval(functionInvocation(fd, ins)) match {
@@ -269,10 +251,10 @@ class Repairman(ctx0: LeonContext, initProgram: Program, fd: FunDef, verifTimeou
       }
     }
 
-    val generatedTests = inputs
-      .take(maxEnumerated)
-      .filter(filtering)
-      .take(maxValid)
+    val dataGen = new GrammarDataGen(evaluator)
+
+    val generatedTests = dataGen
+      .generateFor(fd.paramIds, fd.precOrTrue, maxValid, maxEnumerated)
       .map(inputsToExample)
       .toList
 
diff --git a/src/main/scala/leon/synthesis/ExamplesFinder.scala b/src/main/scala/leon/synthesis/ExamplesFinder.scala
index 5728d3b14..1755966e0 100644
--- a/src/main/scala/leon/synthesis/ExamplesFinder.scala
+++ b/src/main/scala/leon/synthesis/ExamplesFinder.scala
@@ -6,13 +6,10 @@ package synthesis
 import purescala.Expressions._
 import purescala.Definitions._
 import purescala.ExprOps._
-import purescala.Types.TypeTree
 import purescala.Common._
 import purescala.Constructors._
-import purescala.Extractors._
 import evaluators._
 import grammars._
-import bonsai.enumerators._
 import codegen._
 import datagen._
 import solvers._
@@ -110,9 +107,9 @@ class ExamplesFinder(ctx0: LeonContext, program: Program) {
     val datagen   = new GrammarDataGen(evaluator, ValueGrammar)
     val solverDataGen = new SolverDataGen(ctx, program, (ctx, pgm) => SolverFactory(() => new FairZ3Solver(ctx, pgm)))
 
-    val generatedExamples = datagen.generateFor(ids, pc, maxValid, maxEnumerated).map(InExample(_))
+    val generatedExamples = datagen.generateFor(ids, pc, maxValid, maxEnumerated).map(InExample)
 
-    val solverExamples    = solverDataGen.generateFor(ids, pc, maxValid, maxEnumerated).map(InExample(_))
+    val solverExamples    = solverDataGen.generateFor(ids, pc, maxValid, maxEnumerated).map(InExample)
 
     ExamplesBank(generatedExamples.toSeq ++ solverExamples.toList, Nil)
   }
@@ -180,34 +177,20 @@ class ExamplesFinder(ctx0: LeonContext, program: Program) {
           case (a, b, c) =>
             None
         }) getOrElse {
+
           // If the input contains free variables, it does not provide concrete examples. 
           // We will instantiate them according to a simple grammar to get them.
-          val enum = new MemoizedEnumerator[TypeTree, Expr, ProductionRule[TypeTree, Expr]](ValueGrammar.getProductions)
-          val values = enum.iterator(tupleTypeWrap(freeVars.map { _.getType }))
-          val instantiations = values.map {
-            v => freeVars.zip(unwrapTuple(v, freeVars.size)).toMap
-          }
 
-          def filterGuard(e: Expr, mapping: Map[Identifier, Expr]): Boolean = cs.optGuard match {
-            case Some(guard) =>
-              // in -> e should be enough. We shouldn't find any subexpressions of in.
-              evaluator.eval(replace(Map(in -> e), guard), mapping) match {
-                case EvaluationResults.Successful(BooleanLiteral(true)) => true
-                case _ => false
-              }
+          val dataGen = new GrammarDataGen(evaluator)
+
+          val theGuard = replace(Map(in -> pattExpr), cs.optGuard.getOrElse(BooleanLiteral(true)))
 
-            case None =>
-              true
+          dataGen.generateFor(freeVars, theGuard, examplesPerCase, 1000).toSeq map { vals =>
+            val inst = freeVars.zip(vals).toMap
+            val inR = replaceFromIDs(inst, pattExpr)
+            val outR = replaceFromIDs(inst, doSubstitute(ieMap, cs.rhs))
+            (inR, outR)
           }
-          
-          if(cs.optGuard == Some(BooleanLiteral(false))) {
-            Nil
-          } else (for {
-            inst <- instantiations.toSeq
-            inR = replaceFromIDs(inst, pattExpr)
-            outR = replaceFromIDs(inst, doSubstitute(ieMap, cs.rhs))
-            if filterGuard(inR, inst)
-          } yield (inR, outR)).take(examplesPerCase)
         }
       }
     }
diff --git a/src/main/scala/leon/synthesis/disambiguation/ExamplesAdder.scala b/src/main/scala/leon/synthesis/disambiguation/ExamplesAdder.scala
index 6e9dc2376..6ce5f020a 100644
--- a/src/main/scala/leon/synthesis/disambiguation/ExamplesAdder.scala
+++ b/src/main/scala/leon/synthesis/disambiguation/ExamplesAdder.scala
@@ -3,15 +3,12 @@ package leon
 package synthesis
 package disambiguation
 
-import leon.LeonContext
-import leon.purescala.Expressions._
 import purescala.Common.FreshIdentifier
 import purescala.Constructors.{ and, tupleWrap }
 import purescala.Definitions.{ FunDef, Program, ValDef }
 import purescala.ExprOps.expressionToPattern
-import purescala.Expressions.{ BooleanLiteral, Equals, Expr, Lambda, MatchCase, Passes, Variable, WildcardPattern }
 import purescala.Extractors.TopLevelAnds
-import leon.purescala.Expressions._
+import purescala.Expressions._
 
 /**
  * @author Mikael
diff --git a/src/main/scala/leon/synthesis/disambiguation/QuestionBuilder.scala b/src/main/scala/leon/synthesis/disambiguation/QuestionBuilder.scala
index 244925b90..d77c06c97 100644
--- a/src/main/scala/leon/synthesis/disambiguation/QuestionBuilder.scala
+++ b/src/main/scala/leon/synthesis/disambiguation/QuestionBuilder.scala
@@ -1,21 +1,18 @@
 package leon
 package synthesis.disambiguation
 
+import datagen.GrammarDataGen
 import synthesis.Solution
 import evaluators.DefaultEvaluator
 import purescala.Expressions._
 import purescala.ExprOps
-import purescala.Constructors._
-import purescala.Extractors._
 import purescala.Types.{StringType, TypeTree}
 import purescala.Common.Identifier
 import purescala.Definitions.Program
 import purescala.DefOps
-import grammars.ValueGrammar
-import bonsai.enumerators.MemoizedEnumerator
+import grammars._
 import solvers.ModelBuilder
 import scala.collection.mutable.ListBuffer
-import grammars._
 
 object QuestionBuilder {
   /** Sort methods for questions. You can build your own */
@@ -92,11 +89,9 @@ object QuestionBuilder {
  * 
  * @tparam T A subtype of Expr that will be the type used in the Question[T] results.
  * @param input The identifier of the unique function's input. Must be typed or the type should be defined by setArgumentType
- * @param ruleApplication The set of solutions for the body of f
  * @param filter A function filtering which outputs should be considered for comparison.
- * It takes as input the sequence of outputs already considered for comparison, and the new output.
- * It should return Some(result) if the result can be shown, and None else.
- * @return An ordered
+ *               It takes as input the sequence of outputs already considered for comparison, and the new output.
+ *               It should return Some(result) if the result can be shown, and None else.
  * 
  */
 class QuestionBuilder[T <: Expr](
@@ -139,25 +134,22 @@ class QuestionBuilder[T <: Expr](
   /** Returns a list of input/output questions to ask to the user. */
   def result(): List[Question[T]] = {
     if(solutions.isEmpty) return Nil
-    
-    val enum = new MemoizedEnumerator[TypeTree, Expr, ProductionRule[TypeTree,Expr]](value_enumerator.getProductions)
-    val values = enum.iterator(tupleTypeWrap(_argTypes))
-    val instantiations = values.map {
-      v => input.zip(unwrapTuple(v, input.size))
-    }
-    
-    val enumerated_inputs = instantiations.take(expressionsToTake).toList
-    
+
+    val datagen = new GrammarDataGen(new DefaultEvaluator(c, p), value_enumerator)
+    val enumerated_inputs = datagen.generateMapping(input, BooleanLiteral(true), expressionsToTake, expressionsToTake).toList
+
     val solution = solutions.head
     val alternatives = solutions.drop(1).take(solutionsToTake).toList
     val questions = ListBuffer[Question[T]]()
-    for{possible_input             <- enumerated_inputs
-        current_output_nonfiltered <- run(solution, possible_input)
-        current_output             <- filter(Seq(), current_output_nonfiltered)} {
+    for {
+      possibleInput            <- enumerated_inputs
+      currentOutputNonFiltered <- run(solution, possibleInput)
+      currentOutput            <- filter(Seq(), currentOutputNonFiltered)
+    } {
       
-      val alternative_outputs = ((ListBuffer[T](current_output) /: alternatives) { (prev, alternative) =>
-        run(alternative, possible_input) match {
-          case Some(alternative_output) if alternative_output != current_output =>
+      val alternative_outputs = (ListBuffer[T](currentOutput) /: alternatives) { (prev, alternative) =>
+        run(alternative, possibleInput) match {
+          case Some(alternative_output) if alternative_output != currentOutput =>
             filter(prev, alternative_output) match {
               case Some(alternative_output_filtered) =>
                 prev += alternative_output_filtered
@@ -165,9 +157,9 @@ class QuestionBuilder[T <: Expr](
             }
           case _ => prev
         }
-      }).drop(1).toList.distinct
-      if(alternative_outputs.nonEmpty || keepEmptyAlternativeQuestions(current_output)) {
-        questions += Question(possible_input.map(_._2), current_output, alternative_outputs.sortWith((e,f) => _alternativeSortMethod.compare(e, f) <= 0))
+      }.drop(1).toList.distinct
+      if(alternative_outputs.nonEmpty || keepEmptyAlternativeQuestions(currentOutput)) {
+        questions += Question(possibleInput.map(_._2), currentOutput, alternative_outputs.sortWith((e,f) => _alternativeSortMethod.compare(e, f) <= 0))
       }
     }
     questions.toList.sortBy(_questionSorMethod(_))
diff --git a/src/main/scala/leon/synthesis/rules/BottomUpTegis.scala b/src/main/scala/leon/synthesis/rules/BottomUpTegis.scala
index f716997f4..4c12f5822 100644
--- a/src/main/scala/leon/synthesis/rules/BottomUpTegis.scala
+++ b/src/main/scala/leon/synthesis/rules/BottomUpTegis.scala
@@ -14,7 +14,6 @@ import codegen.CodeGenParams
 import grammars._
 
 import bonsai.enumerators._
-import bonsai.{Generator => Gen}
 
 case object BottomUpTEGIS extends BottomUpTEGISLike[TypeTree]("BU TEGIS") {
   def getGrammar(sctx: SynthesisContext, p: Problem) = {
diff --git a/src/main/scala/leon/synthesis/rules/CEGISLike.scala b/src/main/scala/leon/synthesis/rules/CEGISLike.scala
index 368608b90..fba29e2f0 100644
--- a/src/main/scala/leon/synthesis/rules/CEGISLike.scala
+++ b/src/main/scala/leon/synthesis/rules/CEGISLike.scala
@@ -765,7 +765,11 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) {
           }
         }
 
-
+        println("BASE EXAMPLES")
+        baseExampleInputs.foreach { in =>
+          println("  - "+in.asString)
+        }
+        println("BASE EXAMPLES END")
         /**
          * We generate tests for discarding potential programs
          */
@@ -842,6 +846,10 @@ abstract class CEGISLike[T <: Typed](name: String) extends Rule(name) {
               }
             }
 
+            allInputExamples().foreach { in =>
+              println("  - "+in.asString)
+            }
+
             val nPassing = prunedPrograms.size
             val nTotal   = ndProgram.allProgramsCount()
 
diff --git a/src/main/scala/leon/synthesis/rules/StringRender.scala b/src/main/scala/leon/synthesis/rules/StringRender.scala
index f03c54b56..7b72da539 100644
--- a/src/main/scala/leon/synthesis/rules/StringRender.scala
+++ b/src/main/scala/leon/synthesis/rules/StringRender.scala
@@ -7,35 +7,28 @@ package rules
 import scala.annotation.tailrec
 import scala.collection.mutable.ListBuffer
 
-import bonsai.enumerators.MemoizedEnumerator
-import leon.evaluators.DefaultEvaluator
-import leon.evaluators.StringTracingEvaluator
-import leon.synthesis.programsets.DirectProgramSet
-import leon.synthesis.programsets.JoinProgramSet
-import leon.purescala.Common.FreshIdentifier
-import leon.purescala.Common.Identifier
-import leon.purescala.DefOps
-import leon.purescala.Definitions.FunDef
-import leon.purescala.Definitions.FunDef
-import leon.purescala.Definitions.ValDef
-import leon.purescala.ExprOps
-import leon.solvers.Model
-import leon.solvers.ModelBuilder
-import leon.solvers.string.StringSolver
-import leon.utils.DebugSectionSynthesis
+import purescala.Common._
+import purescala.Types._
 import purescala.Constructors._
 import purescala.Definitions._
-import purescala.ExprOps._
 import purescala.Expressions._
 import purescala.Extractors._
 import purescala.TypeOps
-import purescala.Types._
+import purescala.DefOps
+import purescala.ExprOps
+
+import evaluators.StringTracingEvaluator
+import synthesis.programsets.DirectProgramSet
+import synthesis.programsets.JoinProgramSet
+
+import solvers.ModelBuilder
+import solvers.string.StringSolver
 
 
 /** A template generator for a given type tree. 
   * Extend this class using a concrete type tree,
   * Then use the apply method to get a hole which can be a placeholder for holes in the template.
-  * Each call to the ``.instantiate` method of the subsequent Template will provide different instances at each position of the hole.
+  * Each call to the `.instantiate` method of the subsequent Template will provide different instances at each position of the hole.
   */
 abstract class TypedTemplateGenerator(t: TypeTree) {
   import StringRender.WithIds
diff --git a/src/main/scala/leon/synthesis/rules/TEGIS.scala b/src/main/scala/leon/synthesis/rules/TEGIS.scala
index d7ec34617..3d496d059 100644
--- a/src/main/scala/leon/synthesis/rules/TEGIS.scala
+++ b/src/main/scala/leon/synthesis/rules/TEGIS.scala
@@ -6,7 +6,6 @@ package rules
 
 import purescala.Types._
 import grammars._
-import utils._
 
 case object TEGIS extends TEGISLike[TypeTree]("TEGIS") {
   def getParams(sctx: SynthesisContext, p: Problem) = {
diff --git a/src/main/scala/leon/utils/UniqueCounter.scala b/src/main/scala/leon/utils/UniqueCounter.scala
index 06a6c0bb4..7c7862747 100644
--- a/src/main/scala/leon/utils/UniqueCounter.scala
+++ b/src/main/scala/leon/utils/UniqueCounter.scala
@@ -17,4 +17,5 @@ class UniqueCounter[K] {
     globalId
   }
 
+  def current = nameIds
 }
diff --git a/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala b/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala
index fe01946d1..0f30a5ba1 100644
--- a/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala
+++ b/testcases/synthesis/etienne-thesis/BatchedQueue/Enqueue.scala
@@ -72,17 +72,12 @@ object BatchedQueue {
     def enqueue(v: T): Queue[T] = {
       require(invariant)
 
-      f match {
-        case Cons(h, t) =>
-          Queue(f, Cons(v, r))
-        case Nil() =>
-          Queue(Cons(v, f), Nil())
-      }
-
+      ???[Queue[T]]
     } ensuring { (res: Queue[T]) =>
-        res.invariant &&
-        res.toList.last == v &&
-        res.content == this.content ++ Set(v)
+      res.invariant &&
+      res.toList.last == v &&
+      res.size == size + 1 &&
+      res.content == this.content ++ Set(v)
     }
   }
 }
-- 
GitLab