From 65b1b6af9de0331d88a288fc5db703cdd32557c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9gis=20Blanc?= <regwblanc@gmail.com>
Date: Fri, 14 Dec 2012 20:53:37 +0100
Subject: [PATCH] Remove EmptySet, EmptyMap and SingletonMap

EmptySet, EmptyMap and SingletonMap are redundant, so they are removed.
They are subsumed by FiniteSet and FiniteMap.

This commit also deletes two testcases that were testing for equality
between EmptySet and FiniteSet of 0 element. Obviously they no longer
relevant. Additionnaly, this commit adds some new regression testcases for
Maps and Sets.
---
 src/main/scala/leon/Evaluator.scala           | 38 ++--------
 .../scala/leon/codegen/CodeGeneration.scala   |  3 -
 .../scala/leon/plugin/CodeExtraction.scala    | 28 +++-----
 .../scala/leon/purescala/Extractors.scala     | 13 +++-
 .../scala/leon/purescala/PrettyPrinter.scala  | 15 ++--
 .../scala/leon/purescala/ScalaPrinter.scala   | 13 ++--
 src/main/scala/leon/purescala/TreeOps.scala   |  4 +-
 src/main/scala/leon/purescala/Trees.scala     |  5 +-
 .../scala/leon/solvers/RandomSolver.scala     |  2 +-
 .../leon/solvers/z3/AbstractZ3Solver.scala    | 33 +++------
 .../verification/purescala/valid/MyMap.scala  | 16 +++++
 .../verification/purescala/valid/MySet.scala  | 16 +++++
 .../leon/test/codegen/CodeGenEvaluation.scala |  1 -
 .../test/solvers/z3/BugWithEmptySet.scala     | 51 --------------
 .../solvers/z3/BugWithEmptySetNewAPI.scala    | 70 -------------------
 15 files changed, 93 insertions(+), 215 deletions(-)
 create mode 100644 src/test/resources/regression/verification/purescala/valid/MyMap.scala
 create mode 100644 src/test/resources/regression/verification/purescala/valid/MySet.scala
 delete mode 100644 src/test/scala/leon/test/solvers/z3/BugWithEmptySet.scala
 delete mode 100644 src/test/scala/leon/test/solvers/z3/BugWithEmptySetNewAPI.scala

diff --git a/src/main/scala/leon/Evaluator.scala b/src/main/scala/leon/Evaluator.scala
index 5792b973c..24d0fd06e 100644
--- a/src/main/scala/leon/Evaluator.scala
+++ b/src/main/scala/leon/Evaluator.scala
@@ -209,55 +209,38 @@ object Evaluator {
         }
 
         case SetUnion(s1,s2) => (rec(ctx,s1), rec(ctx,s2)) match {
-          case (EmptySet(_), f2) => f2
-          case (f1, EmptySet(_)) => f1
           case (f@FiniteSet(els1),FiniteSet(els2)) => FiniteSet((els1 ++ els2).distinct).setType(f.getType)
           case (le,re) => throw TypeErrorEx(TypeError(le, s1.getType))
         }
         case SetIntersection(s1,s2) => (rec(ctx,s1), rec(ctx,s2)) match {
-          case (e @ EmptySet(_), _) => e
-          case (_, e @ EmptySet(_)) => e
           case (f@FiniteSet(els1),FiniteSet(els2)) => {
             val newElems = (els1.toSet intersect els2.toSet).toSeq
             val baseType = f.getType.asInstanceOf[SetType].base
-            if(newElems.isEmpty) {
-              EmptySet(baseType).setType(f.getType)
-            } else {
-              FiniteSet(newElems).setType(f.getType)
-            }
+            FiniteSet(newElems).setType(f.getType)
           }
           case (le,re) => throw TypeErrorEx(TypeError(le, s1.getType))
         }
         case SetDifference(s1,s2) => (rec(ctx,s1), rec(ctx,s2)) match {
-          case (e @ EmptySet(_), _) => e
-          case (f , EmptySet(_)) => f
           case (f@FiniteSet(els1),FiniteSet(els2)) => {
             val newElems = (els1.toSet -- els2.toSet).toSeq
             val baseType = f.getType.asInstanceOf[SetType].base
-            if(newElems.isEmpty) {
-              EmptySet(baseType).setType(f.getType)
-            } else {
-              FiniteSet(newElems).setType(f.getType)
-            }
+            FiniteSet(newElems).setType(f.getType)
           }
           case (le,re) => throw TypeErrorEx(TypeError(le, s1.getType))
         }
         case ElementOfSet(el,s) => (rec(ctx,el), rec(ctx,s)) match {
-          case (_, EmptySet(_)) => BooleanLiteral(false)
           case (e, f @ FiniteSet(els)) => BooleanLiteral(els.contains(e))
           case (l,r) => throw TypeErrorEx(TypeError(r, SetType(l.getType)))
         }
         case SetCardinality(s) => {
           val sr = rec(ctx, s)
           sr match {
-            case EmptySet(_) => IntLiteral(0)
             case FiniteSet(els) => IntLiteral(els.size)
             case _ => throw TypeErrorEx(TypeError(sr, SetType(AnyType)))
           }
         }
 
         case f @ FiniteSet(els) => FiniteSet(els.map(rec(ctx,_)).distinct).setType(f.getType)
