summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
blob: cc8d39fc5f238200fef039f81e55df32da2f0389 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* 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 =>
            }
        }
      }
    }
  }
}