summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
blob: cc8d39fc5f238200fef039f81e55df32da2f0389 (plain) (tree)
1
2
3
4
5
6
7
8
9
                            
                                


                          
 

                       
 
                                     
                                                  


                                              
                 
 
                                                                  
 
                  
                               
                                                                                    
                                              

   
                                    
                                    



                                          


                                      


                                         


                                          

   
                                                                           

                                                                
                  
 
                                                                 
                  


                                      


                                            
           



                                                                                    
       

          

                                       
                                         





















                                                                                                              
               
             













                                                                                         
           

                              
         
       


                                        
                                         












                                                                   
         
       
     

   
/* NSC -- new Scala compiler
 * Copyright 2005-2010 LAMP/EPFL
 * @author  Martin Odersky
 */
// $Id$

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 _ =>
          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() + "]")
      }
      tree
    }

    object precheck extends Traverser {
      override def traverse(tree: Tree) {
        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))) {
              if (currentOwner.ownerChain takeWhile (_ != tree.symbol) exists (_ == 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)
        }
      }
    }

    object postcheck extends Traverser {
      override def traverse(tree: Tree) {
        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 =>
            }
        }
      }
    }
  }
}