diff options
author | Paul Phillips <paulp@improving.org> | 2012-09-20 14:33:59 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-09-20 15:07:28 -0700 |
commit | 2097a653642927c39b1cb614546240ac9213f3fb (patch) | |
tree | 646778309893b3394fc36c720bd0bda4e0f86006 /src/compiler/scala/tools/nsc/transform/Erasure.scala | |
parent | feb77881ff8bc1e46c8ae4317a9d95cbf97e34bd (diff) | |
parent | c065bde5f50cae3e1fa6d0724e2043818d6301e9 (diff) | |
download | scala-2097a653642927c39b1cb614546240ac9213f3fb.tar.gz scala-2097a653642927c39b1cb614546240ac9213f3fb.tar.bz2 scala-2097a653642927c39b1cb614546240ac9213f3fb.zip |
Merge branch '2.10.x'
* 2.10.x: (36 commits)
Normalized line endings.
New .gitattributes file.
Disabled failing build manager tests.
New test case for SI-6337
New test case for closing SI-6385
Value classes: eliminated half-boxing
Cleanup of OverridingPairs
Fixes SI-6260
Use faster download URL now that artifactory is fixed.
don't try to create tags w/o scala-reflect.jar
some small remaining fixes
SI-5943 toolboxes now autoimport Predef and scala
Fix for loud test.
SI-6363 deploys the updated starr
SI-6363 removes scala.reflect.base
SI-6392 wraps non-terms before typecheck/eval
SI-6394 fixes macros.Context.enclosingClass
Error message improvement for SI-6336.
Adjustments to scala.concurrent.duration.
prepping for the refactoring
...
Conflicts:
src/actors-migration/scala/actors/Pattern.scala
src/compiler/scala/tools/nsc/Global.scala
src/compiler/scala/tools/nsc/transform/Erasure.scala
src/compiler/scala/tools/nsc/typechecker/Typers.scala
src/library/scala/collection/immutable/Vector.scala
test/files/jvm/actmig-PinS_1.scala
test/files/jvm/actmig-PinS_2.scala
test/files/jvm/actmig-PinS_3.scala
test/files/jvm/actmig-public-methods_1.scala
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Erasure.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 107 |
1 files changed, 81 insertions, 26 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 71d684ccd7..2c768d903a 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -167,6 +167,8 @@ abstract class Erasure extends AddInterfaces case tp => tp :: Nil } + private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] + /** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return * type for constructors. */ @@ -373,18 +375,18 @@ abstract class Erasure extends AddInterfaces } } - class ComputeBridges(owner: Symbol) { + class ComputeBridges(unit: CompilationUnit, root: Symbol) { assert(phase == currentRun.erasurePhase, phase) var toBeRemoved = immutable.Set[Symbol]() - val site = owner.thisType + val site = root.thisType val bridgesScope = newScope val bridgeTarget = mutable.HashMap[Symbol, Symbol]() var bridges = List[Tree]() val opc = enteringExplicitOuter { - new overridingPairs.Cursor(owner) { - override def parents = List(owner.info.firstParent) + new overridingPairs.Cursor(root) { + override def parents = List(root.info.firstParent) override def exclude(sym: Symbol) = !sym.isMethod || sym.isPrivate || super.exclude(sym) } } @@ -402,8 +404,58 @@ abstract class Erasure extends AddInterfaces (bridges, toBeRemoved) } + /** Check that a bridge only overrides members that are also overridden by the original member. + * This test is necessary only for members that have a value class in their type. + * Such members are special because their types after erasure and after post-erasure differ/. + * This means we generate them after erasure, but the post-erasure transform might introduce + * a name clash. The present method guards against these name clashes. + * + * @param member The original member + * @param other The overidden symbol for which the bridge was generated + * @param bridge The bridge + */ + def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Boolean = { + def fulldef(sym: Symbol) = + if (sym == NoSymbol) sym.toString + else s"$sym: ${sym.tpe} in ${sym.owner}" + var noclash = true + def clashError(what: String) = { + noclash = false + unit.error( + if (member.owner == root) member.pos else root.pos, + s"""bridge generated for member ${fulldef(member)} + |which overrides ${fulldef(other)} + |clashes with definition of $what; + |both have erased type ${exitingPostErasure(bridge.tpe)}""".stripMargin) + } + for (bc <- root.baseClasses) { + if (settings.debug.value) + exitingPostErasure(println( + s"""check bridge overrides in $bc + ${bc.info.nonPrivateDecl(bridge.name)} + ${site.memberType(bridge)} + ${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)} + ${(bridge.matchingSymbol(bc, site))}""".stripMargin)) + + def overriddenBy(sym: Symbol) = + sym.matchingSymbol(bc, site).alternatives filter (sym => !sym.isBridge) + for (overBridge <- exitingPostErasure(overriddenBy(bridge))) { + if (overBridge == member) { + clashError("the member itself") + } else { + val overMembers = overriddenBy(member) + if (!overMembers.exists(overMember => + exitingPostErasure(overMember.tpe =:= overBridge.tpe))) { + clashError(fulldef(overBridge)) + } + } + } + } + noclash + } + def checkPair(member: Symbol, other: Symbol) { - val otpe = erasure(owner)(other.tpe) + val otpe = erasure(root)(other.tpe) val bridgeNeeded = exitingErasure ( !(other.tpe =:= member.tpe) && !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) && @@ -417,24 +469,29 @@ abstract class Erasure extends AddInterfaces return val newFlags = (member.flags | BRIDGE | ARTIFACT) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) - val bridge = other.cloneSymbolImpl(owner, newFlags) setPos owner.pos + val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos debuglog("generating bridge from %s (%s): %s to %s: %s".format( other, flagsToString(newFlags), otpe + other.locationString, member, - erasure(owner)(member.tpe) + member.locationString) + erasure(root)(member.tpe) + member.locationString) ) // the parameter symbols need to have the new owner bridge setInfo (otpe cloneInfo bridge) bridgeTarget(bridge) = member - exitingErasure(owner.info.decls enter bridge) - if (other.owner == owner) { - exitingErasure(owner.info.decls.unlink(other)) - toBeRemoved += other + + if (!(member.tpe exists (_.typeSymbol.isDerivedValueClass)) || + checkBridgeOverrides(member, other, bridge)) { + exitingErasure(root.info.decls enter bridge) + if (other.owner == root) { + exitingErasure(root.info.decls.unlink(other)) + toBeRemoved += other + } + + bridgesScope enter bridge + bridges ::= makeBridgeDefDef(bridge, member, other) } - bridgesScope enter bridge - bridges ::= makeBridgeDefDef(bridge, member, other) } def makeBridgeDefDef(bridge: Symbol, member: Symbol, other: Symbol) = exitingErasure { @@ -466,7 +523,7 @@ abstract class Erasure extends AddInterfaces val rhs = member.tpe match { case MethodType(Nil, ConstantType(c)) => Literal(c) case _ => - val sel: Tree = Select(This(owner), member) + val sel: Tree = Select(This(root), member) val bridgingCall = (sel /: bridge.paramss)((fun, vparams) => Apply(fun, vparams map Ident)) maybeWrap(bridgingCall) @@ -480,8 +537,6 @@ abstract class Erasure extends AddInterfaces private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol) - private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] - private def isDifferentErasedValueType(tpe: Type, other: Type) = isErasedValueType(tpe) && (tpe ne other) @@ -814,7 +869,6 @@ abstract class Erasure extends AddInterfaces * but their erased types are the same. */ private def checkNoDoubleDefs(root: Symbol) { - def exitingErasure[T](op: => T): T = enteringPhase(phase.next.next)(op) def doubleDefError(sym1: Symbol, sym2: Symbol) { // the .toString must also be computed at the earlier phase val tpe1 = exitingRefchecks(root.thisType.memberType(sym1)) @@ -830,7 +884,7 @@ abstract class Erasure extends AddInterfaces 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: " + exitingErasure(sym1.tpe))) + (if (exitingRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + exitingPostErasure(sym1.tpe))) sym1.setInfo(ErrorType) } @@ -840,7 +894,7 @@ abstract class Erasure extends AddInterfaces if (e.sym.isTerm) { var e1 = decls.lookupNextEntry(e) while (e1 ne null) { - if (exitingErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) + if (exitingPostErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) e1 = decls.lookupNextEntry(e1) } } @@ -848,13 +902,14 @@ abstract class Erasure extends AddInterfaces } val opc = new overridingPairs.Cursor(root) { - 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.hasTypeAt(currentRun.refchecksPhase.id)) + 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.hasTypeAt(currentRun.refchecksPhase.id) + ) override def matches(sym1: Symbol, sym2: Symbol): Boolean = - exitingErasure(sym1.tpe =:= sym2.tpe) + exitingPostErasure(sym1.tpe =:= sym2.tpe) } while (opc.hasNext) { if (!exitingRefchecks( @@ -902,7 +957,7 @@ 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(owner) compute() + new ComputeBridges(unit, owner) compute() } def addBridges(stats: List[Tree], base: Symbol): List[Tree] = @@ -1001,7 +1056,7 @@ abstract class Erasure extends AddInterfaces } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { // !!! Another spot where we produce overloaded types (see test run/t6301) ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos - } else if (fn.symbol.isMethodWithExtension) { + } else if (fn.symbol.isMethodWithExtension && !fn.symbol.tpe.isErroneous) { Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) } else { tree |