summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
blob: 3f56ae416a254d5a09e789a30f5a2a0fe8bdedfa (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
131
132
133
134
135
136
137
138
139
140
141
/* NSC -- new Scala compiler
 * Copyright 2005-2009 LAMP/EPFL
 * @author Martin Odersky
 */
// $Id$

package scala.tools.nsc.transform

import collection.mutable.HashMap
import symtab.Flags._
import util.HashSet

/** This abstract class ...
 *
 *  @author Martin Odersky
 *  @version 1.0
 */
abstract class OverridingPairs {

  val global: Global
  import global._

  class Cursor(base: Symbol) {

    private val self = base.thisType

    protected def exclude(sym: Symbol): Boolean =
      sym.isConstructor || sym.isPrivateLocal || sym.hasFlag(BRIDGE)

    protected def parents: List[Type] = base.info.parents

    protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
      sym1.isType || (self.memberType(sym1) matches self.memberType(sym2))

    private type BitSet = Array[Int]

    private def newBitSet(size: Int): BitSet = new Array((size + 31) >> 5)

    private def include(bs: BitSet, n: Int) {
      val nshifted = n >> 5
      val nmask = 1 << (n & 31)
      bs(nshifted) = bs(nshifted) | nmask
    }

    private def intersectionContainsElementLeq(bs1: BitSet, bs2: BitSet,
                                               n: Int): Boolean =
    {
      val nshifted = n >> 5
      val nmask = 1 << (n & 31);
      ((List.range(0, nshifted) exists (i => (bs1(i) & bs2(i)) != 0)) ||
       ((bs1(nshifted) & bs2(nshifted) & (nmask | nmask - 1)) != 0))
    }

    private val decls = newScope

    { def fillDecls(bcs: List[Symbol], deferredflag: Int) {
        if (!bcs.isEmpty) {
          fillDecls(bcs.tail, deferredflag)
          var e = bcs.head.info.decls.elems;
          while (e ne null) {
            if (e.sym.getFlag(DEFERRED) == deferredflag && !exclude(e.sym))
              decls enter e.sym;
            e = e.next
          }
        }
      }
      fillDecls(base.info.baseClasses, DEFERRED)
      fillDecls(base.info.baseClasses, 0)
    }

    private val size = base.info.baseClasses.length

    private val index = new HashMap[Symbol, Int]

    { var i = 0
      for (bc <- base.info.baseClasses) {
        index(bc) = i
        i += 1
      }
    }

    private val subParents = new Array[BitSet](size)

    { for (i <- List.range(0, size))
        subParents(i) = new BitSet(size);
      for (p <- parents) {
        val pIndex = index(p.typeSymbol)
        for (bc <- p.baseClasses) include(subParents(index(bc)), pIndex)
      }
    }


    private def hasCommonParent(sym1: Symbol, sym2: Symbol) = {
      //assert(index.get(sym1.owner) != None, "" + base + " " + sym1 + " " + sym1.owner);//DEBUG
      //assert(index.get(sym2.owner) != None, "" + base + " " + sym2 + " " + sym2.owner);//DEBUG
      val index1 = index(sym1.owner)
      val index2 = index(sym2.owner)
      val minindex = if (index1 < index2) index1 else index2
      intersectionContainsElementLeq(subParents(index1), subParents(index2), minindex)
    }

    private val visited = new HashSet[ScopeEntry](256)
    private var curEntry = decls.elems
    private var nextEntry = curEntry

    var overriding: Symbol = _
    var overridden: Symbol = _

    //@M: note that next is called once during object initialisation
    def hasNext: Boolean = curEntry ne null

    def next {
      if (curEntry ne null) {
        overriding = curEntry.sym
        if (nextEntry ne null) {
          do {
            nextEntry = decls.lookupNextEntry(nextEntry);
          } while ((nextEntry ne null) &&
                   ((nextEntry.sym hasFlag PRIVATE) ||
                    (overriding.owner == nextEntry.sym.owner) ||
                    (!matches(overriding, nextEntry.sym)) ||
                    (hasCommonParent(overriding, nextEntry.sym)) ||
                    (exclude(overriding))))
        }
        if (nextEntry ne null) {
          overridden = nextEntry.sym;
          //Console.println("yield: " + overriding + overriding.locationString + " / " + overridden + overridden.locationString);//DEBUG
          visited addEntry nextEntry
        } else {
          do {
            curEntry = curEntry.next
          } while ((curEntry ne null) && (visited contains curEntry));
          nextEntry = curEntry
          next
        }
      }
    }

    next //@M: ATTN! this method gets called during construction!
  }
}