summaryrefslogtreecommitdiff
path: root/src/compiler/scala/reflect/reify/phases/Calculate.scala
blob: 59a36f0ba474ea51d24ec355592ab7cd01bc1d17 (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
package scala.reflect.reify
package phases

trait Calculate {
  self: Reifier =>

  import mirror._
  import definitions._
  import treeInfo._

  implicit def sym2richSym(sym: Symbol): RichSymbol = new RichSymbol(sym)
  class RichSymbol(sym: Symbol) {
    def metalevel: Int = { assert(sym != NoSymbol); localSymbols.getOrElse(sym, 0) }
    def isLocalToReifee = (localSymbols contains sym) // [Eugene] how do I account for local skolems?
  }

  implicit def tpe2richTpe(tpe: Type): RichType = new RichType(tpe)
  class RichType(tpe: Type) {
    def isLocalToReifee = tpe != null && (tpe exists (tp => (localSymbols contains tp.typeSymbol) || (localSymbols contains tp.termSymbol)))
  }

  private var localSymbols = collection.mutable.Map[Symbol, Int]() // set of all symbols that are local to the tree to be reified
  private def registerLocalSymbol(sym: Symbol, metalevel: Int): Unit =
    if (sym != null && sym != NoSymbol) {
      if (localSymbols contains sym)
        assert(localSymbols(sym) == metalevel, "metalevel mismatch: expected %s, actual %s".format(localSymbols(sym), metalevel))
      localSymbols(sym) = metalevel
    }

  /**
   *  Merely traverses the reifiee and records local symbols along with their metalevels.
   */
  val calculate = new Traverser {
    // see the explanation of metalevels in ``Metalevels''
    var currMetalevel = 1

    override def traverse(tree: Tree): Unit = tree match {
      case TreeSplice(_) =>
        currMetalevel -= 1
        try super.traverse(tree)
        finally currMetalevel += 1
      case tree if tree.isDef =>
        if (reifyDebug) println("boundSym: %s of type %s".format(tree.symbol, (tree.productIterator.toList collect { case tt: TypeTree => tt } headOption).getOrElse(TypeTree(tree.tpe))))
        registerLocalSymbol(tree.symbol, currMetalevel)

        bindRelatedSymbol(tree.symbol.sourceModule, "sourceModule")
        bindRelatedSymbol(tree.symbol.moduleClass, "moduleClass")
        bindRelatedSymbol(tree.symbol.companionClass, "companionClass")
        bindRelatedSymbol(tree.symbol.companionModule, "companionModule")
        Some(tree.symbol) collect { case termSymbol: TermSymbol => bindRelatedSymbol(termSymbol.referenced, "referenced") }
        def bindRelatedSymbol(related: Symbol, name: String): Unit =
          if (related != null && related != NoSymbol) {
            if (reifyDebug) println("boundSym (" + name + "): " + related)
            registerLocalSymbol(related, currMetalevel)
          }
        super.traverse(tree)
      case _ =>
        super.traverse(tree)
    }
  }
}