-        case e @ EmptySet(_) => e
         case i @ IntLiteral(_) => i
         case b @ BooleanLiteral(_) => b
         case u @ UnitLiteral => u
@@ -292,31 +275,24 @@ object Evaluator {
           FiniteArray(exprs.map(e => rec(ctx, e)))
         }
 
-        case f @ FiniteMap(ss) => FiniteMap(ss.map(rec(ctx,_)).distinct.asInstanceOf[Seq[SingletonMap]]).setType(f.getType)
-        case e @ EmptyMap(_,_) => e
-        case s @ SingletonMap(f,t) => SingletonMap(rec(ctx,f), rec(ctx,t)).setType(s.getType)
+        case f @ FiniteMap(ss) => FiniteMap(ss.map{ case (k, v) => (rec(ctx, k), rec(ctx, v)) }.distinct).setType(f.getType)
         case g @ MapGet(m,k) => (rec(ctx,m), rec(ctx,k)) match {
-          case (FiniteMap(ss), e) => ss.find(_.from == e) match {
-            case Some(SingletonMap(k0,v0)) => v0
+          case (FiniteMap(ss), e) => ss.find(_._1 == e) match {
+            case Some((_, v0)) => v0
             case None => throw RuntimeErrorEx("key not found: " + e)
           }
-          case (EmptyMap(ft,tt), e) => throw RuntimeErrorEx("key not found: " + e)
-          // case (SingletonMap(f,t), e) => if (f == e) t else throw RuntimeErrorEx("key not found: " + e)
           case (l,r) => throw TypeErrorEx(TypeError(l, MapType(r.getType, g.getType)))
         }
         case u @ MapUnion(m1,m2) => (rec(ctx,m1), rec(ctx,m2)) match {
-          case (EmptyMap(_,_), r) => r
-          case (l, EmptyMap(_,_)) => l
           case (f1@FiniteMap(ss1), FiniteMap(ss2)) => {
-            val filtered1 = ss1.filterNot(s1 => ss2.exists(s2 => s2.from == s1.from))
+            val filtered1 = ss1.filterNot(s1 => ss2.exists(s2 => s2._1 == s1._1))
             val newSs = filtered1 ++ ss2
             FiniteMap(newSs).setType(f1.getType)
           }
           case (l, r) => throw TypeErrorEx(TypeError(l, m1.getType))
         }
         case i @ MapIsDefinedAt(m,k) => (rec(ctx,m), rec(ctx,k)) match {
-          case (EmptyMap(_,_),_) => BooleanLiteral(false)
-          case (FiniteMap(ss), e) => BooleanLiteral(ss.exists(_.from == e))
+          case (FiniteMap(ss), e) => BooleanLiteral(ss.exists(_._1 == e))
           case (l, r) => throw TypeErrorEx(TypeError(l, m.getType))
         }
         case Distinct(args) => {
diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index ae4cf9102..6ccb05f24 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -153,9 +153,6 @@ object CodeGeneration {
         ch << InvokeVirtual(TupleClass, "get", "(I)Ljava/lang/Object;")
         mkUnbox(bs(i - 1), ch)
 
-      case EmptySet(_) =>
-        ch << DefaultNew(SetClass)  
-
       case FiniteSet(es) =>
         ch << DefaultNew(SetClass)
         for(e <- es) {
diff --git a/src/main/scala/leon/plugin/CodeExtraction.scala b/src/main/scala/leon/plugin/CodeExtraction.scala
index 78b75cf46..babf6d728 100644
--- a/src/main/scala/leon/plugin/CodeExtraction.scala
+++ b/src/main/scala/leon/plugin/CodeExtraction.scala
@@ -754,7 +754,7 @@ trait CodeExtraction extends Extractors {
           }
           case ExEmptySet(tt) => {
             val underlying = scalaType2PureScala(unit, silent)(tt.tpe)
-            EmptySet(underlying).setType(SetType(underlying))          
+            FiniteSet(Seq()).setType(SetType(underlying))          
           }
           case ExEmptyMultiset(tt) => {
             val underlying = scalaType2PureScala(unit, silent)(tt.tpe)
@@ -765,28 +765,23 @@ trait CodeExtraction extends Extractors {
             val toUnderlying   = scalaType2PureScala(unit, silent)(tt.tpe)
             val tpe = MapType(fromUnderlying, toUnderlying)
 
-            EmptyMap(fromUnderlying, toUnderlying).setType(tpe)
+            FiniteMap(Seq()).setType(tpe)
           }
           case ExLiteralMap(ft, tt, elems) => {
             val fromUnderlying = scalaType2PureScala(unit, silent)(ft.tpe)
             val toUnderlying   = scalaType2PureScala(unit, silent)(tt.tpe)
             val tpe = MapType(fromUnderlying, toUnderlying)
 
-            if (elems.isEmpty) {
-              EmptyMap(fromUnderlying, toUnderlying).setType(tpe)
-            } else {
-              val singletons = elems.collect { case ExTuple(tpes, trees) if (trees.size == 2) =>
-                SingletonMap(rec(trees(0)), rec(trees(1))).setType(tpe)
-              }
-
-
-              if (singletons.size != elems.size) {
-                unit.error(nextExpr.pos, "Some map elements could not be extracted as Tuple2")
-                throw ImpureCodeEncounteredException(nextExpr)
-              }
+            val singletons: Seq[(Expr, Expr)] = elems.collect { case ExTuple(tpes, trees) if (trees.size == 2) =>
+              (rec(trees(0)), rec(trees(1)))
+            }
 
-              FiniteMap(singletons).setType(tpe)
+            if (singletons.size != elems.size) {
+              unit.error(nextExpr.pos, "Some map elements could not be extracted as Tuple2")
+              throw ImpureCodeEncounteredException(nextExpr)
             }
+
+            FiniteMap(singletons).setType(tpe)
           }
 
           case ExSetMin(t) => {
@@ -890,8 +885,7 @@ trait CodeExtraction extends Extractors {
             val rt = rec(t)
             rm.getType match {
               case MapType(ft, tt) => {
-                val newSingleton = SingletonMap(rf, rt).setType(rm.getType)
-                MapUnion(rm, FiniteMap(Seq(newSingleton)).setType(rm.getType)).setType(rm.getType)
+                MapUnion(rm, FiniteMap(Seq((rf, rt))).setType(rm.getType)).setType(rm.getType)
               }
               case ArrayType(bt) => {
                 ArrayUpdated(rm, rf, rt).setType(rm.getType).setPosInfo(up.pos.line, up.pos.column)
diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala
index b5a349bb1..904e6e3d3 100644
--- a/src/main/scala/leon/purescala/Extractors.scala
+++ b/src/main/scala/leon/purescala/Extractors.scala
@@ -61,7 +61,6 @@ object Extractors {
       case MultisetUnion(t1,t2) => Some((t1,t2,MultisetUnion))
       case MultisetPlus(t1,t2) => Some((t1,t2,MultisetPlus))
       case MultisetDifference(t1,t2) => Some((t1,t2,MultisetDifference))
-      case SingletonMap(t1,t2) => Some((t1,t2,SingletonMap))
       case mg@MapGet(t1,t2) => Some((t1,t2, (t1, t2) => MapGet(t1, t2).setPosInfo(mg)))
       case MapUnion(t1,t2) => Some((t1,t2,MapUnion))
       case MapDifference(t1,t2) => Some((t1,t2,MapDifference))
@@ -88,7 +87,17 @@ object Extractors {
       case And(args) => Some((args, And.apply))
       case Or(args) => Some((args, Or.apply))
       case FiniteSet(args) => Some((args, FiniteSet))
-      case FiniteMap(args) => Some((args, (as : Seq[Expr]) => FiniteMap(as.asInstanceOf[Seq[SingletonMap]])))
+      case FiniteMap(args) => {
+        val subArgs = args.flatMap{case (k, v) => Seq(k, v)}
+        val builder: (Seq[Expr]) => Expr = (as: Seq[Expr]) => {
+          val (keys, values, isKey) = as.foldLeft[(List[Expr], List[Expr], Boolean)]((Nil, Nil, true)){
+            case ((keys, values, isKey), rExpr) => if(isKey) (rExpr::keys, values, false) else (keys, rExpr::values, true)
+          }
+          assert(isKey)
+          FiniteMap(keys.zip(values))
+        }
+        Some((subArgs, builder))
+      }
       case FiniteMultiset(args) => Some((args, FiniteMultiset))
       case ArrayUpdated(t1, t2, t3) => Some((Seq(t1,t2,t3), (as: Seq[Expr]) => ArrayUpdated(as(0), as(1), as(2))))
       case FiniteArray(args) => Some((args, FiniteArray))
diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala
index 0f023bfb9..8a244a5e8 100644
--- a/src/main/scala/leon/purescala/PrettyPrinter.scala
+++ b/src/main/scala/leon/purescala/PrettyPrinter.scala
@@ -142,9 +142,8 @@ object PrettyPrinter {
     case GreaterThan(l,r) => ppBinary(sb, l, r, " > ", lvl)
     case LessEquals(l,r) => ppBinary(sb, l, r, " \u2264 ", lvl)      // \leq
     case GreaterEquals(l,r) => ppBinary(sb, l, r, " \u2265 ", lvl)   // \geq
-    case FiniteSet(rs) => ppNary(sb, rs, "{", ", ", "}", lvl)
+    case FiniteSet(rs) => if(rs.isEmpty) sb.append("\u2205") /* Ø */ else ppNary(sb, rs, "{", ", ", "}", lvl)
     case FiniteMultiset(rs) => ppNary(sb, rs, "{|", ", ", "|}", lvl)
-    case EmptySet(_) => sb.append("\u2205")                          // Ø
     case EmptyMultiset(_) => sb.append("\u2205")                     // Ø
     case Not(ElementOfSet(s,e)) => ppBinary(sb, s, e, " \u2209 ", lvl) // \notin
     case ElementOfSet(s,e) => ppBinary(sb, s, e, " \u2208 ", lvl)    // \in
@@ -163,9 +162,15 @@ object PrettyPrinter {
     case MultisetCardinality(t) => ppUnary(sb, t, "|", "|", lvl)
     case MultisetPlus(l,r) => ppBinary(sb, l, r, " \u228E ", lvl)    // U+
     case MultisetToSet(e) => pp(e, sb, lvl).append(".toSet")
-    case EmptyMap(_,_) => sb.append("{}")
-    case SingletonMap(f,t) => ppBinary(sb, f, t, " -> ", lvl)
-    case FiniteMap(rs) => ppNary(sb, rs, "{", ", ", "}", lvl)
+    case FiniteMap(rs) => {
+      sb.append("{")
+      val sz = rs.size
+      var c = 0
+      rs.foreach{case (k, v) => {
+        pp(k, sb, lvl); sb.append(" -> "); pp(v, sb, lvl); c += 1 ; if(c < sz) sb.append(", ")
+      }}
+      sb.append("}")
+    }
     case MapGet(m,k) => {
       var nsb = sb
       pp(m, nsb, lvl)
diff --git a/src/main/scala/leon/purescala/ScalaPrinter.scala b/src/main/scala/leon/purescala/ScalaPrinter.scala
index aad213668..26a57c62c 100644
--- a/src/main/scala/leon/purescala/ScalaPrinter.scala
+++ b/src/main/scala/leon/purescala/ScalaPrinter.scala
@@ -140,7 +140,6 @@ object ScalaPrinter {
     case GreaterEquals(l,r) => ppBinary(sb, l, r, " >= ", lvl)   // \geq
     case FiniteSet(rs) => ppNary(sb, rs, "Set(", ", ", ")", lvl)
     case FiniteMultiset(rs) => ppNary(sb, rs, "{|", ", ", "|}", lvl)
-    case EmptySet(bt) => sb.append("Set()")                          // Ø
     case EmptyMultiset(_) => sys.error("Not Valid Scala")
     case ElementOfSet(s,e) => ppBinary(sb, s, e, " contains ", lvl)
     //case ElementOfSet(s,e) => ppBinary(sb, s, e, " \u2208 ", lvl)    // \in
@@ -163,9 +162,15 @@ object ScalaPrinter {
    // case MultisetCardinality(t) => ppUnary(sb, t, "|", "|", lvl)
    // case MultisetPlus(l,r) => ppBinary(sb, l, r, " \u228E ", lvl)    // U+
    // case MultisetToSet(e) => pp(e, sb, lvl).append(".toSet")
-    case EmptyMap(_,_) => sb.append("Map()")
-    case SingletonMap(f,t) => ppBinary(sb, f, t, " -> ", lvl)
-    case FiniteMap(rs) => ppNary(sb, rs, "Map(", ", ", ")", lvl)
+    case FiniteMap(rs) => {
+      sb.append("{")
+      val sz = rs.size
+      var c = 0
+      rs.foreach{case (k, v) => {
+        pp(k, sb, lvl); sb.append(" -> "); pp(v, sb, lvl); c += 1 ; if(c < sz) sb.append(", ")
+      }}
+      sb.append("}")
+    }
     case MapGet(m,k) => {
       pp(m, sb, lvl)
       ppNary(sb, Seq(k), "(", ",", ")", lvl)
diff --git a/src/main/scala/leon/purescala/TreeOps.scala b/src/main/scala/leon/purescala/TreeOps.scala
index 10a74488f..3409bde31 100644
--- a/src/main/scala/leon/purescala/TreeOps.scala
+++ b/src/main/scala/leon/purescala/TreeOps.scala
@@ -822,8 +822,8 @@ object TreeOps {
     case CaseClassType(ccd) =>
       val fields = ccd.fields
       CaseClass(ccd, fields.map(f => simplestValue(f.getType)))
-    case SetType(baseType) => EmptySet(baseType).setType(tpe)
-    case MapType(fromType, toType) => EmptyMap(fromType, toType).setType(tpe)
+    case SetType(baseType) => FiniteSet(Seq()).setType(tpe)
+    case MapType(fromType, toType) => FiniteMap(Seq()).setType(tpe)
     case _ => throw new Exception("I can't choose simplest value for type " + tpe)
   }
 
diff --git a/src/main/scala/leon/purescala/Trees.scala b/src/main/scala/leon/purescala/Trees.scala
index 8877c17af..c783bbb04 100644
--- a/src/main/scala/leon/purescala/Trees.scala
+++ b/src/main/scala/leon/purescala/Trees.scala
@@ -402,7 +402,6 @@ object Trees {
   }
 
   /* Set expressions */
-  case class EmptySet(baseType: TypeTree) extends Expr with Terminal
   case class FiniteSet(elements: Seq[Expr]) extends Expr 
   // TODO : Figure out what evaluation order is, for this.
   // Perhaps then rewrite as "contains".
@@ -436,9 +435,7 @@ object Trees {
   case class MultisetToSet(multiset: Expr) extends Expr
 
   /* Map operations. */
-  case class EmptyMap(fromType: TypeTree, toType: TypeTree) extends Expr with Terminal
-  case class SingletonMap(from: Expr, to: Expr) extends Expr 
-  case class FiniteMap(singletons: Seq[SingletonMap]) extends Expr 
+  case class FiniteMap(singletons: Seq[(Expr, Expr)]) extends Expr 
 
   case class MapGet(map: Expr, key: Expr) extends Expr with ScalacPositional
   case class MapUnion(map1: Expr, map2: Expr) extends Expr 
diff --git a/src/main/scala/leon/solvers/RandomSolver.scala b/src/main/scala/leon/solvers/RandomSolver.scala
index 330bd00fc..3c7265635 100644
--- a/src/main/scala/leon/solvers/RandomSolver.scala
+++ b/src/main/scala/leon/solvers/RandomSolver.scala
@@ -68,7 +68,7 @@ class RandomSolver(context: LeonContext, val nbTrial: Option[Int] = None) extend
       CaseClass(cd, cd.fields.map(f => randomValue(f.getType, size / nbFields))) 
     }
     case AnyType => randomValue(randomType(), size)
-    case SetType(base) => EmptySet(base)
+    case SetType(base) => FiniteSet(Seq())
     case MultisetType(base) => EmptyMultiset(base)
     case Untyped => sys.error("I don't know what to do")
     case BottomType => sys.error("I don't know what to do")
diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index 7628c6acb..c5f6c0f7e 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -442,7 +442,6 @@ trait AbstractZ3Solver extends solvers.IncrementalSolverBuilder {
         case f @ FunctionInvocation(fd, args) => {
           z3.mkApp(functionDefToDecl(fd), args.map(rec(_)): _*)
         }
-        case e @ EmptySet(_) => z3.mkEmptySet(typeToSort(e.getType.asInstanceOf[SetType].base))
         
         case SetEquals(s1, s2) => z3.mkEq(rec(s1), rec(s2))
         case ElementOfSet(e, s) => z3.mkSetSubset(z3.mkSetAdd(z3.mkEmptySet(typeToSort(e.getType)), rec(e)), rec(s))
@@ -457,25 +456,12 @@ trait AbstractZ3Solver extends solvers.IncrementalSolverBuilder {
         }
         case SetMin(s) => intSetMinFun(rec(s))
         case SetMax(s) => intSetMaxFun(rec(s))
-        case s @ SingletonMap(from,to) => s.getType match {
-          case MapType(fromType, toType) =>
-            val fromSort = typeToSort(fromType)
-            val toSort = typeToSort(toType)
-            val constArray = z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)())
-            z3.mkStore(constArray, rec(from), mapRangeSomeConstructors(toType)(rec(to)))
-          case errorType => scala.sys.error("Unexpected type for singleton map: " + (ex, errorType))
-        }
-        case e @ EmptyMap(fromType, toType) => {
-          typeToSort(e.getType) //had to add this here because the mapRangeNoneConstructors was not yet constructed...
-          val fromSort = typeToSort(fromType)
-          val toSort = typeToSort(toType)
-          z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)())
-        }
         case f @ FiniteMap(elems) => f.getType match {
-          case MapType(fromType, toType) =>
+          case tpe@MapType(fromType, toType) =>
+            typeToSort(tpe) //had to add this here because the mapRangeNoneConstructors was not yet constructed...
             val fromSort = typeToSort(fromType)
             val toSort = typeToSort(toType)
-            elems.foldLeft(z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)())){ case (ast, SingletonMap(k,v)) => z3.mkStore(ast, rec(k), mapRangeSomeConstructors(toType)(rec(v))) }
+            elems.foldLeft(z3.mkConstArray(fromSort, mapRangeNoneConstructors(toType)())){ case (ast, (k,v)) => z3.mkStore(ast, rec(k), mapRangeSomeConstructors(toType)(rec(v))) }
           case errorType => scala.sys.error("Unexpected type for finite map: " + (ex, errorType))
         }
         case mg @ MapGet(m,k) => m.getType match {
@@ -488,9 +474,8 @@ trait AbstractZ3Solver extends solvers.IncrementalSolverBuilder {
           case MapType(ft, tt) => m2 match {
             case FiniteMap(ss) =>
               ss.foldLeft(rec(m1)){
-                case (ast, SingletonMap(k, v)) => z3.mkStore(ast, rec(k), mapRangeSomeConstructors(tt)(rec(v)))
+                case (ast, (k, v)) => z3.mkStore(ast, rec(k), mapRangeSomeConstructors(tt)(rec(v)))
               }
-            case SingletonMap(k, v) => z3.mkStore(rec(m1), rec(k), mapRangeSomeConstructors(tt)(rec(v)))
             case _ => scala.sys.error("map updates can only be applied with concrete map instances")
           }
           case errorType => scala.sys.error("Unexpected type for map: " + (ex, errorType))
@@ -555,17 +540,17 @@ trait AbstractZ3Solver extends solvers.IncrementalSolverBuilder {
         model.getArrayValue(t) match {
           case None => throw new CantTranslateException(t)
           case Some((map, elseValue)) => 
-            val singletons = map.map(e => (e, z3.getASTKind(e._2))).collect {
-              case ((index, value), Z3AppAST(someCons, arg :: Nil)) if someCons == mapRangeSomeConstructors(vt) => SingletonMap(rec(index, Some(kt)), rec(arg, Some(vt)))
-            }
-            (if (singletons.isEmpty) EmptyMap(kt, vt) else FiniteMap(singletons.toSeq)).setType(expType.get)
+            val singletons: Seq[(Expr, Expr)] = map.map(e => (e, z3.getASTKind(e._2))).collect {
+              case ((index, value), Z3AppAST(someCons, arg :: Nil)) if someCons == mapRangeSomeConstructors(vt) => (rec(index, Some(kt)), rec(arg, Some(vt)))
+            }.toSeq
+            FiniteMap(singletons).setType(expType.get)
         }
       case Some(SetType(dt)) => 
         model.getSetValue(t) match {
           case None => throw new CantTranslateException(t)
           case Some(set) => {
             val elems = set.map(e => rec(e, Some(dt)))
-            (if (elems.isEmpty) EmptySet(dt) else FiniteSet(elems.toSeq)).setType(expType.get)
+            FiniteSet(elems.toSeq).setType(expType.get)
           }
         }
       case Some(ArrayType(dt)) => {
diff --git a/src/test/resources/regression/verification/purescala/valid/MyMap.scala b/src/test/resources/regression/verification/purescala/valid/MyMap.scala
new file mode 100644
index 000000000..c71bfcf52
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/MyMap.scala
@@ -0,0 +1,16 @@
+import leon.Utils._
+
+object MyMap {
+
+  def map1(): Int = {
+    val m = Map(1 -> 2, 2 -> 3, 3 -> 4)
+    m(2)
+  } ensuring(_ == 3)
+
+  def map2(): Boolean = {
+    val m1 = Map[Int, Int]()
+    val m2 = Map.empty[Int, Int]
+    m1 == m2
+  } holds
+
+}
diff --git a/src/test/resources/regression/verification/purescala/valid/MySet.scala b/src/test/resources/regression/verification/purescala/valid/MySet.scala
new file mode 100644
index 000000000..3b6fdf42f
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/valid/MySet.scala
@@ -0,0 +1,16 @@
+import leon.Utils._
+
+object MySet {
+
+  def set1(): Boolean = {
+    val s = Set(1, 2, 3, 4)
+    s.contains(3)
+  } holds
+
+  def set2(): Boolean = {
+    val s1 = Set[Int]()
+    val s2 = Set.empty[Int]
+    s1 == s2
+  } holds
+
+}
diff --git a/src/test/scala/leon/test/codegen/CodeGenEvaluation.scala b/src/test/scala/leon/test/codegen/CodeGenEvaluation.scala
index 20f41f641..13d4a4948 100644
--- a/src/test/scala/leon/test/codegen/CodeGenEvaluation.scala
+++ b/src/test/scala/leon/test/codegen/CodeGenEvaluation.scala
@@ -164,7 +164,6 @@ object Sets {
     val unit = out.result.get
 
     def asIntSet(e : Expr) : Option[Set[Int]] = e match {
-      case EmptySet(_) => Some(Set.empty)
       case FiniteSet(es) =>
         val ois = es.map(_ match {
           case IntLiteral(v) => Some(v)
diff --git a/src/test/scala/leon/test/solvers/z3/BugWithEmptySet.scala b/src/test/scala/leon/test/solvers/z3/BugWithEmptySet.scala
deleted file mode 100644
index 569dba2a4..000000000
--- a/src/test/scala/leon/test/solvers/z3/BugWithEmptySet.scala
+++ /dev/null
@@ -1,51 +0,0 @@
-package leon.test.solvers.z3
-
-import leon.LeonContext
-import leon.SilentReporter
-
-import leon.purescala.Common._
-import leon.purescala.Definitions._
-import leon.purescala.Trees._
-import leon.purescala.TreeOps._
-import leon.purescala.TypeTrees._
-
-import leon.solvers.Solver
-import leon.solvers.z3.UninterpretedZ3Solver
-
-import org.scalatest.FunSuite
-
-class BugWithEmptySet extends FunSuite {
-  private val emptyProgram = Program(FreshIdentifier("empty"), ObjectDef(FreshIdentifier("empty"), Nil, Nil))
-
-  test("No distinction between Set() and Set.empty") {
-    val tInt = Int32Type
-    val tIntSet = SetType(Int32Type)
-
-    val e1 = EmptySet(tInt).setType(tIntSet)
-    assert(e1.getType === tIntSet)
-
-    val e2 = FiniteSet(Nil).setType(tIntSet)
-    assert(e2.getType === tIntSet)
-
-    val s0 = FiniteSet(Seq(IntLiteral(0))).setType(tIntSet)
-
-    val f1 = Equals(e1, e2)
-
-    val silentContext = LeonContext(reporter = new SilentReporter)
-    val solver : Solver = new UninterpretedZ3Solver(silentContext)
-    solver.setProgram(emptyProgram)
-
-    assert(solver.solve(f1) === Some(true),
-           "Z3 should prove the equivalence between Ø and {}.")
-
-    val f2 = Equals(e1, SetDifference(e1, s0))
-
-    assert(solver.solve(f2) === Some(true),
-           """Z3 should prove Ø = Ø \ {0}""")
-
-    val f3 = Equals(e2, SetDifference(e2, s0))
-
-    assert(solver.solve(f3) === Some(true),
-           """Z3 should prove {} = {} \ {0}""")
-  } 
-}
diff --git a/src/test/scala/leon/test/solvers/z3/BugWithEmptySetNewAPI.scala b/src/test/scala/leon/test/solvers/z3/BugWithEmptySetNewAPI.scala
deleted file mode 100644
index 98cf97075..000000000
--- a/src/test/scala/leon/test/solvers/z3/BugWithEmptySetNewAPI.scala
+++ /dev/null
@@ -1,70 +0,0 @@
-package leon.test.solvers.z3
-
-import leon.LeonContext
-import leon.SilentReporter
-
-import leon.purescala.Common._
-import leon.purescala.Definitions._
-import leon.purescala.Trees._
-import leon.purescala.TreeOps._
-import leon.purescala.TypeTrees._
-
-import leon.solvers.Solver
-import leon.solvers.z3.{AbstractZ3Solver, UninterpretedZ3Solver}
-
-import org.scalatest.FunSuite
-
-class BugWithEmptySetNewAPI extends FunSuite {
-  private val emptyProgram = Program(FreshIdentifier("empty"), ObjectDef(FreshIdentifier("empty"), Nil, Nil))
-
-  test("No distinction between Set() and Set.empty") {
-    val tInt = Int32Type
-    val tIntSet = SetType(Int32Type)
-
-    val e1 = EmptySet(tInt).setType(tIntSet)
-    assert(e1.getType === tIntSet)
-
-    val e2 = FiniteSet(Nil).setType(tIntSet)
-    assert(e2.getType === tIntSet)
-
-    val s0 = FiniteSet(Seq(IntLiteral(0))).setType(tIntSet)
-
-    val f1 = Equals(e1, e2)
-
-    val silentContext = LeonContext(reporter = new SilentReporter)
-    val solver : AbstractZ3Solver = new UninterpretedZ3Solver(silentContext)
-    solver.setProgram(emptyProgram)
-    solver.restartZ3
-
-
-    val subSolver = solver.getNewSolver
-
-    subSolver.push()
-    subSolver.assertCnstr(Not(f1))
-
-
-    assert(subSolver.check === Some(false),
-           "Z3 should prove the equivalence between Ø and {}.")
-
-    subSolver.pop(1)
-
-    val f2 = Equals(e1, SetDifference(e1, s0))
-
-    subSolver.push()
-    subSolver.assertCnstr(Not(f2))
-
-    assert(subSolver.check === Some(false),
-           """Z3 should prove Ø = Ø \ {0}""")
-
-
-    subSolver.pop(1)
-
-    val f3 = Equals(e2, SetDifference(e2, s0))
-
-    subSolver.push()
-    subSolver.assertCnstr(Not(f3))
-
-    assert(subSolver.check === Some(false),
-           """Z3 should prove {} = {} \ {0}""")
-  } 
-}
-- 
GitLab