From ed632f4da84b18eb36dfcc02e0e9e617082cea10 Mon Sep 17 00:00:00 2001
From: Philippe Suter <philippe.suter@gmail.com>
Date: Mon, 26 Apr 2010 19:27:57 +0000
Subject: [PATCH] still in the
 "breaking-before-I'll-fix-it-all-again-and-like-will-be-wonderful-with-rainbows-and-unicorns"
 phase.

---
 src/funcheck/CodeExtraction.scala        |  14 +-
 src/funcheck/purescala/Definitions.scala |  11 +-
 src/funcheck/purescala/Symbols.scala     | 188 ++++++------
 src/funcheck/purescala/Trees.scala       | 357 +++++------------------
 src/funcheck/purescala/TypeTrees.scala   |  18 +-
 5 files changed, 198 insertions(+), 390 deletions(-)

diff --git a/src/funcheck/CodeExtraction.scala b/src/funcheck/CodeExtraction.scala
index e50d91ffe..b9b50f6cc 100644
--- a/src/funcheck/CodeExtraction.scala
+++ b/src/funcheck/CodeExtraction.scala
@@ -19,7 +19,7 @@ trait CodeExtraction extends Extractors {
     import scala.collection.mutable.HashMap
 
     // register where the symbols where extracted from
-    val symbolDefMap = new HashMap[purescala.Symbols.Symbol,Tree]
+    // val symbolDefMap = new HashMap[purescala.Symbols.Symbol,Tree]
 
     def s2ps(tree: Tree): Expr = toPureScala(unit)(tree) match {
       case Some(ex) => ex
@@ -28,7 +28,7 @@ trait CodeExtraction extends Extractors {
 
     /** Populates the symbolDefMap with object and class symbols, and returns
      * the symbol corresponding to the expected single top-level object. */
-    def extractClassSymbols: purescala.Symbols.ObjectSymbol = {
+    def extractClassSymbols: ObjectDef = {
       val top = unit.body match {
         case p @ PackageDef(name, lst) if lst.size == 0 => {
           unit.error(p.pos, "No top-level definition found.")
@@ -54,13 +54,13 @@ trait CodeExtraction extends Extractors {
       top.get
     }
 
-    def extractObjectSym(name: Identifier, tmpl: Template): purescala.Symbols.ObjectSymbol = {
+    def extractObjectSym(name: Identifier, tmpl: Template): ObjectDef = {
       // we assume that the template actually corresponds to an object
       // definition. Typically it should have been obtained from the proper
       // extractor (ExObjectDef)
 
-      var classSyms: List[purescala.Symbols.ClassSymbol] = Nil
-      var objectSyms: List[purescala.Symbols.ObjectSymbol] = Nil
+      var classDefs: List[ClassTypeDef] = Nil
+      var objectDefs: List[purescala.Symbols.ObjectSymbol] = Nil
 
       tmpl.body.foreach(tree => tree match {
         case ExObjectDef(o2, t2) => { objectSyms = extractObjectSym(o2, t2) :: objectSyms }
@@ -68,10 +68,10 @@ trait CodeExtraction extends Extractors {
         case _ => ;
       })
 
-      val theSym = new purescala.Symbols.ObjectSymbol(name, classSyms.reverse, objectSyms.reverse)
+      // val theSym = new purescala.Symbols.ObjectSymbol(name, classSyms.reverse, objectSyms.reverse)
       // we register the tree associated to the symbol to be able to fill in
       // the rest later
-      symbolDefMap(theSym) = tmpl
+      // symbolDefMap(theSym) = tmpl
       theSym
     }
 
diff --git a/src/funcheck/purescala/Definitions.scala b/src/funcheck/purescala/Definitions.scala
index dc5d6a206..fcc92c6d0 100644
--- a/src/funcheck/purescala/Definitions.scala
+++ b/src/funcheck/purescala/Definitions.scala
@@ -39,20 +39,25 @@ object Definitions {
   }
 
   /** A VarDecl declares a new identifier to be of a certain type. */
-  final case class VarDecl(id: Identifier, tpe: TypeTree) {
+  case class VarDecl(id: Identifier, tpe: TypeTree) extends Typed {
     val uniqueID: Int = UniqueID(id.toString)
+
     override val toString: String = id + uniqueID
+
     override def equals(other: Any) = other match {
       case v: VarDecl => this.equals(v) && uniqueID == v.uniqueID
       case _ => false
     }
+
+    override def getType = tpe
+    override def setType(tt: TypeTree) = scala.Predef.error("Can't set type of VarDecl.")
   }
 
   type VarDecls = Seq[VarDecl]
 
   /** A wrapper for a program. For now a program is simply a single object. The
-   * name is meaningless and we just use the package name. */
-  final case class Program(id: Identifier, mainObject: ObjectDef) extends Definition {
+   * name is meaningless and we just use the package name as id. */
+  case class Program(id: Identifier, mainObject: ObjectDef) extends Definition {
     override val parentScope = None
 
     override def lookupObject(id: Identifier) = {
diff --git a/src/funcheck/purescala/Symbols.scala b/src/funcheck/purescala/Symbols.scala
index 42fcc1c4f..b1c310f8f 100644
--- a/src/funcheck/purescala/Symbols.scala
+++ b/src/funcheck/purescala/Symbols.scala
@@ -3,99 +3,101 @@ package funcheck.purescala
 import Common._
 import TypeTrees._
 
+object Symbols { /* dummy */ }
+
 /** There's a need for symbols, as we have purely functional trees with
  * potential recursive calls, and we want references to be resolved once and
  * for all. */
-object Symbols {
-  trait Symbolic {
-    self =>
-
-    private var __s: Option[Symbol] = None
-
-    def symbol: Symbol = __s.getOrElse(throw new Exception("Undefined symbol."))
-
-    def setSymbol(s: Symbol): self.type = __s match {
-      case Some(_) => throw new Exception("Symbol already set.")
-      case None => { __s = Some(s); this }
-    }
-  }
-
-  sealed abstract class Symbol {
-    val id: Identifier
-  }
-  
-  class VariableSymbol(val id: Identifier, val tpe: TypeTree) extends Typed {
-    def getType = tpe
-  }
-
-  // The object and class members have to be known at construction time. The
-  // typed members can be added anytime.
-  class ObjectSymbol(
-    val id: Identifier,
-    val classes: Seq[ClassSymbol],
-    val objects: Seq[ObjectSymbol]) extends Symbol {
-
-    private var _fields: List[VariableSymbol] = Nil
-    private var _functions: List[FunctionSymbol] = Nil
-
-    def fields: Seq[VariableSymbol] = _fields
-    def  functions: Seq[FunctionSymbol] = _functions
-
-    def registerField(f: VariableSymbol): ObjectSymbol = {
-      _fields = _fields ::: List(f)
-      this
-    }
-
-    def registerFunction(f: FunctionSymbol): ObjectSymbol = {
-      _functions = _functions ::: List(f)
-      this
-    }
-
-    override def toString: String = withInc(0)
-
-    private def withInc(inc: Int): String = {
-      val ii: String = "    " * inc
-      ii + "[object: " + id + "\n" +
-      (if(!fields.isEmpty) {
-        ii + " fields: " + fields.map(_.toString).mkString("{ ", ", ", " }") + "\n"
-      } else { "" }) +
-      (if(!functions.isEmpty) {
-        ii + " functions: " + functions.map(_.toString).mkString("{ ", ", ", " }") + "\n"
-      } else { "" }) +
-      (if(!classes.isEmpty) {
-        ii + " classes: " + classes.map(_.toString).mkString("{ ", ", ", " }") + "\n" 
-      } else { "" }) +
-      (if(!objects.isEmpty) {
-        ii + " objects: " + objects.map(_.withInc(inc+1)).mkString("{\n", ",\n", "\n" + ii + " }") + "\n"
-      } else { "" }) +
-      ii + "]"
-    }
-  }
-
-  sealed abstract class ClassSymbol extends Symbol {
-    val parents: Seq[AbstractClassSymbol]
-
-    protected val _pfx: String
-
-    override def toString = "[" + _pfx + ": " + id + (if (!parents.isEmpty) { " extends " + parents.mkString(", ") } else { "" }) + "]"
-  }
-
-  /** Symbols for abstract classes (or traits) */
-  class AbstractClassSymbol(val id: Identifier, val parents: Seq[AbstractClassSymbol]) extends ClassSymbol {
-    override protected val _pfx = "abstract class"
-  }
-
-  /** Symbols for "regular" (= non-abstract, non-case) classes */
-  class RefClassSymbol(val id: Identifier, val parents: Seq[AbstractClassSymbol]) extends ClassSymbol {
-    override protected val _pfx = "class"
-  }
-
-  /** Symbols for case classes. */
-  class CaseClassSymbol(val id: Identifier, val parents: Seq[AbstractClassSymbol]) extends ClassSymbol {
-    override protected val _pfx = "case class"
-  }
-
-  class FunctionSymbol(val id: Identifier, val params: Seq[VariableSymbol], val returnType: TypeTree) extends Typed {
-    def getType = returnType
-  }
-}
+// object Symbols {
+//   trait Symbolic {
+//     self =>
+// 
+//     private var __s: Option[Symbol] = None
+// 
+//     def symbol: Symbol = __s.getOrElse(throw new Exception("Undefined symbol."))
+// 
+//     def setSymbol(s: Symbol): self.type = __s match {
+//       case Some(_) => throw new Exception("Symbol already set.")
+//       case None => { __s = Some(s); this }
+//     }
+//   }
+// 
+//   sealed abstract class Symbol {
+//     val id: Identifier
+//   }
+//   
+//   class VariableSymbol(val id: Identifier, val tpe: TypeTree) extends Typed {
+//     def getType = tpe
+//   }
+// 
+//   // The object and class members have to be known at construction time. The
+//   // typed members can be added anytime.
+//   class ObjectSymbol(
+//     val id: Identifier,
+//     val classes: Seq[ClassSymbol],
+//     val objects: Seq[ObjectSymbol]) extends Symbol {
+// 
+//     private var _fields: List[VariableSymbol] = Nil
+//     private var _functions: List[FunctionSymbol] = Nil
+// 
+//     def fields: Seq[VariableSymbol] = _fields
+//     def  functions: Seq[FunctionSymbol] = _functions
+// 
+//     def registerField(f: VariableSymbol): ObjectSymbol = {
+//       _fields = _fields ::: List(f)
+//       this
+//     }
+// 
+//     def registerFunction(f: FunctionSymbol): ObjectSymbol = {
+//       _functions = _functions ::: List(f)
+//       this
+//     }
+// 
+//     override def toString: String = withInc(0)
+// 
+//     private def withInc(inc: Int): String = {
+//       val ii: String = "    " * inc
+//       ii + "[object: " + id + "\n" +
+//       (if(!fields.isEmpty) {
+//         ii + " fields: " + fields.map(_.toString).mkString("{ ", ", ", " }") + "\n"
+//       } else { "" }) +
+//       (if(!functions.isEmpty) {
+//         ii + " functions: " + functions.map(_.toString).mkString("{ ", ", ", " }") + "\n"
+//       } else { "" }) +
+//       (if(!classes.isEmpty) {
+//         ii + " classes: " + classes.map(_.toString).mkString("{ ", ", ", " }") + "\n" 
+//       } else { "" }) +
+//       (if(!objects.isEmpty) {
+//         ii + " objects: " + objects.map(_.withInc(inc+1)).mkString("{\n", ",\n", "\n" + ii + " }") + "\n"
+//       } else { "" }) +
+//       ii + "]"
+//     }
+//   }
+// 
+//   sealed abstract class ClassSymbol extends Symbol {
+//     val parents: Seq[AbstractClassSymbol]
+// 
+//     protected val _pfx: String
+// 
+//     override def toString = "[" + _pfx + ": " + id + (if (!parents.isEmpty) { " extends " + parents.mkString(", ") } else { "" }) + "]"
+//   }
+// 
+//   /** Symbols for abstract classes (or traits) */
+//   class AbstractClassSymbol(val id: Identifier, val parents: Seq[AbstractClassSymbol]) extends ClassSymbol {
+//     override protected val _pfx = "abstract class"
+//   }
+// 
+//   /** Symbols for "regular" (= non-abstract, non-case) classes */
+//   class RefClassSymbol(val id: Identifier, val parents: Seq[AbstractClassSymbol]) extends ClassSymbol {
+//     override protected val _pfx = "class"
+//   }
+// 
+//   /** Symbols for case classes. */
+//   class CaseClassSymbol(val id: Identifier, val parents: Seq[AbstractClassSymbol]) extends ClassSymbol {
+//     override protected val _pfx = "case class"
+//   }
+// 
+//   class FunctionSymbol(val id: Identifier, val params: Seq[VariableSymbol], val returnType: TypeTree) extends Typed {
+//     def getType = returnType
+//   }
+// }
diff --git a/src/funcheck/purescala/Trees.scala b/src/funcheck/purescala/Trees.scala
index 912765cee..f995ded93 100644
--- a/src/funcheck/purescala/Trees.scala
+++ b/src/funcheck/purescala/Trees.scala
@@ -9,66 +9,30 @@ object Trees {
 
   /* EXPRESSIONS */
 
-  /** There's no such thing as a typing phase for these trees, they need to be
-   * correctly typed at construction time. Each AST node checks that the
-   * children provided satisfy whatever typing constraints are required by the
-   * node, and each node is then responsible for communicating its type. */
   sealed abstract class Expr extends Typed {
     override def toString: String = PrettyPrinter(this)
 
-    private var _scope: Option[Scope] = None
+    // private var _scope: Option[Scope] = None
+    //
+    // def scope: Scope =
+    //   if(_scope.isEmpty)
+    //     throw new Exception("Undefined scope.")
+    //   else
+    //     _scope.get
 
-    def scope: Scope =
-      if(_scope.isEmpty)
-        throw new Exception("Undefined scope.")
-      else
-        _scope.get
-
-    def scope_=(s: Scope): Unit = {
-      if(_scope.isEmpty) {
-        _scope = Some(s)
-      } else {
-        throw new Exception("Redefining scope.")
-      }
-    }
+    // def scope_=(s: Scope): Unit = {
+    //   if(_scope.isEmpty) {
+    //     _scope = Some(s)
+    //   } else {
+    //     throw new Exception("Redefining scope.")
+    //   }
+    // }
   }
 
-  /** 
-   equality on sets, ADTs etc. (equality on function types?!)
-
-   forall, exists - optionally bounded quantifiers
-     * comes with type A of bound variable 
-     * also comes with an optional Set[A] that gives more precise description of the range of this variable
-
-    Without Set[A] bound, the variable ranges over all constructible (not only allocated) objects.
-
-see examples in:
-     http://code.google.com/p/scalacheck/wiki/UserGuide
-   */
-
   /* Control flow */
-  case class FunctionInvocation(funDef: FunDef, args: Seq[Expr]) extends Expr {
-    assert(args.map(_.getType).corresponds(funDef.argTypes)(_ == _))
-    lazy val getType = funDef.returnType
-  }
-
-  case class IfExpr(cond: Expr, then: Expr, elze: Expr) extends Expr {
-    assert(cond.getType == BooleanType)
-    assert(then.getType == elze.getType)
-    def getType = then.getType
-  }
-
-  case class MatchExpr(scrutinee: Expr, cases: Seq[MatchCase]) extends Expr {
-    // there can be no assumption about the type of the scrutinee..  Scala
-    // gives nice errors "constructor cannot be instantiated to expected type"
-    // but that seems relatively hard to check at construction for now...
-    // Actually it only gives that error when the pattern is unapply (ie. not
-    // an "instanceOf" one), so there's hope.
-    
-    // we should assert that the rhs types of all MatchCases match !
-
-    lazy val getType = cases(0).rhs.getType
-  }
+  case class FunctionInvocation(funDef: FunDef, args: Seq[Expr]) extends Expr
+  case class IfExpr(cond: Expr, then: Expr, elze: Expr) extends Expr 
+  case class MatchExpr(scrutinee: Expr, cases: Seq[MatchCase]) extends Expr
 
   sealed abstract class MatchCase {
     val pattern: Pattern
@@ -76,9 +40,7 @@ see examples in:
   }
 
   case class SimpleCase(pattern: Pattern, rhs: Expr) extends MatchCase
-  case class GuardedCase(pattern: Pattern, guard: Expr, rhs: Expr) extends MatchCase {
-    assert(guard.getType == BooleanType)
-  }
+  case class GuardedCase(pattern: Pattern, guard: Expr, rhs: Expr) extends MatchCase
 
   sealed abstract class Pattern
   case class InstanceOfPattern(binder: Option[Identifier], classTypeDef: ClassTypeDef) extends Pattern // c: Class
@@ -86,257 +48,82 @@ see examples in:
   case class ExtractorPattern(binder: Option[Identifier], 
 			      extractor : ExtractorTypeDef, 
 			      subPatterns: Seq[Pattern]) extends Pattern // c @ Extractor(...,...)
-  // I suggest we skip Seq stars for now.
+  // We don't handle Seq stars for now.
 
   /* Propositional logic */
-  case class And(exprs: Seq[Expr]) extends Expr {
-    assert(exprs.forall(_.getType == BooleanType))
-    def getType = BooleanType
-  }
-
-  case class Or(exprs: Seq[Expr]) extends Expr {
-    assert(exprs.forall(_.getType == BooleanType))
-    def getType = BooleanType
-  }
-
-  case class Not(expr: Expr) extends Expr {
-    assert(expr.getType == BooleanType)
-    def getType = BooleanType
-  }
-
-  /* Not sure if we should really have these.. I suppose they could be of some
-   * help to some theorem provers? *
-  case class Implies(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == BooleanType && rhs.getType == BooleanType)
-    def getType = BooleanType
-  }
-
-  case class Iff(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == BooleanType && rhs.getType == BooleanType)
-    def getType = BooleanType
-  } */
+  case class And(exprs: Seq[Expr]) extends Expr
+  case class Or(exprs: Seq[Expr]) extends Expr
+  case class Not(expr: Expr) extends Expr 
 
   /* Maybe we should split this one depending on types? */
-  case class Equals(left: Expr, right: Expr) extends Expr { 
-    assert(left.getType == right.getType)
-    val getType = BooleanType
-  }
+  case class Equals(left: Expr, right: Expr) extends Expr  
   
   /* Literals */
   // to be fixed! Should contain a reference to the definition of that
   // variable, which would also give us its type.
-  case class Variable(id: Identifier) extends Expr {
-    val getType = AnyType
-  }
+  case class Variable(id: Identifier) extends Expr
 
-  case class IntLiteral(value: Int) extends Expr {
-    val getType = Int32Type
+  sealed abstract class Literal[T] extends Expr {
+    val value: T
   }
 
-  case class BooleanLiteral(value: Boolean) extends Expr {
-    val getType = BooleanType
-  }
+  case class IntLiteral(value: Int) extends Literal[Int] 
+  case class BooleanLiteral(value: Boolean) extends Literal[Boolean] 
 
   /* Arithmetic */
-  case class Plus(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = Int32Type
-  }
-
-  case class Minus(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = Int32Type
-  }
-
-  case class UMinus(expr: Expr) extends Expr {
-    assert(expr.getType == Int32Type)
-    val getType = Int32Type
-  }
-
-  case class Times(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = Int32Type
-  }
-
-  case class Division(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = Int32Type
-  }
-
-  case class LessThan(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = BooleanType
-  }
-
-  case class GreaterThan(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = BooleanType
-  }
-
-  case class LessEquals(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = BooleanType
-  }
-
-  case class GreaterEquals(lhs: Expr, rhs: Expr) extends Expr {
-    assert(lhs.getType == Int32Type && rhs.getType == Int32Type)
-    val getType = BooleanType
-  }
+  case class Plus(lhs: Expr, rhs: Expr) extends Expr
+  case class Minus(lhs: Expr, rhs: Expr) extends Expr 
+  case class UMinus(expr: Expr) extends Expr 
+  case class Times(lhs: Expr, rhs: Expr) extends Expr 
+  case class Division(lhs: Expr, rhs: Expr) extends Expr 
+  case class LessThan(lhs: Expr, rhs: Expr) extends Expr 
+  case class GreaterThan(lhs: Expr, rhs: Expr) extends Expr 
+  case class LessEquals(lhs: Expr, rhs: Expr) extends Expr 
+  case class GreaterEquals(lhs: Expr, rhs: Expr) extends Expr 
 
   /* Option expressions */
-  case class OptionSome(value: Expr) extends Expr {
-    lazy val getType = OptionType(value.getType)
-  }
-
-  case class OptionNone(baseType: TypeTree) extends Expr {
-    lazy val getType = OptionType(baseType)
-  }
+  case class OptionSome(value: Expr) extends Expr 
+  case class OptionNone(baseType: TypeTree) extends Expr 
 
   /* Set expressions */
-  case class EmptySet(baseType: TypeTree) extends Expr {
-    lazy val getType = SetType(baseType)
-  }
-  case class FiniteSet(elements: Seq[Expr]) extends Expr {
-    assert(elements.size > 0)
-    assert(elements.drop(1).forall(_.getType == elements(0).getType))
-    lazy val getType = SetType(elements(0).getType)
-  }
-  case class ElementOfSet(element: Expr, set: Expr) extends Expr {
-    assert(set.getType == SetType(element.getType))
-    val getType = BooleanType
-  }
-  case class IsEmptySet(set: Expr) extends Expr {
-    assert(set.getType.isInstanceOf[SetType])
-    val getType = BooleanType
-  }
-  case class SetEquals(set1: Expr, set2: Expr) extends Expr {
-    assert(set1.getType == set2.getType && set1.getType.isInstanceOf[SetType])
-    val getType = BooleanType
-  }
-  case class SetCardinality(set: Expr) extends Expr {
-    assert(set.getType.isInstanceOf[SetType])
-    val getType = Int32Type
-  }
-  case class SubsetOf(set1: Expr, set2: Expr) extends Expr {
-    assert(set1.getType == set2.getType && set1.getType.isInstanceOf[SetType])
-    val getType = BooleanType
-  }
-  case class SetIntersection(set1: Expr, set2: Expr) extends Expr {
-    assert(set1.getType == set2.getType && set1.getType.isInstanceOf[SetType])
-    lazy val getType = set1.getType
-  }
-  case class SetUnion(set1: Expr, set2: Expr) extends Expr {
-    assert(set1.getType == set2.getType && set1.getType.isInstanceOf[SetType])
-    lazy val getType = set1.getType
-  }
-  case class SetDifference(set1: Expr, set2: Expr) extends Expr {
-    assert(set1.getType == set2.getType && set1.getType.isInstanceOf[SetType])
-    lazy val getType = set1.getType
-  }
+  case class EmptySet(baseType: TypeTree) extends Expr 
+  case class FiniteSet(elements: Seq[Expr]) extends Expr 
+  case class ElementOfSet(element: Expr, set: Expr) extends Expr 
+  case class IsEmptySet(set: Expr) extends Expr 
+  case class SetEquals(set1: Expr, set2: Expr) extends Expr 
+  case class SetCardinality(set: Expr) extends Expr 
+  case class SubsetOf(set1: Expr, set2: Expr) extends Expr 
+  case class SetIntersection(set1: Expr, set2: Expr) extends Expr 
+  case class SetUnion(set1: Expr, set2: Expr) extends Expr 
+  case class SetDifference(set1: Expr, set2: Expr) extends Expr 
 
   /* Multiset expressions */
-  case class EmptyMultiset(baseType: TypeTree) extends Expr {
-    lazy val getType = MultisetType(baseType)
-  }
-  case class FiniteMultiset(elements: Seq[Expr]) extends Expr {
-    assert(elements.size > 0)
-    assert(elements.drop(1).forall(_.getType == elements(0).getType))
-    lazy val getType = MultisetType(elements(0).getType)
-  }
-  case class Multiplicity(element: Expr, multiset: Expr) extends Expr {
-    assert(multiset.getType == MultisetType(element.getType))
-    val getType = Int32Type
-  }
-  case class IsEmptyMultiset(multiset: Expr) extends Expr {
-    assert(multiset.getType.isInstanceOf[MultisetType])
-    val getType = BooleanType
-  }
-  case class MultisetEquals(multiset1: Expr, multiset2: Expr) extends Expr {
-    assert(multiset1.getType == multiset2.getType && multiset1.getType.isInstanceOf[MultisetType])
-    val getType = BooleanType
-  }
-  case class MultisetCardinality(multiset: Expr) extends Expr {
-    assert(multiset.getType.isInstanceOf[MultisetType])
-    val getType = Int32Type
-  }
-  case class SubmultisetOf(multiset1: Expr, multiset2: Expr) extends Expr {
-    assert(multiset1.getType == multiset2.getType && multiset1.getType.isInstanceOf[MultisetType])
-    val getType = BooleanType
-  }
-  case class MultisetIntersection(multiset1: Expr, multiset2: Expr) extends Expr {
-    assert(multiset1.getType == multiset2.getType && multiset1.getType.isInstanceOf[MultisetType])
-    lazy val getType = multiset1.getType
-  }
-  case class MultisetUnion(multiset1: Expr, multiset2: Expr) extends Expr {
-    assert(multiset1.getType == multiset2.getType && multiset1.getType.isInstanceOf[MultisetType])
-    lazy val getType = multiset1.getType
-  }
-  case class MultisetPlus(multiset1: Expr, multiset2: Expr) extends Expr { // disjoint union
-    assert(multiset1.getType == multiset2.getType && multiset1.getType.isInstanceOf[MultisetType])
-    lazy val getType = multiset1.getType
-  }
-  case class MultisetDifference(multiset1: Expr, multiset2: Expr) extends Expr {
-    assert(multiset1.getType == multiset2.getType && multiset1.getType.isInstanceOf[MultisetType])
-    lazy val getType = multiset1.getType
-  }
+  // case class EmptyMultiset(baseType: TypeTree) extends Expr 
+  // case class FiniteMultiset(elements: Seq[Expr]) extends Expr 
+  // case class Multiplicity(element: Expr, multiset: Expr) extends Expr 
+  // case class IsEmptyMultiset(multiset: Expr) extends Expr 
+  // case class MultisetEquals(multiset1: Expr, multiset2: Expr) extends Expr 
+  // case class MultisetCardinality(multiset: Expr) extends Expr 
+  // case class SubmultisetOf(multiset1: Expr, multiset2: Expr) extends Expr 
+  // case class MultisetIntersection(multiset1: Expr, multiset2: Expr) extends Expr 
+  // case class MultisetUnion(multiset1: Expr, multiset2: Expr) extends Expr 
+  // case class MultisetPlus(multiset1: Expr, multiset2: Expr) extends Expr // disjoint union
+  // case class MultisetDifference(multiset1: Expr, multiset2: Expr) extends Expr 
 
   /* Map operations. */
-  case class EmptyMap(fromType: TypeTree, toType: TypeTree) extends Expr {
-    lazy val getType = MapType(fromType, toType)
-  }
-
-  case class SingletonMap(from: Expr, to: Expr) extends Expr {
-    lazy val getType = MapType(from.getType, to.getType)
-  }
+  case class EmptyMap(fromType: TypeTree, toType: TypeTree) extends Expr 
+  case class SingletonMap(from: Expr, to: Expr) extends Expr 
+  case class FiniteMap(singletons: Seq[SingletonMap]) extends Expr 
 
-  case class FiniteMap(singletons: Seq[SingletonMap]) extends Expr {
-    assert(singletons.size > 0
-      && singletons.drop(1).forall(_.getType == singletons(0).getType))
-    lazy val getType = singletons(0).getType
-  }
-
-  case class MapGet(map: Expr, key: Expr) extends Expr {
-    assert(map.getType.isInstanceOf[MapType] && key.getType == map.getType.asInstanceOf[MapType].from)
-    lazy val getType = OptionType(map.getType.asInstanceOf[MapType].to)
-  }
-
-  case class MapUnion(map1: Expr, map2: Expr) extends Expr {
-    assert(map1.getType.isInstanceOf[MapType] && map1.getType == map2.getType)
-    lazy val getType = map1.getType
-  }
-
-  case class MapDiffrence(map: Expr, keys: Expr) extends Expr {
-    assert(map.getType.isInstanceOf[MapType] && keys.isInstanceOf[SetType] && map.getType.asInstanceOf[MapType].from == keys.getType.asInstanceOf[SetType].base)
-    lazy val getType = map.getType
-  }
+  case class MapGet(map: Expr, key: Expr) extends Expr 
+  case class MapUnion(map1: Expr, map2: Expr) extends Expr 
+  case class MapDiffrence(map: Expr, keys: Expr) extends Expr 
 
   /* List operations */
-  case class NilList(baseType: TypeTree) extends Expr {
-    lazy val getType = ListType(baseType)
-  }
-
-  case class Cons(head: Expr, tail: Expr) extends Expr {
-    assert(tail.isInstanceOf[ListType] && tail.getType.asInstanceOf[ListType].base == head.getType)
-    lazy val getType = tail.getType
-  }
-
-  case class Car(list: Expr) extends Expr {
-    assert(list.getType.isInstanceOf[ListType])
-    lazy val getType = list.getType.asInstanceOf[ListType].base
-  }
-
-  case class Cdr(list: Expr) extends Expr {
-    assert(list.getType.isInstanceOf[ListType])
-    lazy val getType = list.getType
-  }
-
-  case class Concat(list1: Expr, list2: Expr) extends Expr {
-    assert(list1.getType.isInstanceOf[ListType] && list1.getType == list2.getType)
-    lazy val getType = list1.getType
-  }
-
-  case class ListAt(list: Expr, index: Expr) extends Expr {
-    assert(list.getType.isInstanceOf[ListType] && index.getType == Int32Type)
-    lazy val getType = OptionType(list.getType.asInstanceOf[ListType].base)
-  }
+  case class NilList(baseType: TypeTree) extends Expr 
+  case class Cons(head: Expr, tail: Expr) extends Expr 
+  case class Car(list: Expr) extends Expr 
+  case class Cdr(list: Expr) extends Expr 
+  case class Concat(list1: Expr, list2: Expr) extends Expr 
+  case class ListAt(list: Expr, index: Expr) extends Expr 
 }
diff --git a/src/funcheck/purescala/TypeTrees.scala b/src/funcheck/purescala/TypeTrees.scala
index 54ec17162..1ff91b436 100644
--- a/src/funcheck/purescala/TypeTrees.scala
+++ b/src/funcheck/purescala/TypeTrees.scala
@@ -6,13 +6,27 @@ object TypeTrees {
   import Definitions._
 
   trait Typed {
-    def getType: TypeTree
+    self =>
+
+    var _type: Option[TypeTree] = None
+
+    def getType: TypeTree = _type match {
+      case None => NoType
+      case Some(t) => t
+    }
+
+    def setType(tt: TypeTree): self.type = _type match {
+      case None => _type = Some(tt); this
+      case Some(_) => scala.Predef.error("Resetting type information.")
+    }
   }
 
   sealed abstract class TypeTree {
     override def toString: String = PrettyPrinter(this)
   }
 
+  case object NoType extends TypeTree
+
   case object AnyType extends TypeTree
   case object BooleanType extends TypeTree
   case object Int32Type extends TypeTree
@@ -21,7 +35,7 @@ object TypeTrees {
   case class TupleType(bases: Seq[TypeTree]) extends TypeTree { lazy val dimension: Int = bases.length }
   case class FunctionType(arg: TypeTree, res: TypeTree) extends TypeTree
   case class SetType(base: TypeTree) extends TypeTree
-  case class MultisetType(base: TypeTree) extends TypeTree
+  // case class MultisetType(base: TypeTree) extends TypeTree
   case class MapType(from: TypeTree, to: TypeTree) extends TypeTree
   case class ClassType(id: Identifier) extends TypeTree
   case class CaseClassType(id: Identifier) extends TypeTree
-- 
GitLab