/* NSC -- new Scala compiler * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ // $Id: TreeCheckers.scala 18387 2009-07-24 15:28:37Z odersky $ package scala.tools.nsc package typechecker import scala.tools.nsc.symtab.Flags._ import scala.tools.nsc.util.{Position, NoPosition} abstract class TreeCheckers extends Analyzer { import global._ val tpeOfTree = new scala.collection.mutable.HashMap[Tree, Type] def checkTrees { if (settings.verbose.value) Console.println("[consistency check at the beginning of phase " + phase + "]") for (unit <- currentRun.units) check(unit) } def check(unit: CompilationUnit) { informProgress("checking "+unit) val context = rootContext(unit) context.checking = true tpeOfTree.clear val checker = new TreeChecker(context) val unit0 = currentRun.currentUnit currentRun.currentUnit = unit checker.precheck.traverse(unit.body) checker.typed(unit.body) checker.postcheck.traverse(unit.body) currentRun.advanceUnit assert(currentRun.currentUnit == unit) currentRun.currentUnit = unit0 } override def newTyper(context: Context): Typer = new TreeChecker(context) class TreeChecker(context0: Context) extends Typer(context0) { import infer._ override def typed(tree: Tree, mode: Int, pt: Type): Tree = { tree match { case EmptyTree | TypeTree() => ; case _ => try { if (!tpeOfTree.contains(tree)) { tpeOfTree.update(tree, tree.tpe) tree.tpe = null } val newtree = super.typed(tree, mode, pt); if ((newtree ne tree) && !newtree.isInstanceOf[Literal]) error(tree.pos, "trees differ\n old: " + tree + " [" + tree.getClass() + "]\n new: " + newtree + " [" + newtree.getClass() + "]") } catch { case ex: Throwable => Console.println("exception while typing "+tree) throw ex } } tree } object precheck extends Traverser { override def traverse(tree: Tree) { try { tree match { case DefDef(_, _, _, _, _, _) => if (tree.symbol.hasFlag(ACCESSOR) && !tree.symbol.isDeferred && !tree.symbol.tpe.resultType.isInstanceOf[ConstantType]) { assert(tree.symbol.accessed != NoSymbol, tree.symbol) assert(tree.symbol.accessed.getter(tree.symbol.owner) == tree.symbol || tree.symbol.accessed.setter(tree.symbol.owner) == tree.symbol) } case ValDef(_, _, _, _) => if (tree.symbol.hasGetter) { assert(tree.symbol.getter(tree.symbol.owner) != NoSymbol, tree.symbol) } case Apply(_, args) => assert(args forall (EmptyTree !=)) case Select(_, _) => assert(tree.symbol != NoSymbol, tree) case This(_) => if (!(tree.symbol.isStatic && (tree.symbol hasFlag MODULE))) { var o = currentOwner while (o != tree.symbol) { o = o.owner if (o == NoSymbol) { error(tree.pos, "tree symbol "+tree.symbol+" does not point to enclosing class; tree = "+tree) return } } } case _ => } if (tree.pos == NoPosition && tree != EmptyTree) { error(tree.pos, "tree without position: " + tree) } else if ((tree.tpe eq null) && phase.id >= currentRun.typerPhase.id) { error(tree.pos, "tree without type: " + tree) } else if (tree.isDef && tree.symbol.owner != currentOwner) { var owner = currentOwner while (owner.isTerm && !owner.isMethod && tree.symbol.owner != owner) owner = owner.owner; if (tree.symbol.owner != owner) { error(tree.pos, "" + tree.symbol + " has wrong owner: " + tree.symbol.owner + tree.symbol.owner.locationString + ", should be: " + currentOwner + currentOwner.locationString) } } else { super.traverse(tree) } } catch { case ex: Throwable => if (settings.debug.value) Console.println("exception when traversing " + tree); throw(ex) } } } object postcheck extends Traverser { override def traverse(tree: Tree) { try { tree match { case EmptyTree | TypeTree() => ; case _ => tpeOfTree.get(tree) match { case Some(oldtpe) => if (!(oldtpe =:= tree.tpe)) error(tree.pos, "types differ\n old: " + oldtpe + "\n new: " + tree.tpe + "\n tree: " + tree) tree.tpe = oldtpe super.traverse(tree) case None => } } } catch { case ex: Throwable => if (settings.debug.value) Console.println("exception when traversing " + tree); throw(ex) } } } } }