diff options
author | Martin Odersky <odersky@gmail.com> | 2009-02-05 19:24:56 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-02-05 19:24:56 +0000 |
commit | 48355ee28a930f19000901d761f24ca44b324c1f (patch) | |
tree | d16dd3125cdcdb955af61c1289f5e92af07a147c /src/compiler | |
parent | a81199163d973c9e643d28cc00bb3adb7ea26a10 (diff) | |
download | scala-48355ee28a930f19000901d761f24ca44b324c1f.tar.gz scala-48355ee28a930f19000901d761f24ca44b324c1f.tar.bz2 scala-48355ee28a930f19000901d761f24ca44b324c1f.zip |
Fixed duplicate symbols problem in new collecti...
Fixed duplicate symbols problem in new collection libraries by adding
a special case to Erasure. Fixed override problems in new collection
libraries by refining OverriddenPairs. Fixed repeated load by applying
patch to Settings. Improved error message iin RefChecks.
Diffstat (limited to 'src/compiler')
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 |