Skip to content

Commit 2cb9050

Browse files
committed
Preparation for intgeration of RefChecks
Added OverridingPairs Small tweaks here and there.
1 parent 51eeac7 commit 2cb9050

File tree

5 files changed

+179
-23
lines changed

5 files changed

+179
-23
lines changed

src/dotty/tools/dotc/core/Flags.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,9 @@ object Flags {
521521
/** A Java companion object */
522522
final val JavaModule = allOf(JavaDefined, Module)
523523

524+
/** A Java companion object */
525+
final val JavaProtected = allOf(JavaDefined, Protected)
526+
524527
/** Labeled private[this] */
525528
final val PrivateLocal = allOf(Private, Local)
526529

src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,12 @@ object NameOps {
251251

252252
/** If this is a default getter, its index (starting from 0), else -1 */
253253
def defaultGetterIndex: Int = {
254-
val p = name.indexOfSlice(DEFAULT_GETTER)
255-
if (p >= 0) name.drop(p + DEFAULT_GETTER.length).toString.toInt - 1
256-
else -1
254+
var i = name.length
255+
while (i > 0 && name(i - 1).isDigit) i -= 1
256+
if (i > 0 && i < name.length && name.take(i).endsWith(DEFAULT_GETTER))
257+
name.drop(i).toString.toInt - 1
258+
else
259+
-1
257260
}
258261

259262
/** The name of an accessor for protected symbols. */

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,13 @@ object SymDenotations {
589589
NoSymbol
590590
}
591591

592-
/** The field accessed by this getter or setter */
593-
def accessedField(implicit ctx: Context): Symbol = {
592+
/** The field accessed by this getter or setter, or if it does not exist, the getter */
593+
def accessedFieldOrGetter(implicit ctx: Context): Symbol = {
594594
val fieldName = if (isSetter) name.asTermName.setterToGetter else name
595-
owner.info.decl(fieldName).suchThat(d => !(d is Method)).symbol
595+
val d = owner.info.decl(fieldName)
596+
val field = d.suchThat(!_.is(Method)).symbol
597+
def getter = d.suchThat(_.info.isParameterless).symbol
598+
field orElse getter
596599
}
597600

598601
/** The chain of owners of this denotation, starting with the denoting symbol itself */
@@ -723,17 +726,29 @@ object SymDenotations {
723726
denot.symbol
724727
}
725728

729+
/** If false, this symbol cannot possibly participate in an override,
730+
* either as overrider or overridee.
731+
*/
732+
final def canMatchInheritedSymbols(implicit ctx: Context): Boolean =
733+
maybeOwner.isClass && !isConstructor && !is(Private)
734+
726735
/** The symbol, in class `inClass`, that is overridden by this denotation. */
727736
final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
728-
if ((this is Private) && (owner ne inClass)) NoSymbol
737+
if (!canMatchInheritedSymbols && (owner ne inClass)) NoSymbol
729738
else matchingSymbol(inClass, owner.thisType)
730739

731740
/** All symbols overriden by this denotation. */
732741
final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
733-
if (exists && owner.isClass)
734-
owner.info.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
735-
else
736-
Iterator.empty
742+
if (!canMatchInheritedSymbols) Iterator.empty
743+
else overriddenFromType(owner.info)
744+
745+
/** Returns all all matching symbols defined in parents of the selftype. */
746+
final def extendedOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
747+
if (!canMatchInheritedSymbols) Iterator.empty
748+
else overriddenFromType(owner.asClass.classInfo.selfType)
749+
750+
private def overriddenFromType(tp: Type)(implicit ctx: Context): Iterator[Symbol] =
751+
tp.baseClasses.tail.iterator map overriddenSymbol filter (_.exists)
737752

738753
/** The symbol overriding this symbol in given subclass `ofclazz`.
739754
*
@@ -743,17 +758,6 @@ object SymDenotations {
743758
if (canMatchInheritedSymbols) matchingSymbol(inClass, inClass.thisType)
744759
else NoSymbol
745760

746-
/** If false, this symbol cannot possibly participate in an override,
747-
* either as overrider or overridee. For internal use; you should consult
748-
* with isOverridingSymbol. This is used by isOverridingSymbol to escape
749-
* the recursive knot.
750-
*/
751-
private def canMatchInheritedSymbols = (
752-
owner.isClass
753-
&& !this.isClass
754-
&& !this.isConstructor
755-
)
756-
757761
/** The symbol accessed by a super in the definition of this symbol when
758762
* seen from class `base`. This symbol is always concrete.
759763
* pre: `this.owner` is in the base class sequence of `base`.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import Flags._, Symbols._, Contexts._, Types._, Scopes._
6+
import util.HashSet
7+
import collection.mutable.HashMap
8+
import collection.immutable.BitSet
9+
import scala.annotation.tailrec
10+
11+
/** A class that yields a kind of iterator (`Cursor`),
12+
* which yields all pairs of overriding/overridden symbols
13+
* that are visible in some baseclass, unless there's a parent class
14+
* that already contains the same pairs.
15+
*
16+
* Adapted from the 2.9 version of OverridingPairs. The 2.10 version is IMO
17+
* way too unwieldy to be maintained.
18+
*/
19+
abstract class OverridingPairs {
20+
21+
/** The cursor class
22+
* @param base the base class that contains the overriding pairs
23+
*/
24+
class Cursor(base: Symbol)(implicit ctx: Context) {
25+
26+
private val self = base.thisType
27+
28+
/** Symbols to exclude: Here these are constructors and private locals.
29+
* But it may be refined in subclasses.
30+
*/
31+
protected def exclude(sym: Symbol): Boolean =
32+
sym.isConstructor || sym.is(PrivateLocal)
33+
34+
/** The parents of base (may also be refined).
35+
*/
36+
protected def parents: Array[Symbol] = base.info.parents.toArray map (_.typeSymbol)
37+
38+
/** Does `sym1` match `sym2` so that it qualifies as overriding.
39+
* Types always match. Term symbols match if their membertypes
40+
* relative to <base>.this do
41+
*/
42+
protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
43+
sym1.isType || {
44+
val info1 = self.memberInfo(sym1)
45+
val info2 = self.memberInfo(sym2)
46+
// info1.signature == info2.signature && // TODO enable for speed
47+
info1 matches info2
48+
}
49+
50+
/** The symbols that can take part in an overriding pair */
51+
private val decls = {
52+
val decls = newScope
53+
// fill `decls` with overriding shadowing overridden */
54+
def fillDecls(bcs: List[Symbol], deferred: Boolean): Unit = bcs match {
55+
case bc :: bcs1 =>
56+
fillDecls(bcs1, deferred)
57+
var e = bc.info.decls.asInstanceOf[MutableScope].lastEntry
58+
while (e != null) {
59+
if (e.sym.is(Deferred) == deferred && !exclude(e.sym))
60+
decls.enter(e.sym)
61+
e = e.prev
62+
}
63+
case nil =>
64+
}
65+
// first, deferred (this will need to change if we change lookup rules!
66+
fillDecls(base.info.baseClasses, deferred = true)
67+
// then, concrete.
68+
fillDecls(base.info.baseClasses, deferred = false)
69+
decls
70+
}
71+
72+
private val subParents = {
73+
val subParents = new HashMap[Symbol, BitSet]
74+
for (bc <- base.info.baseClasses)
75+
subParents(bc) = BitSet(parents.indices.filter(parents(_).derivesFrom(bc)): _*)
76+
subParents
77+
}
78+
79+
private def hasCommonParentAsSubclass(cls1: Symbol, cls2: Symbol): Boolean =
80+
(subParents(cls1) intersect subParents(cls2)).isEmpty
81+
82+
/** The scope entries that have already been visited as overridden
83+
* (maybe excluded because of hasCommonParentAsSubclass).
84+
* These will not appear as overriding
85+
*/
86+
private val visited = new HashSet[ScopeEntry](64)
87+
88+
/** The current entry candidate for overriding
89+
*/
90+
private var curEntry = decls.lastEntry
91+
92+
/** The current entry candidate for overridden */
93+
private var nextEntry = curEntry
94+
95+
/** The current candidate symbol for overriding */
96+
var overriding: Symbol = _
97+
98+
/** If not null: The symbol overridden by overriding */
99+
var overridden: Symbol = _
100+
101+
//@M: note that next is called once during object initialization
102+
def hasNext: Boolean = curEntry ne null
103+
104+
@tailrec
105+
final def next: Unit = {
106+
if (curEntry ne null) {
107+
overriding = curEntry.sym
108+
if (nextEntry ne null) {
109+
val overridingOwner = overriding.owner
110+
do {
111+
do {
112+
nextEntry = decls.lookupNextEntry(nextEntry);
113+
/* DEBUG
114+
if ((nextEntry ne null) &&
115+
!(nextEntry.sym hasFlag PRIVATE) &&
116+
!(overriding.owner == nextEntry.sym.owner) &&
117+
!matches(overriding, nextEntry.sym))
118+
println("skipping "+overriding+":"+self.memberType(overriding)+overriding.locationString+" to "+nextEntry.sym+":"+self.memberType(nextEntry.sym)+nextEntry.sym.locationString)
119+
*/
120+
} while ((nextEntry ne null) &&
121+
(//!!!!nextEntry.sym.canMatchInheritedSymbols ||
122+
(overriding.owner == nextEntry.sym.owner) ||
123+
(!matches(overriding, nextEntry.sym)) ||
124+
(exclude(overriding))))
125+
if (nextEntry ne null) visited.addEntry(nextEntry)
126+
// skip nextEntry if a class in `parents` is a subclass of the owners of both
127+
// overriding and nextEntry.sym
128+
} while ((nextEntry ne null) &&
129+
hasCommonParentAsSubclass(overridingOwner, nextEntry.sym.owner))
130+
if (nextEntry ne null) {
131+
overridden = nextEntry.sym;
132+
//Console.println("yield: " + overriding + overriding.locationString + " / " + overridden + overridden.locationString);//DEBUG
133+
} else {
134+
do {
135+
curEntry = curEntry.prev
136+
} while ((curEntry ne null) && visited.contains(curEntry))
137+
nextEntry = curEntry
138+
next
139+
}
140+
}
141+
}
142+
}
143+
144+
next
145+
}
146+
}

src/dotty/tools/dotc/transform/SuperAccessors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ class SuperAccessors extends MacroTransform with IdentityDenotTransformer { this
356356

357357
case Super(_, mix) =>
358358
if ((sym.isTerm) && !(sym is Method) || (sym is Accessor)) {
359-
ctx.error(s"super may be not be used on ${sym.accessedField orElse sym}", tree.pos)
359+
ctx.error(s"super may be not be used on ${sym.accessedFieldOrGetter orElse sym}", tree.pos)
360360
} else if (isDisallowed(sym)) {
361361
ctx.error(s"super not allowed here: use this.${name.decode} instead", tree.pos)
362362
}

0 commit comments

Comments
 (0)