diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-10-09 05:13:24 -0700 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-10-09 05:13:24 -0700 |
commit | 810ce7e2790e4da4e3f1d9473ccad5a721847096 (patch) | |
tree | 2cba192a70b5a932363d47b7b4491af1bd89ec46 /src/compiler | |
parent | 185ff4c929645a14fcfe77b6bcdea2bc28ece100 (diff) | |
parent | e609f1f20b0dce4905271b92aebd0298c7862859 (diff) | |
download | scala-810ce7e2790e4da4e3f1d9473ccad5a721847096.tar.gz scala-810ce7e2790e4da4e3f1d9473ccad5a721847096.tar.bz2 scala-810ce7e2790e4da4e3f1d9473ccad5a721847096.zip |
Merge pull request #3020 from paulp/pr/overriding-pairs
Generalize OverridingPairs to SymbolPairs.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 136 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/OverridingPairs.scala | 224 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 144 |
4 files changed, 154 insertions, 352 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 92bfe6e0fe..1cd3e0ec4b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -135,6 +135,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val global: Global.this.type = Global.this } with OverridingPairs + type SymbolPair = overridingPairs.SymbolPair + // Optimizer components /** ICode analysis for optimization */ diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 2d005b26e3..e2902a74b8 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -371,17 +371,14 @@ abstract class Erasure extends AddInterfaces val opc = enteringExplicitOuter { new overridingPairs.Cursor(root) { override def parents = List(root.info.firstParent) - override def exclude(sym: Symbol) = !sym.isMethod || sym.isPrivate || super.exclude(sym) + override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym) } } def compute(): (List[Tree], immutable.Set[Symbol]) = { while (opc.hasNext) { - val member = opc.overriding - val other = opc.overridden - //println("bridge? " + member + ":" + member.tpe + member.locationString + " to " + other + ":" + other.tpe + other.locationString)//DEBUG - if (enteringExplicitOuter(!member.isDeferred)) - checkPair(member, other) + if (enteringExplicitOuter(!opc.low.isDeferred)) + checkPair(opc.currentPair) opc.next() } @@ -438,8 +435,15 @@ abstract class Erasure extends AddInterfaces noclash } - def checkPair(member: Symbol, other: Symbol) { - val otpe = specialErasure(root)(other.tpe) + /** TODO - work through this logic with a fine-toothed comb, incorporating + * into SymbolPairs where appropriate. + */ + def checkPair(pair: SymbolPair) { + import pair._ + val member = low + val other = high + val otpe = highErased + val bridgeNeeded = exitingErasure ( !member.isMacro && !(other.tpe =:= member.tpe) && @@ -844,88 +848,75 @@ abstract class Erasure extends AddInterfaces /** The erasure transformer */ class ErasureTransformer(unit: CompilationUnit) extends Transformer { - /** Emit an error if there is a double definition. This can happen if: - * - * - A template defines two members with the same name and erased type. - * - A template defines and inherits two members `m` with different types, - * but their erased types are the same. - * - A template inherits two members `m` with different types, - * but their erased types are the same. - */ - private def checkNoDoubleDefs(root: Symbol) { - def doubleDefError(sym1: Symbol, sym2: Symbol) { - // the .toString must also be computed at the earlier phase - val tpe1 = exitingRefchecks(root.thisType.memberType(sym1)) - val tpe2 = exitingRefchecks(root.thisType.memberType(sym2)) - if (!tpe1.isErroneous && !tpe2.isErroneous) - unit.error( - if (sym1.owner == root) sym1.pos else root.pos, - (if (sym1.owner == sym2.owner) "double definition:\n" - else if (sym1.owner == root) "name clash between defined and inherited member:\n" - else "name clash between inherited members:\n") + - sym1 + ":" + exitingRefchecks(tpe1.toString) + - (if (sym1.owner == root) "" else sym1.locationString) + " and\n" + - sym2 + ":" + exitingRefchecks(tpe2.toString) + - (if (sym2.owner == root) " at line " + (sym2.pos).line else sym2.locationString) + - "\nhave same type" + - (if (exitingRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + exitingPostErasure(sym1.tpe))) - sym1.setInfo(ErrorType) + import overridingPairs.Cursor + + private def doubleDefError(pair: SymbolPair) { + import pair._ + + if (!pair.isErroneous) { + val what = ( + if (low.owner == high.owner) "double definition" + else if (low.owner == base) "name clash between defined and inherited member" + else "name clash between inherited members" + ) + val when = if (exitingRefchecks(lowType matches highType)) "" else " after erasure: " + exitingPostErasure(highType) + + unit.error(pos, + s"""|$what: + |${exitingRefchecks(highString)} and + |${exitingRefchecks(lowString)} + |have same type$when""".trim.stripMargin + ) } + low setInfo ErrorType + } - val decls = root.info.decls + /** TODO - adapt SymbolPairs so it can be used here. */ + private def checkNoDeclaredDoubleDefs(base: Symbol) { + val decls = base.info.decls var e = decls.elems while (e ne null) { if (e.sym.isTerm) { - var e1 = decls.lookupNextEntry(e) + var e1 = decls lookupNextEntry e while (e1 ne null) { - if (exitingPostErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) - e1 = decls.lookupNextEntry(e1) + if (exitingPostErasure(e1.sym.info =:= e.sym.info)) + doubleDefError(new SymbolPair(base, e.sym, e1.sym)) + + e1 = decls lookupNextEntry e1 } } e = e.next } + } - val opc = new overridingPairs.Cursor(root) { + /** Emit an error if there is a double definition. This can happen if: + * + * - A template defines two members with the same name and erased type. + * - A template defines and inherits two members `m` with different types, + * but their erased types are the same. + * - A template inherits two members `m` with different types, + * but their erased types are the same. + */ + private def checkNoDoubleDefs(root: Symbol) { + checkNoDeclaredDoubleDefs(root) + object opc extends Cursor(root) { + // specialized members have no type history before 'specialize', causing double def errors for curried defs override def exclude(sym: Symbol): Boolean = ( - !sym.isTerm || sym.isPrivate || super.exclude(sym) - // specialized members have no type history before 'specialize', causing double def errors for curried defs + sym.isType + || sym.isPrivate + || super.exclude(sym) || !sym.hasTypeAt(currentRun.refchecksPhase.id) ) - - override def matches(sym1: Symbol, sym2: Symbol): Boolean = - exitingPostErasure(sym1.tpe =:= sym2.tpe) + override def matches(sym1: Symbol, sym2: Symbol) = true } - while (opc.hasNext) { - if (!exitingRefchecks( - root.thisType.memberType(opc.overriding) matches - root.thisType.memberType(opc.overridden))) { - debuglog("" + opc.overriding.locationString + " " + - opc.overriding.infosString + - opc.overridden.locationString + " " + - opc.overridden.infosString) - doubleDefError(opc.overriding, opc.overridden) - } - opc.next() + def sameTypeAfterErasure(pair: SymbolPair) = { + import pair._ + log(s"Considering for erasure clash:\n$pair") + !exitingRefchecks(lowType matches highType) && exitingPostErasure(low.tpe =:= high.tpe) } + opc.iterator filter sameTypeAfterErasure foreach doubleDefError } -/* - for (bc <- root.info.baseClasses.tail; other <- bc.info.decls.toList) { - if (other.isTerm && !other.isConstructor && !(other hasFlag (PRIVATE | BRIDGE))) { - for (member <- root.info.nonPrivateMember(other.name).alternatives) { - if (member != other && - !(member hasFlag BRIDGE) && - exitingErasure(member.tpe =:= other.tpe) && - !exitingRefchecks( - root.thisType.memberType(member) matches root.thisType.memberType(other))) { - debuglog("" + member.locationString + " " + member.infosString + other.locationString + " " + other.infosString); - doubleDefError(member, other) - } - } - } - } -*/ - /** Add bridge definitions to a template. This means: * * If there is a concrete member `m` which overrides a member in a base @@ -940,7 +931,6 @@ abstract class Erasure extends AddInterfaces */ private def bridgeDefs(owner: Symbol): (List[Tree], immutable.Set[Symbol]) = { assert(phase == currentRun.erasurePhase, phase) - debuglog("computing bridges for " + owner) new ComputeBridges(unit, owner) compute() } diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index 2610679542..4222c4d8c8 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -6,221 +6,33 @@ package scala.tools.nsc package transform -import scala.collection.mutable import symtab.Flags._ -import util.HashSet -import scala.annotation.tailrec +import scala.reflect.internal.SymbolPairs /** 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 already contains the same pairs. - * @author Martin Odersky - * @version 1.0 + * which yields pairs of corresponding symbols visible in some base class, + * unless there's a parent class that already contains the same pairs. + * Most of the logic is in SymbolPairs, which contains generic + * pair-oriented traversal logic. */ -abstract class OverridingPairs { - - val global: Global +abstract class OverridingPairs extends SymbolPairs { 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 hidden symbols, including bridges. But it may be refined in subclasses. - * - */ - protected def exclude(sym: Symbol): Boolean = - sym.isConstructor || sym.isPrivateLocal || sym.isArtifact - - /** 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 overriding. - * Types always match. Term symbols match if their membertypes - * relative to <base>.this do - */ - protected def matches(sym1: Symbol, sym2: Symbol): Boolean = { - def tp_s(s: Symbol) = self.memberType(s) + "/" + self.memberType(s).getClass - val result = sym1.isType || (self.memberType(sym1) matches self.memberType(sym2)) - debuglog("overriding-pairs? %s matches %s (%s vs. %s) == %s".format( - sym1.fullLocationString, sym2.fullLocationString, tp_s(sym1), tp_s(sym2), result)) - - result - } + class Cursor(base: Symbol) extends super.Cursor(base) { + lazy val relatively = new RelativeTo(base.thisType) - /** An implementation of BitSets as arrays (maybe consider collection.BitSet - * for that?) The main purpose of this is to implement - * intersectionContainsElement efficiently. + /** Symbols to exclude: Here these are constructors and private/artifact symbols, + * including bridges. But it may be refined in subclasses. */ - private type BitSet = Array[Int] - - private def include(bs: BitSet, n: Int) { - val nshifted = n >> 5 - val nmask = 1 << (n & 31) - bs(nshifted) = bs(nshifted) | nmask - } - - /** 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) - 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 + override protected def exclude(sym: Symbol) = (sym hasFlag PRIVATE | ARTIFACT) || sym.isConstructor - // fill `decls` with overriding shadowing overridden */ - { 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.toLong && !exclude(e.sym)) - decls enter e.sym - e = e.next - } - } - } - // 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 meaning lower in - * linearization order. - * symbols that are not baseclasses map to -1. + /** Types always match. Term symbols match if their member types + * relative to `self` match. */ - private val index = new mutable.HashMap[Symbol, Int] { - override def default(key: Symbol) = -1 - } - - // Note: overridingPairs can be called at odd instances by the Eclipse plugin - // Soemtimes symbols are not yet defined and we get missing keys. - // The implementation here is hardened so that it does not crash on a missing key. - - { var i = 0 - for (bc <- base.info.baseClasses) { - index(bc) = i - i += 1 - } - } - - /** 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 - * p.baseType(b) == self.baseType(b) - */ - 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) - if (pIndex >= 0) - for (bc <- p.baseClasses) - if (p.baseType(bc) =:= self.baseType(bc)) { - val bcIndex = index(bc) - if (bcIndex >= 0) - include(subParents(bcIndex), pIndex) - } - } - } - - /** 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) - (index1 >= 0) && { - val index2 = index(sym2.owner) - (index2 >= 0) && { - 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 = HashSet[ScopeEntry]("visited", 64) - - /** 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 overriding */ - var overriding: Symbol = _ - - /** If not null: The symbol overridden by overriding */ - var overridden: Symbol = _ - - //@M: note that next is called once during object initialization - def hasNext: Boolean = curEntry ne null - - @tailrec - final def next() { - if (curEntry ne null) { - overriding = curEntry.sym - if (nextEntry ne null) { - do { - do { - nextEntry = decls.lookupNextEntry(nextEntry) - /* DEBUG - if ((nextEntry ne null) && - !(nextEntry.sym hasFlag PRIVATE) && - !(overriding.owner == nextEntry.sym.owner) && - !matches(overriding, nextEntry.sym)) - println("skipping "+overriding+":"+self.memberType(overriding)+overriding.locationString+" to "+nextEntry.sym+":"+self.memberType(nextEntry.sym)+nextEntry.sym.locationString) - */ - } 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() + override protected def matches(sym1: Symbol, sym2: Symbol) = sym1.isType || ( + (sym1.owner != sym2.owner) + && !exclude(sym2) + && relatively.matches(sym1, sym2) + ) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index d60e61df1b..a9a7f6a954 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -305,18 +305,23 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans /* Check that all conditions for overriding `other` by `member` * of class `clazz` are met. */ - def checkOverride(member: Symbol, other: Symbol) { + def checkOverride(pair: SymbolPair) { + import pair._ + val member = low + val other = high + def memberTp = lowType + def otherTp = highType + debuglog("Checking validity of %s overriding %s".format(member.fullLocationString, other.fullLocationString)) - def memberTp = self.memberType(member) - def otherTp = self.memberType(other) - def noErrorType = other.tpe != ErrorType && member.tpe != ErrorType + def noErrorType = !pair.isErroneous def isRootOrNone(sym: Symbol) = sym != null && sym.isRoot || sym == NoSymbol - def isNeitherInClass = (member.owner != clazz) && (other.owner != clazz) + def isNeitherInClass = member.owner != pair.base && other.owner != pair.base + def objectOverrideErrorMsg = ( - "overriding " + other.fullLocationString + " with " + member.fullLocationString + ":\n" + + "overriding " + high.fullLocationString + " with " + low.fullLocationString + ":\n" + "an overriding object must conform to the overridden object's class bound" + - analyzer.foundReqMsg(classBoundAsSeen(member.tpe), classBoundAsSeen(other.tpe)) + analyzer.foundReqMsg(pair.lowClassBound, pair.highClassBound) ) def overrideErrorMsg(msg: String): String = { @@ -460,79 +465,72 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans } } - def checkOverrideTypes() { - if (other.isAliasType) { - //if (!member.typeParams.isEmpty) (1.5) @MAT - // overrideError("may not be parameterized"); - //if (!other.typeParams.isEmpty) (1.5) @MAT - // overrideError("may not override parameterized type"); - // @M: substSym - - if( !(sameLength(member.typeParams, other.typeParams) && (memberTp.substSym(member.typeParams, other.typeParams) =:= otherTp)) ) // (1.6) - overrideTypeError() + //if (!member.typeParams.isEmpty) (1.5) @MAT + // overrideError("may not be parameterized"); + //if (!other.typeParams.isEmpty) (1.5) @MAT + // overrideError("may not override parameterized type"); + // @M: substSym + def checkOverrideAlias() { + if (pair.sameKind && lowType.substSym(low.typeParams, high.typeParams) =:= highType) () + else overrideTypeError() // (1.6) + } + //if (!member.typeParams.isEmpty) // (1.7) @MAT + // overrideError("may not be parameterized"); + def checkOverrideAbstract() { + if (!(highInfo.bounds containsType lowType)) { // (1.7.1) + overrideTypeError(); // todo: do an explaintypes with bounds here + explainTypes(_.bounds containsType _, highInfo, lowType) } - else if (other.isAbstractType) { - //if (!member.typeParams.isEmpty) // (1.7) @MAT - // overrideError("may not be parameterized"); - val otherTp = self.memberInfo(other) - - if (!(otherTp.bounds containsType memberTp)) { // (1.7.1) - overrideTypeError(); // todo: do an explaintypes with bounds here - explainTypes(_.bounds containsType _, otherTp, memberTp) - } - - // check overriding (abstract type --> abstract type or abstract type --> concrete type member (a type alias)) - // making an abstract type member concrete is like passing a type argument - val kindErrors = typer.infer.checkKindBounds(List(other), List(memberTp), self, member.owner) // (1.7.2) - - if(!kindErrors.isEmpty) + // check overriding (abstract type --> abstract type or abstract type --> concrete type member (a type alias)) + // making an abstract type member concrete is like passing a type argument + typer.infer.checkKindBounds(high :: Nil, lowType :: Nil, rootType, low.owner) match { // (1.7.2) + case Nil => + case kindErrors => unit.error(member.pos, "The kind of "+member.keyString+" "+member.varianceString + member.nameString+ " does not conform to the expected kind of " + other.defString + other.locationString + "." + kindErrors.toList.mkString("\n", ", ", "")) - - // check a type alias's RHS corresponds to its declaration - // this overlaps somewhat with validateVariance - if(member.isAliasType) { - // println("checkKindBounds" + ((List(member), List(memberTp.dealiasWiden), self, member.owner))) - val kindErrors = typer.infer.checkKindBounds(List(member), List(memberTp.dealiasWiden), self, member.owner) - - if(!kindErrors.isEmpty) + } + // check a type alias's RHS corresponds to its declaration + // this overlaps somewhat with validateVariance + if (low.isAliasType) { + typer.infer.checkKindBounds(low :: Nil, lowType.normalize :: Nil, rootType, low.owner) match { + case Nil => + case kindErrors => unit.error(member.pos, - "The kind of the right-hand side "+memberTp.dealiasWiden+" of "+member.keyString+" "+ - member.varianceString + member.nameString+ " does not conform to its expected kind."+ + "The kind of the right-hand side "+lowType.normalize+" of "+low.keyString+" "+ + low.varianceString + low.nameString+ " does not conform to its expected kind."+ kindErrors.toList.mkString("\n", ", ", "")) - } else if (member.isAbstractType) { - if (memberTp.isVolatile && !otherTp.bounds.hi.isVolatile) - overrideError("is a volatile type; cannot override a type with non-volatile upper bound") } - } else if (other.isTerm) { - other.cookJavaRawInfo() // #2454 - val memberTp = self.memberType(member) - val otherTp = self.memberType(other) - if (!overridesTypeInPrefix(memberTp, otherTp, self)) { // 8 - overrideTypeError() - explainTypes(memberTp, otherTp) - } - - if (member.isStable && !otherTp.isVolatile) { - // (1.4), pt 2 -- member.isStable && memberTp.isVolatile started being possible after SI-6815 - // (before SI-6815, !symbol.tpe.isVolatile was implied by symbol.isStable) - // TODO: allow overriding when @uncheckedStable? - if (memberTp.isVolatile) - overrideError("has a volatile type; cannot override a member with non-volatile type") - else memberTp.dealiasWiden.resultType match { - case rt: RefinedType if !(rt =:= otherTp) && !(checkedCombinations contains rt.parents) => - // might mask some inconsistencies -- check overrides - checkedCombinations += rt.parents - val tsym = rt.typeSymbol - if (tsym.pos == NoPosition) tsym setPos member.pos - checkAllOverrides(tsym, typesOnly = true) - case _ => - } + } + else if (low.isAbstractType && lowType.isVolatile && !highInfo.bounds.hi.isVolatile) + overrideError("is a volatile type; cannot override a type with non-volatile upper bound") + } + def checkOverrideTerm() { + other.cookJavaRawInfo() // #2454 + if (!overridesTypeInPrefix(lowType, highType, rootType)) { // 8 + overrideTypeError() + explainTypes(lowType, highType) + } + if (low.isStable && !highType.isVolatile) { + if (lowType.isVolatile) + overrideError("has a volatile type; cannot override a member with non-volatile type") + else lowType.normalize.resultType match { + case rt: RefinedType if !(rt =:= highType) && !(checkedCombinations contains rt.parents) => + // might mask some inconsistencies -- check overrides + checkedCombinations += rt.parents + val tsym = rt.typeSymbol + if (tsym.pos == NoPosition) tsym setPos member.pos + checkAllOverrides(tsym, typesOnly = true) + case _ => } } } + def checkOverrideTypes() { + if (high.isAliasType) checkOverrideAlias() + else if (high.isAbstractType) checkOverrideAbstract() + else if (high.isTerm) checkOverrideTerm() + } def checkOverrideDeprecated() { if (other.hasDeprecatedOverridingAnnotation) { @@ -545,8 +543,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans val opc = new overridingPairs.Cursor(clazz) while (opc.hasNext) { - //Console.println(opc.overriding/* + ":" + opc.overriding.tpe*/ + " in "+opc.overriding.fullName + " overrides " + opc.overridden/* + ":" + opc.overridden.tpe*/ + " in "+opc.overridden.fullName + "/"+ opc.overridden.hasFlag(DEFERRED));//debug - if (!opc.overridden.isClass) checkOverride(opc.overriding, opc.overridden) + if (!opc.high.isClass) + checkOverride(opc.currentPair) opc.next() } @@ -585,10 +583,10 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans def ignoreDeferred(member: Symbol) = ( (member.isAbstractType && !member.isFBounded) || ( - member.isJavaDefined && // the test requires exitingErasure so shouldn't be // done if the compiler has no erasure phase available - (currentRun.erasurePhase == NoPhase || javaErasedOverridingSym(member) != NoSymbol) + member.isJavaDefined + && (currentRun.erasurePhase == NoPhase || javaErasedOverridingSym(member) != NoSymbol) ) ) |