diff --git a/build.sbt b/build.sbt
index 12e774b4a9bfbe67628ddbfad2bcdf712659c675..4de988e5dc18eb4aa5c9dbf6a9c8e7f6178f1ef9 100644
--- a/build.sbt
+++ b/build.sbt
@@ -10,6 +10,8 @@ scalacOptions += "-deprecation"
 
 scalacOptions += "-unchecked"
 
+javacOptions += "-Xlint:unchecked"
+
 libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.9.2"
 
 libraryDependencies += "org.scalatest" %% "scalatest" % "1.8" % "test"
diff --git a/src/main/java/leon/codegen/runtime/LeonCodeGenRuntimeException.java b/src/main/java/leon/codegen/runtime/LeonCodeGenRuntimeException.java
new file mode 100644
index 0000000000000000000000000000000000000000..24f37cb2b90755fe5a81d0dd593a8cfe9c8a0adf
--- /dev/null
+++ b/src/main/java/leon/codegen/runtime/LeonCodeGenRuntimeException.java
@@ -0,0 +1,13 @@
+package leon.codegen.runtime;
+
+public class LeonCodeGenRuntimeException extends Exception {
+    private final String msg;
+
+    public LeonCodeGenRuntimeException(String msg) {
+        this.msg = msg;
+    }
+
+    public String getMessage() {
+        return this.msg;
+    }
+}
diff --git a/src/main/java/leon/codegen/runtime/Map.java b/src/main/java/leon/codegen/runtime/Map.java
new file mode 100644
index 0000000000000000000000000000000000000000..b82ba05c9090677d713d0af74b9b8e937ae66c78
--- /dev/null
+++ b/src/main/java/leon/codegen/runtime/Map.java
@@ -0,0 +1,50 @@
+package leon.codegen.runtime;
+
+import java.util.Arrays;
+import java.util.TreeMap;
+
+/** If someone wants to make it an efficient implementation of immutable
+ *  sets, go ahead. */
+public final class Map {
+  private final TreeMap<Object,Object> _underlying;
+
+  protected final TreeMap<Object,Object> underlying() {
+    return _underlying;
+  }
+
+  public Map() {
+    _underlying = new TreeMap<Object,Object>();
+  }
+
+  // For Maps, it's simpler to build them by starting with empty and putting
+  // the elements in.
+  public void add(Object key, Object value) {
+    _underlying.put(key, value);
+  }
+
+  private Map(TreeMap<Object,Object> u) {
+    _underlying = u;
+  }
+
+  public boolean isDefinedAt(Object element) {
+    return underlying().containsKey(element);
+  }
+
+  public Object get(Object k) throws LeonCodeGenRuntimeException {
+    Object result = underlying().get(k);
+    if(result == null) {
+      throw new LeonCodeGenRuntimeException("Get of undefined key.");
+    }
+    return result;
+  }
+
+  public int size() {
+    return underlying().size();
+  }
+
+  public Map union(Map s) {
+    TreeMap<Object,Object> n = new TreeMap<Object,Object>(underlying());
+    n.putAll(s.underlying());
+    return new Map(n);
+  }
+}
diff --git a/src/main/java/leon/codegen/runtime/Set.java b/src/main/java/leon/codegen/runtime/Set.java
new file mode 100644
index 0000000000000000000000000000000000000000..df70fd057836ec84a85fc8f0be5750089c46257a
--- /dev/null
+++ b/src/main/java/leon/codegen/runtime/Set.java
@@ -0,0 +1,77 @@
+package leon.codegen.runtime;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+/** If someone wants to make it an efficient implementation of immutable
+ *  sets, go ahead. */
+public final class Set {
+  private final TreeSet<Object> _underlying;
+
+  protected final TreeSet<Object> underlying() {
+    return _underlying;
+  }
+
+  public Set() {
+    _underlying = new TreeSet<Object>();
+  }
+
+  public Set(Object[] elements) {
+    _underlying = new TreeSet<Object>(Arrays.asList(elements));
+  }
+
+  // Uses mutation!
+  public void add(Object e) {
+    _underlying.add(e);
+  }
+
+  public Iterator<Object> getElements() {
+    return _underlying.iterator();
+  }
+
+  private Set(TreeSet<Object> u) {
+    _underlying = u;
+  }
+
+  public boolean contains(Object element) {
+    return _underlying.contains(element);
+  }
+
+  public boolean subsetOf(Set s) {
+    for(Object o : _underlying) {
+      if(!s.underlying().contains(o)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public int size() {
+    return _underlying.size();
+  }
+
+  public Set union(Set s) {
+    TreeSet<Object> n = new TreeSet<Object>(underlying());
+    n.addAll(s.underlying());
+    return new Set(n);
+  }
+
+  public Set intersect(Set s) {
+    TreeSet<Object> n = new TreeSet<Object>();
+    for(Object o : _underlying) {
+      if(s.underlying().contains(o)) {
+        n.add(o);
+      }
+    }
+    return new Set(n);
+  }
+
+  public Set minus(Set s) {
+    TreeSet<Object> n = new TreeSet<Object>(_underlying);
+    for(Object o : s.underlying()) {
+      n.remove(o);
+    }
+    return new Set(n);
+  }
+}
diff --git a/src/main/java/leon/codegen/runtime/Tuple.java b/src/main/java/leon/codegen/runtime/Tuple.java
index c8f46923bdd47184264cf8ac73ce5a6b757de4fd..e010870ad1c17cceea99bce2725f6565eb5f7a53 100644
--- a/src/main/java/leon/codegen/runtime/Tuple.java
+++ b/src/main/java/leon/codegen/runtime/Tuple.java
@@ -3,25 +3,35 @@ package leon.codegen.runtime;
 import java.util.Arrays;
 
 public final class Tuple {
-  private int arity;
-  private Object[] elements;
+  private final Object[] elements;
 
   // You may think that using varargs here would show less of the internals,
   // however the bytecode is exactly the same, so let's reflect the reality
   // instead.
-  public Tuple(int arity, Object[] elements) {
-    this.arity = arity;
+  public Tuple(Object[] elements) {
     this.elements = Arrays.copyOf(elements, elements.length);
   }
 
   public final Object get(int index) {
-    if(index < 0 || index >= arity) {
+    if(index < 0 || index >= this.elements.length) {
         throw new IllegalArgumentException("Invalid tuple index : " + index);
     }
     return this.elements[index];
   }
 
   public final int getArity() {
-    return this.arity;
+    return this.elements.length;
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if(that == this) return true;
+    if(!(that instanceof Tuple)) return false;
+    Tuple other = (Tuple)that;
+    if(other.getArity() != this.getArity()) return false;
+    for(int i = 0; i < this.getArity(); i++) {
+        if(other.get(i) != this.get(i)) return false;
+    }
+    return true; 
   }
 }
diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index b585b5b1c36573d939be3b499379d59be3c19f94..7ed53e440042d9e0507391e86bd131ce0112c335 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -17,7 +17,8 @@ object CodeGeneration {
   private val BoxedIntClass = "java/lang/Integer"
   private val BoxedBoolClass = "java/lang/Boolean"
 
-  private val TupleClass = "leon/codegen/runtime/Tuple"
+  private val TupleClass     = "leon/codegen/runtime/Tuple"
+  private val SetClass       = "leon/codegen/runtime/Set"
   private val CaseClassClass = "leon/codegen/runtime/CaseClass"
 
   def defToJVMName(p : Program, d : Definition) : String = "Leon$CodeGen$" + d.id.uniqueName
@@ -30,9 +31,12 @@ object CodeGeneration {
     case c : ClassType =>
       env.classDefToClass(c.classDef).map(n => "L" + n + ";").getOrElse("Unsupported class " + c.id)
 
-    case t : TupleType =>
+    case _ : TupleType =>
       "L" + TupleClass + ";"
 
+    case _ : SetType =>
+      "L" + SetClass + ";"
+
     case _ => throw CompilationException("Unsupported type : " + tpe)
   }
 
@@ -49,7 +53,7 @@ object CodeGeneration {
       case Int32Type | BooleanType =>
         ch << IRETURN
 
-      case _ : ClassType | _ : TupleType =>
+      case _ : ClassType | _ : TupleType | _ : SetType =>
         ch << ARETURN
 
       case other =>
@@ -132,7 +136,7 @@ object CodeGeneration {
 
       case Tuple(es) =>
         ch << New(TupleClass) << DUP
-        ch << Ldc(es.size) << DUP
+        ch << Ldc(es.size)
         ch << NewArray("java/lang/Object")
         for((e,i) <- es.zipWithIndex) {
           ch << DUP
@@ -140,7 +144,7 @@ object CodeGeneration {
           mkBoxedExpr(e, ch)
           ch << AASTORE
         }
-        ch << InvokeSpecial(TupleClass, constructorName, "(I[Ljava/lang/Object;)V")
+        ch << InvokeSpecial(TupleClass, constructorName, "([Ljava/lang/Object;)V")
 
       case TupleSelect(t, i) =>
         val TupleType(bs) = t.getType
@@ -149,6 +153,46 @@ 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) {
+          ch << DUP
+          mkBoxedExpr(e, ch)
+          ch << InvokeVirtual(SetClass, "add", "(Ljava/lang/Object;)V")
+        }
+
+      case ElementOfSet(e, s) =>
+        mkExpr(s, ch)
+        mkBoxedExpr(e, ch)
+        ch << InvokeVirtual(SetClass, "contains", "(Ljava/lang/Object;)Z")
+
+      case SetCardinality(s) =>
+        mkExpr(s, ch)
+        ch << InvokeVirtual(SetClass, "size", "()I")
+
+      case SubsetOf(s1, s2) =>
+        mkExpr(s1, ch)
+        mkExpr(s2, ch)
+        ch << InvokeVirtual(SetClass, "subsetOf", "(L%s;)Z".format(SetClass))
+
+      case SetIntersection(s1, s2) =>
+        mkExpr(s1, ch)
+        mkExpr(s2, ch)
+        ch << InvokeVirtual(SetClass, "intersect", "(L%s;)L%s;".format(SetClass,SetClass))
+
+      case SetUnion(s1, s2) =>
+        mkExpr(s1, ch)
+        mkExpr(s2, ch)
+        ch << InvokeVirtual(SetClass, "union", "(L%s;)L%s;".format(SetClass,SetClass))
+
+      case SetDifference(s1, s2) =>
+        mkExpr(s1, ch)
+        mkExpr(s2, ch)
+        ch << InvokeVirtual(SetClass, "minus", "(L%s;)L%s;".format(SetClass,SetClass))
+
       case IfExpr(c, t, e) =>
         val tl = ch.getFreshLabel("then")
         val el = ch.getFreshLabel("else")
diff --git a/src/main/scala/leon/purescala/Trees.scala b/src/main/scala/leon/purescala/Trees.scala
index 6f5d2aff477af4e27369bb790f3d58084b3802f6..844152a3d07325efc40b9e86d23c8bdd728e6977 100644
--- a/src/main/scala/leon/purescala/Trees.scala
+++ b/src/main/scala/leon/purescala/Trees.scala
@@ -429,6 +429,8 @@ 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".
   case class ElementOfSet(element: Expr, set: Expr) extends Expr with FixedType {
     val fixedType = BooleanType
   }
diff --git a/src/test/resources/regression/codegen/Prog004.scala b/src/test/resources/regression/codegen/Prog004.scala
new file mode 100644
index 0000000000000000000000000000000000000000..cf5ece1a1a0e9d85ace9fbefdf4f70c43ffe7a15
--- /dev/null
+++ b/src/test/resources/regression/codegen/Prog004.scala
@@ -0,0 +1,17 @@
+object Prog004 {
+  def set1() : Set[Int] = {
+    Set(6, 7)
+  }
+
+  def set2() : Set[Int] = {
+    set1() ++ Set(4)
+  }
+
+  def set3() : Set[Int] = {
+    set2() ** set1()
+  }
+
+  def set4() : Set[Int] = {
+    set2() -- set1()
+  }
+}