diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 540de2cfe1..3d6fad4238 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -9,9 +9,7 @@ package transform import symtab._ import Flags.{ CASE => _, _ } -import scala.collection.mutable import scala.collection.mutable.ListBuffer -import scala.tools.nsc.settings.ScalaVersion /** This class ... * @@ -159,19 +157,24 @@ abstract class ExplicitOuter extends InfoTransform * elides outer pointers. */ def transformInfo(sym: Symbol, tp: Type): Type = tp match { - case MethodType(params, restpe1) => - val restpe = transformInfo(sym, restpe1) - if (sym.owner.isTrait && ((sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isModule)) { // 5 - sym.makeNotPrivate(sym.owner) + case MethodType(params, resTp) => + val resTpTransformed = transformInfo(sym, resTp) + + // juggle flags (and mangle names) after transforming info + if (sym.owner.isTrait) { + // TODO: I don't believe any private accessors remain after the fields phase + if ((sym hasFlag (ACCESSOR | SUPERACCESSOR)) || sym.isModule) sym.makeNotPrivate(sym.owner) // 5 + if (sym.isProtected) sym setFlag notPROTECTED // 6 } - if (sym.owner.isTrait && sym.isProtected) sym setFlag notPROTECTED // 6 - if (sym.isClassConstructor && isInner(sym.owner)) { // 1 - val p = sym.newValueParameter(innerClassConstructorParamName, sym.pos) - .setInfo(sym.owner.outerClass.thisType) - MethodType(p :: params, restpe) - } else if (restpe ne restpe1) - MethodType(params, restpe) + + val paramsWithOuter = + if (sym.isClassConstructor && isInner(sym.owner)) // 1 + sym.newValueParameter(innerClassConstructorParamName, sym.pos).setInfo(sym.owner.outerClass.thisType) :: params + else params + + if ((resTpTransformed ne resTp) || (paramsWithOuter ne params)) MethodType(paramsWithOuter, resTpTransformed) else tp + case ClassInfoType(parents, decls, clazz) => var decls1 = decls if (isInner(clazz) && !clazz.isInterface) { @@ -207,7 +210,7 @@ abstract class ExplicitOuter extends InfoTransform // class needs to have a common naming scheme, independently of whether // the field was accessed from an inner class or not. See #2946 if (sym.owner.isTrait && sym.isLocalToThis && - (sym.getterIn(sym.owner.toInterface) == NoSymbol)) + (sym.getterIn(sym.owner) == NoSymbol)) sym.makeNotPrivate(sym.owner) tp } @@ -238,12 +241,17 @@ abstract class ExplicitOuter extends InfoTransform * Will return `EmptyTree` if there is no outer accessor because of a premature self reference. */ private def outerSelect(base: Tree): Tree = { - val baseSym = base.tpe.typeSymbol.toInterface + val baseSym = base.tpe.typeSymbol val outerAcc = outerAccessor(baseSym) - if (outerAcc == NoSymbol && baseSym.ownersIterator.exists(isUnderConstruction)) { - // e.g neg/t6666.scala - // The caller will report the error with more information. - EmptyTree + if (outerAcc == NoSymbol) { + if (baseSym.ownersIterator.exists(isUnderConstruction)) { + // e.g neg/t6666.scala + // The caller will report the error with more information. + EmptyTree + } else { + globalError(currentOwner.pos, s"Internal error: unable to find the outer accessor symbol of $baseSym") + EmptyTree + } } else { val currentClass = this.currentClass //todo: !!! if this line is removed, we get a build failure that protected$currentClass need an override modifier // outerFld is the $outer field of the current class, if the reference can @@ -251,6 +259,7 @@ abstract class ExplicitOuter extends InfoTransform // otherwise it is NoSymbol val outerFld = if (outerAcc.owner == currentClass && + !outerAcc.owner.isTrait && base.tpe =:= currentClass.thisType && outerAcc.owner.isEffectivelyFinal) outerField(currentClass) suchThat (_.owner == currentClass) @@ -271,8 +280,7 @@ abstract class ExplicitOuter extends InfoTransform */ protected def outerPath(base: Tree, from: Symbol, to: Symbol): Tree = { //Console.println("outerPath from "+from+" to "+to+" at "+base+":"+base.tpe) - //assert(base.tpe.widen.baseType(from.toInterface) != NoType, ""+base.tpe.widen+" "+from.toInterface)//DEBUG - if (from == to || from.isImplClass && from.toInterface == to) base + if (from == to) base else outerPath(outerSelect(base), from.outerClass, to) } @@ -397,7 +405,7 @@ abstract class ExplicitOuter extends InfoTransform case Template(parents, self, decls) => val newDefs = new ListBuffer[Tree] atOwner(tree, currentOwner) { - if (!currentClass.isInterface || (currentClass hasFlag lateINTERFACE)) { + if (!currentClass.isInterface) { if (isInner(currentClass)) { if (hasOuterField(currentClass)) newDefs += outerFieldDef // (1a) @@ -446,8 +454,10 @@ abstract class ExplicitOuter extends InfoTransform // // See SI-6552 for an example of why `sym.owner.enclMethod hasAnnotation ScalaInlineClass` // is not suitable; if we make a method-local class non-private, it mangles outer pointer names. - if (currentClass != sym.owner || - (closestEnclMethod(currentOwner) hasAnnotation ScalaInlineClass)) + def enclMethodIsInline = closestEnclMethod(currentOwner) hasAnnotation ScalaInlineClass + // SI-8710 The extension method condition reflects our knowledge that a call to `new Meter(12).privateMethod` + // with later be rewritten (in erasure) to `Meter.privateMethod$extension(12)`. + if ((currentClass != sym.owner || enclMethodIsInline) && !sym.isMethodWithExtension) sym.makeNotPrivate(sym.owner) val qsym = qual.tpe.widen.typeSymbol @@ -474,14 +484,15 @@ abstract class ExplicitOuter extends InfoTransform // base.<outer>.eq(o) --> base.$outer().eq(o) if there's an accessor, else the whole tree becomes TRUE // TODO remove the synthetic `<outer>` method from outerFor?? case Apply(eqsel@Select(eqapp@Apply(sel@Select(base, nme.OUTER_SYNTH), Nil), eq), args) => - val outerFor = sel.symbol.owner.toInterface // TODO: toInterface necessary? + val outerFor = sel.symbol.owner val acc = outerAccessor(outerFor) if (acc == NoSymbol || // since we can't fix SI-4440 properly (we must drop the outer accessors of final classes when there's no immediate reference to them in sight) // at least don't crash... this duplicates maybeOmittable from constructors (acc.owner.isEffectivelyFinal && !acc.isOverridingSymbol)) { - currentRun.reporting.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.") + if (!base.tpe.hasAnnotation(UncheckedClass)) + currentRun.reporting.uncheckedWarning(tree.pos, "The outer reference in this type test cannot be checked at run time.") transform(TRUE) // urgh... drop condition if there's no accessor (or if it may disappear after constructors) } else { // println("(base, acc)= "+(base, acc)) |