summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala14
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala5
-rw-r--r--src/compiler/scala/tools/nsc/transform/OverridingPairs.scala119
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala9
7 files changed, 125 insertions, 49 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index b36d82f741..016174615c 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -170,7 +170,7 @@ class Settings(error: String => Unit) {
}
override def equals(that: Any) = that match {
- case s:Settings =>
+ case s: Settings =>
assert(this.allSettings.length == s.allSettings.length)
List.forall2 (
this.allSettings,
@@ -334,7 +334,7 @@ class Settings(error: String => Unit) {
if (value == default) Nil else List(name, value.toString)
override def equals(that: Any) = that match {
- case is:IntSetting => this.name == is.name && this.value == is.value
+ case is: Settings#IntSetting => this.name == is.name && this.value == is.value
case _ => false
}
@@ -355,7 +355,7 @@ class Settings(error: String => Unit) {
def unparse: List[String] = if (value) List(name) else Nil
override def equals(that: Any) = that match {
- case bs:BooleanSetting => this.name == bs.name && this.value == bs.value
+ case bs: Settings#BooleanSetting => this.name == bs.name && this.value == bs.value
case _ => false
}
@@ -389,7 +389,7 @@ class Settings(error: String => Unit) {
if (value == default) Nil else List(name, value)
override def equals(that: Any) = that match {
- case ss:StringSetting => this.name == ss.name && this.value == ss.value
+ case ss: Settings# StringSetting => this.name == ss.name && this.value == ss.value
case _ => false
}
@@ -428,7 +428,7 @@ class Settings(error: String => Unit) {
for (opt <- value) yield nameColon+opt
override def equals(that: Any) = that match {
- case mss:MultiStringSetting =>
+ case mss: Settings# MultiStringSetting =>
this.name == mss.name &&
this.value.length == mss.value.length &&
List.forall2(this.value.sort(_<_), mss.value.sort(_<_))(_==_)
@@ -480,7 +480,7 @@ class Settings(error: String => Unit) {
if (value == default) Nil else List(name + ":" + value)
override def equals(that: Any) = that match {
- case cs:ChoiceSetting => this.name == cs.name && this.value == cs.value
+ case cs: Settings# ChoiceSetting => this.name == cs.name && this.value == cs.value
case _ => false
}
@@ -566,7 +566,7 @@ class Settings(error: String => Unit) {
List(name + ":" + phase) ::: args))
override def equals(that: Any) = that match {
- case ps:PhasesSetting =>
+ case ps: Settings#PhasesSetting =>
this.name == ps.name &&
this.value.length == ps.value.length &&
List.forall2(this.value.sort(_<_), ps.value.sort(_<_))(_==_)
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 4e65e6deab..f6b3b3064c 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -468,6 +468,11 @@ trait Symbols {
isClass && (isAnonymousClass || isRefinementClass || isLocal ||
!owner.isPackageClass && owner.isLocalClass)
+ /** Is this symbol a member of class `clazz'
+ */
+ def isMemberOf(clazz: Symbol) =
+ clazz.info.member(name).alternatives contains this
+
/** A a member of class `base' is incomplete if
* (1) it is declared deferred or
* (2) it is abstract override and its super symbol in `base' is
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index d9aa3e89aa..15cad39db3 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -8,6 +8,7 @@ package scala.tools.nsc.transform
import scala.tools.nsc.symtab.classfile.ClassfileConstants._
import scala.collection.mutable.{HashMap,ListBuffer}
+import scala.collection.immutable.Set
import scala.tools.nsc.util.Position
import symtab._
import Flags._
@@ -816,8 +817,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
* with the erased type of <code>m1</code> in the template.
* </p>
*/
- private def bridgeDefs(owner: Symbol): List[Tree] = {
- //Console.println("computing bridges for " + owner)//DEBUG
+ private def bridgeDefs(owner: Symbol): (List[Tree], Set[Symbol]) = {
+ var toBeRemoved: Set[Symbol] = Set()
+ //println("computing bridges for " + owner)//DEBUG
assert(phase == currentRun.erasurePhase)
val site = owner.thisType
val bridgesScope = newScope
@@ -834,7 +836,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
val member = opc.overriding
val other = opc.overridden
//Console.println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString);//DEBUG
- if (!atPhase(currentRun.explicitOuterPhase)(member.isDeferred)) {
+ if (atPhase(currentRun.explicitOuterPhase)(!member.isDeferred)) {
val otpe = erasure(other.tpe);
val bridgeNeeded = atPhase(phase.next) (
!(other.tpe =:= member.tpe) &&
@@ -853,6 +855,11 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
.setInfo(otpe);
bridgeTarget(bridge) = member
atPhase(phase.next) { owner.info.decls.enter(bridge) }
+ if (other.owner == owner) {
+ //println("bridge to same: "+other+other.locationString)//DEBUG
+ atPhase(phase.next) { owner.info.decls.unlink(other) }
+ toBeRemoved += other
+ }
bridgesScope enter bridge
bridges =
atPhase(phase.next) {
@@ -874,7 +881,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
}
opc.next
}
- bridges
+ (bridges, toBeRemoved)
}
/*
for (val bc <- site.baseClasses.tail; val other <- bc.info.decls.toList) {
@@ -893,8 +900,9 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer {
def addBridges(stats: List[Tree], base: Symbol): List[Tree] =
if (base.isTrait) stats
else {
- val bridges = bridgeDefs(base)
- if (bridges.isEmpty) stats else stats ::: bridges
+ val (bridges, toBeRemoved) = bridgeDefs(base)
+ if (bridges.isEmpty) stats
+ else (stats remove (stat => toBeRemoved contains stat.symbol)) ::: bridges
}
/** <p>
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index ec125fa694..ce0d3c651d 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -987,6 +987,11 @@ abstract class Mixin extends InfoTransform {
}
// }
}
+/* //DEBUG
+ case Ident(name) if (name.toString == "xxx") =>
+ println(tree+":"+tree.tpe+"/"+tree.tpe.baseClasses)
+ tree
+*/
case _ =>
tree
}
diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
index 3f56ae416a..9266515057 100644
--- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
+++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala
@@ -10,8 +10,10 @@ import collection.mutable.HashMap
import symtab.Flags._
import util.HashSet
-/** This abstract class ...
- *
+/** A class that yields a kind of iterator (`Cursor`),
+ * which yields all pairs of overriding/overridden symbols
+ * that are visible in some baseclass, unless there's a parent class
+ * that aleady contains the same pairs.
* @author Martin Odersky
* @version 1.0
*/
@@ -20,18 +22,35 @@ abstract class OverridingPairs {
val global: Global
import global._
+ /** The cursor class
+ * @param base the base class that contains the overriding pairs
+ */
class Cursor(base: Symbol) {
private val self = base.thisType
+ /** Symbols to exclude: Here these are constructors, private locals,
+ * and bridges. But it may be refined in subclasses.
+ *
+ */
protected def exclude(sym: Symbol): Boolean =
sym.isConstructor || sym.isPrivateLocal || sym.hasFlag(BRIDGE)
+ /** The parents of base (may also be refined).
+ */
protected def parents: List[Type] = base.info.parents
+ /** Does `sym1` match `sym2` so that it qualifies as overiding.
+ * Types always match. Term symbols match if their membertypes
+ * relative to <base>.this do
+ */
protected def matches(sym1: Symbol, sym2: Symbol): Boolean =
sym1.isType || (self.memberType(sym1) matches self.memberType(sym2))
+ /** An implementation of BitSets as arrays (maybe consider collection.BitSet
+ * for that?) The main purpose of this is to implement
+ * intersectionContainsElement efficiently.
+ */
private type BitSet = Array[Int]
private def newBitSet(size: Int): BitSet = new Array((size + 31) >> 5)
@@ -42,17 +61,23 @@ abstract class OverridingPairs {
bs(nshifted) = bs(nshifted) | nmask
}
- private def intersectionContainsElementLeq(bs1: BitSet, bs2: BitSet,
- n: Int): Boolean =
- {
+ /** Implements `bs1 * bs2 * {0..n} != 0.
+ * Used in hasCommonParentAsSubclass */
+ 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))
+ val nmask = 1 << (n & 31)
+ var i = 0
+ while (i < nshifted) {
+ if ((bs1(i) & bs2(i)) != 0) return true
+ i += 1
+ }
+ (bs1(nshifted) & bs2(nshifted) & (nmask | nmask - 1)) != 0
}
+ /** The symbols that can take part in an overriding pair */
private val decls = newScope
+ // fill `decls` with overriding shadowing overridden */
{ def fillDecls(bcs: List[Symbol], deferredflag: Int) {
if (!bcs.isEmpty) {
fillDecls(bcs.tail, deferredflag)
@@ -64,12 +89,17 @@ abstract class OverridingPairs {
}
}
}
+ // first, deferred (this wil need to change if we change lookup rules!
fillDecls(base.info.baseClasses, DEFERRED)
+ // then, concrete.
fillDecls(base.info.baseClasses, 0)
}
private val size = base.info.baseClasses.length
+ /** A map from baseclasses of <base> to ints, with smaller ints meansing lower in
+ * lineraizatuon order.
+ */
private val index = new HashMap[Symbol, Int]
{ var i = 0
@@ -79,6 +109,15 @@ abstract class OverridingPairs {
}
}
+ /** A mapping from all base class indices to a bitset
+ * which indicates whether parents are subclasses.
+ *
+ * i \in subParents(j) iff
+ * exists p \in parents, b \in baseClasses:
+ * i = index(p)
+ * j = index(b)
+ * p isSubClass b
+ */
private val subParents = new Array[BitSet](size)
{ for (i <- List.range(0, size))
@@ -89,21 +128,32 @@ abstract class OverridingPairs {
}
}
-
- 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
+ /** Do `sym1` and `sym2` have a common subclass in `parents`?
+ * In that case we do not follow their overriding pairs
+ */
+ private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = {
val index1 = index(sym1.owner)
val index2 = index(sym2.owner)
- val minindex = if (index1 < index2) index1 else index2
- intersectionContainsElementLeq(subParents(index1), subParents(index2), minindex)
+ intersectionContainsElementLeq(subParents(index1), subParents(index2), index1 min index2)
}
+ /** The scope entries that have already been visited as overridden
+ * (maybe excluded because of hasCommonParentAsSubclass).
+ * These will not appear as overriding
+ */
private val visited = new HashSet[ScopeEntry](256)
+
+ /** The current entry candidate for overriding
+ */
private var curEntry = decls.elems
+
+ /** The current entry candidate for overridden */
private var nextEntry = curEntry
+ /** The current candidate symbol for overridding */
var overriding: Symbol = _
+
+ /** If not null: The symbol overridden by overridding */
var overridden: Symbol = _
//@M: note that next is called once during object initialisation
@@ -114,28 +164,31 @@ abstract class OverridingPairs {
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
+ do {
+ nextEntry = decls.lookupNextEntry(nextEntry);
+ } while ((nextEntry ne null) &&
+ ((nextEntry.sym hasFlag PRIVATE) ||
+ (overriding.owner == nextEntry.sym.owner) ||
+ (!matches(overriding, nextEntry.sym)) ||
+ (exclude(overriding))))
+ if (nextEntry ne null) visited addEntry nextEntry
+ // skip nextEntry if a class in `parents` is a subclass of the owners of both
+ // overriding and nextEntry.sym
+ } while ((nextEntry ne null) && (hasCommonParentAsSubclass(overriding, nextEntry.sym)))
+ if (nextEntry ne null) {
+ overridden = nextEntry.sym;
+ //Console.println("yield: " + overriding + overriding.locationString + " / " + overridden + overridden.locationString);//DEBUG
+ } else {
+ do {
+ curEntry = curEntry.next
+ } while ((curEntry ne null) && (visited contains curEntry));
+ nextEntry = curEntry
+ next
+ }
}
}
}
- next //@M: ATTN! this method gets called during construction!
+ next
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 693fa4e63e..f3c2bc3122 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -202,6 +202,8 @@ abstract class UnCurry extends InfoTransform with TypingTransformers {
* I.e. for the method's non-local return key, generate:
*
* throw new NonLocalReturnException(key, expr)
+ * todo: maybe clone a pre-existing exception instead?
+ * (but what to do about excaptions that miss their targets?)
*/
private def nonLocalReturnThrow(expr: Tree, meth: Symbol) =
localTyper.typed {
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index af010998b8..acee4132af 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -103,8 +103,11 @@ abstract class RefChecks extends InfoTransform {
case List(MixinOverrideError(_, msg)) =>
unit.error(clazz.pos, msg)
case MixinOverrideError(member, msg) :: others =>
- unit.error(clazz.pos, msg+";\n other members with override errors are: "+
- (others.map(_.member.name).filter(member.name != _).removeDuplicates mkString ", "))
+ val others1 = others.map(_.member.name.decode).filter(member.name != _).removeDuplicates
+ unit.error(
+ clazz.pos,
+ msg+(if (others1.isEmpty) ""
+ else ";\n other members with override errors are: "+(others1 mkString ", ")))
}
}
@@ -273,7 +276,7 @@ abstract class RefChecks extends InfoTransform {
val opc = new overridingPairs.Cursor(clazz)
while (opc.hasNext) {
- //Console.println("overrides " + opc.overriding/* + ":" + opc.overriding.tpe*/ + opc.overriding.locationString + " " + opc.overridden/* + ":" + opc.overridden.tpe*/ + opc.overridden.locationString + opc.overridden.hasFlag(DEFERRED));//DEBUG
+ //Console.println(opc.overriding/* + ":" + opc.overriding.tpe*/ + " in "+opc.overriding.fullNameString + " overrides " + opc.overridden/* + ":" + opc.overridden.tpe*/ + " in "+opc.overridden.fullNameString + "/"+ opc.overridden.hasFlag(DEFERRED));//debug
if (!opc.overridden.isClass) checkOverride(clazz, opc.overriding, opc.overridden);
opc.next