Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Overcame trait/protected/java limitation.

I think this fixes SI-2296, the inability to access java protected
members from a trait which extends a java class. Counterexamples
appreciated. Closes SI-2296. Review by @dragos.

cherry-picked and adapted from f708b87.
  • Loading branch information...
commit de82f9a04a69a68118c513bda2bee9cd03560db0 1 parent dcf6976
@paulp paulp authored hubertp committed
View
382 src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -6,26 +6,25 @@
package scala.tools.nsc
package typechecker
-import scala.collection.mutable.ListBuffer
+import scala.collection.{ mutable, immutable }
+import mutable.ListBuffer
import symtab.Flags._
-/** This phase adds super accessors for all super calls that
- * either appear in a trait or have as a target a member of some outer class.
- * It also replaces references to parameter accessors with aliases by super
- * references to these aliases.
- * The phase also checks that symbols accessed from super are not abstract,
- * or are overridden by an abstract override.
- * Finally, the phase also mangles the names of class-members which are private
- * up to an enclosing non-package class, in order to avoid overriding conflicts.
+/** This phase adds super accessors for all super calls that either
+ * appear in a trait or have as a target a member of some outer class.
+ * It also replaces references to parameter accessors with aliases
+ * by super references to these aliases. The phase also checks that
+ * symbols accessed from super are not abstract, or are overridden by
+ * an abstract override. Finally, the phase also mangles the names
+ * of class-members which are private up to an enclosing non-package
+ * class, in order to avoid overriding conflicts.
*
* @author Martin Odersky
* @version 1.0
*/
abstract class SuperAccessors extends transform.Transform with transform.TypingTransformers {
- // inherits abstract value `global' and class `Phase' from Transform
-
import global._
- import definitions.{ UnitClass, isRepeatedParamType, isByNameParamType, Any_asInstanceOf }
+ import definitions.{ UnitClass, ObjectClass, isRepeatedParamType, isByNameParamType, Any_asInstanceOf }
import analyzer.{ restrictionError }
/** the following two members override abstract members in Transform */
@@ -35,11 +34,40 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
new SuperAccTransformer(unit)
class SuperAccTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
+ /** validCurrentOwner arrives undocumented, but I reverse engineer it to be
+ * a flag for needsProtectedAccessor which is false while transforming either
+ * a by-name argument block or a closure. This excludes them from being
+ * considered able to access protected members via subclassing (why?) which in turn
+ * increases the frequency with which needsProtectedAccessor will be true.
+ */
private var validCurrentOwner = true
- private var accDefs: List[(Symbol, ListBuffer[Tree])] = List()
+ private val accDefs = mutable.Map[Symbol, ListBuffer[Tree]]()
+ private def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg)
- private def accDefBuf(clazz: Symbol) =
- accDefs collectFirst { case (`clazz`, buf) => buf } getOrElse sys.error("no acc def buf for "+clazz)
+ private def storeAccessorDefinition(clazz: Symbol, tree: Tree) = {
+ val buf = accDefs.getOrElse(clazz, sys.error("no acc def buf for "+clazz))
+ buf += typers(clazz) typed tree
+ }
+ private def ensureAccessor(sel: Select) = {
+ val Select(qual, name) = sel
+ val sym = sel.symbol
+ val clazz = qual.symbol
+ val supername = nme.superName(name)
+ val superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) orElse {
+ debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug
+ val acc = clazz.newMethod(supername, sel.pos).setFlag(SUPERACCESSOR | PRIVATE).setAlias(sym)
+ val tpe = clazz.thisType memberType sym match {
+ case t if sym.isModule && !sym.isMethod => NullaryMethodType(t)
+ case t => t
+ }
+ acc.setInfo(tpe.cloneInfo(acc))
+ clazz.info.decls.enter(acc)
+ storeAccessorDefinition(clazz, DefDef(acc, EmptyTree))
+ acc
+ }
+
+ atPos(sel.pos)(Select(gen.mkAttributedThis(clazz), superAcc) setType sel.tpe)
+ }
private def transformArgs(args: List[Tree], params: List[Symbol]) =
((args, params).zipped map { (arg, param) =>
@@ -78,47 +106,21 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
}
- private def transformSuperSelect(tree: Tree): Tree = tree match {
- case Select(sup @ Super(_, mix), name) =>
- val sym = tree.symbol
- val clazz = sup.symbol
-
- if (sym.isDeferred) {
- val member = sym.overridingSymbol(clazz);
- if (mix != tpnme.EMPTY || member == NoSymbol ||
- !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)))
- unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+
- "unless it is overridden by a member declared `abstract' and `override'");
- }
- if (tree.isTerm && mix == tpnme.EMPTY &&
- (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) {
- val supername = nme.superName(sym.name)
- var superAcc = clazz.info.decl(supername).suchThat(_.alias == sym)
- if (superAcc == NoSymbol) {
- if (settings.debug.value) log("add super acc " + sym + sym.locationString + " to `" + clazz);//debug
- superAcc =
- clazz.newMethod(tree.pos, supername)
- .setFlag(SUPERACCESSOR | PRIVATE)
- .setAlias(sym)
- var superAccTpe = clazz.thisType.memberType(sym)
- if (sym.isModule && !sym.isMethod) {
- // the super accessor always needs to be a method. See #231
- superAccTpe = NullaryMethodType(superAccTpe)
- }
- superAcc.setInfo(superAccTpe.cloneInfo(superAcc))
- //println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG
- clazz.info.decls enter superAcc;
- accDefBuf(clazz) += typers(clazz).typed(DefDef(superAcc, EmptyTree))
- }
- atPos(sup.pos) {
- Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe;
- }
- } else {
- tree
- }
- case _ =>
- assert(tree.tpe.isError, tree)
- tree
+ private def transformSuperSelect(sel: Select): Tree = {
+ val Select(sup @ Super(_, mix), name) = sel
+ val sym = sel.symbol
+ val clazz = sup.symbol
+
+ if (sym.isDeferred) {
+ val member = sym.overridingSymbol(clazz);
+ if (mix != tpnme.EMPTY || member == NoSymbol ||
+ !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)))
+ unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+
+ "unless it is overridden by a member declared `abstract' and `override'");
+ }
+ if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner))
+ ensureAccessor(sel)
+ else sel
}
// Disallow some super.XX calls targeting Any methods which would
@@ -133,8 +135,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
def mayNeedProtectedAccessor(sel: Select, args: List[Tree], goToSuper: Boolean) =
if (needsProtectedAccessor(sym, tree.pos)) {
- if (settings.debug.value)
- log("Adding protected accessor for " + tree)
+ debuglog("Adding protected accessor for " + tree)
transform(makeAccessor(sel, args))
}
@@ -149,12 +150,14 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
case ClassDef(_, _, _, _) =>
checkCompanionNameClashes(sym)
val decls = sym.info.decls
- for (s <- decls.toList) {
+ for (s <- decls) {
if (s.privateWithin.isClass && !s.isProtected && !s.privateWithin.isModuleClass &&
!s.hasFlag(EXPANDEDNAME) && !s.isConstructor) {
+ val savedName = s.name
decls.unlink(s)
s.expandName(s.privateWithin)
decls.enter(s)
+ log("Expanded '%s' to '%s' in %s".format(savedName, s.name, sym))
}
}
if (settings.verbose.value && forScaladoc && !sym.isAnonymousClass) {
@@ -174,37 +177,80 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
checkCompanionNameClashes(sym)
super.transform(tree)
case Template(parents, self, body) =>
- val ownAccDefs = new ListBuffer[Tree];
- accDefs = (currentOwner, ownAccDefs) :: accDefs;
+ val ownAccDefs = new ListBuffer[Tree]
+ accDefs(currentOwner) = ownAccDefs
// ugly hack... normally, the following line should not be
// necessary, the 'super' method taking care of that. but because
// that one is iterating through parents (and we dont want that here)
// we need to inline it.
curTree = tree
- val body1 = atOwner(currentOwner) { transformTrees(body) }
- accDefs = accDefs.tail;
- treeCopy.Template(tree, parents, self, ownAccDefs.toList ::: body1)
+ val body1 = atOwner(currentOwner)(transformTrees(body))
+ accDefs -= currentOwner
+ ownAccDefs ++= body1
+ treeCopy.Template(tree, parents, self, ownAccDefs.toList)
case TypeApply(sel @ Select(This(_), name), args) =>
mayNeedProtectedAccessor(sel, args, false)
case sel @ Select(qual @ This(_), name) =>
- // direct calls to aliases of param accessors to the superclass in order to avoid
- // duplicating fields.
- if (sym.isParamAccessor && sym.alias != NoSymbol) {
- val result = localTyper.typed {
- Select(
- Super(qual, tpnme.EMPTY/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos,
- sym.alias) setPos tree.pos
+ // warn if they are selecting a private[this] member which
+ // also exists in a superclass, because they may be surprised
+ // to find out that a constructor parameter will shadow a
+ // field. See SI-4762.
+ if (settings.lint.value) {
+ if (sym.isPrivateLocal && sym.paramss.isEmpty) {
+ qual.symbol.ancestors foreach { parent =>
+ parent.info.decls filterNot (x => x.isPrivate || x.hasLocalFlag) foreach { m2 =>
+ if (sym.name == m2.name && m2.isGetter && m2.accessed.isMutable) {
+ unit.warning(sel.pos,
+ sym.accessString + " " + sym.fullLocationString + " shadows mutable " + m2.name
+ + " inherited from " + m2.owner + ". Changes to " + m2.name + " will not be visible within "
+ + sym.owner + " - you may want to give them distinct names."
+ )
+ }
+ }
+ }
}
- if (settings.debug.value)
- log("alias replacement: " + tree + " ==> " + result);//debug
+ }
+
+ // direct calls to aliases of param accessors to the superclass in order to avoid
+ // duplicating fields.
+ if (sym.isParamAccessor && sym.alias != NoSymbol) {
+ val result = (localTyper.typedPos(tree.pos) {
+ Select(Super(qual, tpnme.EMPTY) setPos qual.pos, sym.alias)
+ }).asInstanceOf[Select]
+ debuglog("alias replacement: " + tree + " ==> " + result);//debug
localTyper.typed(gen.maybeMkAsInstanceOf(transformSuperSelect(result), sym.tpe, sym.alias.tpe, true))
}
- else mayNeedProtectedAccessor(sel, List(EmptyTree), false)
+ else {
+ /** A trait which extends a class and accesses a protected member
+ * of that class cannot implement the necessary accessor method
+ * because its implementation is in an implementation class (e.g.
+ * Foo$class) which inherits nothing, and jvm access restrictions
+ * require the call site to be in an actual subclass. So non-trait
+ * classes inspect their ancestors for any such situations and
+ * generate the accessors. See SI-2296.
+ */
+ // FIXME - this should be unified with needsProtectedAccessor, but some
+ // subtlety which presently eludes me is foiling my attempts.
+ val shouldEnsureAccessor = (
+ currentClass.isTrait
+ && sym.isProtected
+ && sym.enclClass != currentClass
+ && !sym.owner.isTrait
+ && (sym.owner.enclosingPackageClass != currentPackage)
+ && (qual.symbol.info.member(sym.name) ne NoSymbol)
+ )
+ if (shouldEnsureAccessor) {
+ log("Ensuring accessor for call to protected " + sym.fullLocationString + " from " + currentClass)
+ ensureAccessor(sel)
+ }
+ else
+ mayNeedProtectedAccessor(sel, List(EmptyTree), false)
+ }
- case Select(Super(_, mix), name) =>
+ case sel @ Select(Super(_, mix), name) =>
if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) {
unit.error(tree.pos, "super may be not be used on "+
(if (sym.hasAccessorFlag) sym.accessed else sym))
@@ -212,7 +258,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
else if (isDisallowed(sym)) {
unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead")
}
- transformSuperSelect(tree)
+ transformSuperSelect(sel)
case TypeApply(sel @ Select(qual, name), args) =>
mayNeedProtectedAccessor(sel, args, true)
@@ -224,10 +270,9 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
if (lhs.symbol.isVariable &&
lhs.symbol.isJavaDefined &&
needsProtectedAccessor(lhs.symbol, tree.pos)) {
- if (settings.debug.value) log("Adding protected setter for " + tree)
+ debuglog("Adding protected setter for " + tree)
val setter = makeSetter(lhs);
- if (settings.debug.value)
- log("Replaced " + tree + " with " + setter);
+ debuglog("Replaced " + tree + " with " + setter);
transform(localTyper.typed(Apply(setter, List(qual, rhs))))
} else
super.transform(tree)
@@ -258,21 +303,20 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
private def withInvalidOwner[A](trans: => A): A = {
- val prevValidCurrentOwner = validCurrentOwner
+ val saved = validCurrentOwner
validCurrentOwner = false
- val result = trans
- validCurrentOwner = prevValidCurrentOwner
- result
+ try trans
+ finally validCurrentOwner = saved
}
/** Add a protected accessor, if needed, and return a tree that calls
- * the accessor and returns the the same member. The result is already
+ * the accessor and returns the same member. The result is already
* typed.
*/
private def makeAccessor(tree: Select, targs: List[Tree]): Tree = {
val Select(qual, name) = tree
val sym = tree.symbol
- val clazz = hostForAccessorOf(sym, currentOwner.enclClass)
+ val clazz = hostForAccessorOf(sym, currentClass)
/** Return a list of list of types of all value parameter sections. */
def allParamTypes(tpe: Type): List[List[Type]] = tpe match {
@@ -283,10 +327,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
assert(clazz != NoSymbol, sym)
- if (settings.debug.value) log("Decided for host class: " + clazz)
+ debuglog("Decided for host class: " + clazz)
- val accName = nme.protName(sym.originalName)
- val hasArgs = sym.tpe.paramTypes != Nil
+ val accName = nme.protName(sym.originalName)
+ val hasArgs = sym.tpe.paramSectionCount > 0
val memberType = refchecks.toScalaRepeatedParam(sym.tpe) // fix for #2413
// if the result type depends on the this type of an enclosing class, the accessor
@@ -302,31 +346,31 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
memberType.cloneInfo(protAcc).asSeenFrom(qual.tpe, sym.owner))
}
- var protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s))
- if (protAcc == NoSymbol) {
- protAcc = clazz.newMethod(tree.pos, nme.protName(sym.originalName))
- protAcc.setInfo(accType(protAcc))
- clazz.info.decls.enter(protAcc);
- val code = DefDef(protAcc, {
- val obj = protAcc.paramss.head.head // receiver
- protAcc.paramss.tail.zip(allParamTypes(sym.tpe)).foldLeft(Select(Ident(obj), sym): Tree) (
- (fun, pvparams) => {
- Apply(fun, (pvparams._1, pvparams._2).zipped map (makeArg(_, obj, _)))
- })
+ val protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s)) orElse {
+ val newAcc = clazz.newMethod(nme.protName(sym.originalName), tree.pos)
+ newAcc.setInfo(accType(newAcc))
+ clazz.info.decls.enter(newAcc)
+
+ val code = DefDef(newAcc, {
+ val (receiver :: _) :: tail = newAcc.paramss
+ val base: Tree = Select(Ident(receiver), sym)
+ val args = (tail, allParamTypes(sym.info)).zipped.map((params, tpes) => (params, tpes).zipped.map(makeArg(_, receiver, _)))
+ args.foldLeft(base)(Apply(_, _))
})
- if (settings.debug.value)
- log(code)
- accDefBuf(clazz) += typers(clazz).typed(code)
+ debuglog("" + code)
+ storeAccessorDefinition(clazz, code)
+ newAcc
}
- var res: Tree = atPos(tree.pos) {
- if (targs.head == EmptyTree)
- Apply(Select(This(clazz), protAcc), List(qual))
- else
- Apply(TypeApply(Select(This(clazz), protAcc), targs), List(qual))
+ val selection = Select(This(clazz), protAcc)
+ def mkApply(fn: Tree) = Apply(fn, qual :: Nil)
+ val res = atPos(tree.pos) {
+ targs.head match {
+ case EmptyTree => mkApply(selection)
+ case _ => mkApply(TypeApply(selection, targs))
+ }
}
- if (settings.debug.value)
- log("Replaced " + tree + " with " + res)
+ debuglog("Replaced " + tree + " with " + res)
if (hasArgs) localTyper.typedOperator(res) else localTyper.typed(res)
}
@@ -341,33 +385,17 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
*
* Also, it calls using repeated parameters are ascribed with ': _*'
*/
- private def makeArg(v: Symbol, obj: Symbol, expectedTpe: Type): Tree = {
- var res: Tree = Ident(v)
- val sym = obj.tpe.typeSymbol
- var ownerClass: Symbol = NoSymbol
-
- val isDependentType = expectedTpe match {
- case TypeRef(path, _, _) =>
- ownerClass = thisTypeOfPath(path)
- if (sym.isSubClass(ownerClass)) true else false
- case _ => false
- }
- if (isRepeatedParamType(v.info)) {
- res = gen.wildcardStar(res)
- log("adapted to wildcard star: " + res)
+ private def makeArg(v: Symbol, obj: Symbol, pt: Type): Tree = {
+ // owner class
+ val clazz = pt match {
+ case TypeRef(pre, _, _) => thisTypeOfPath(pre)
+ case _ => NoSymbol
}
- if (isDependentType) {
- val preciseTpe = expectedTpe.asSeenFrom(singleType(NoPrefix, obj), ownerClass) //typeRef(singleType(NoPrefix, obj), v.tpe.symbol, List())
- TypeApply(Select(res, Any_asInstanceOf),
- List(TypeTree(preciseTpe)))
- } else res
- }
-
- /** For a path-dependent type, return the this type. */
- private def thisTypeOfPath(path: Type): Symbol = path match {
- case ThisType(outerSym) => outerSym
- case SingleType(rest, _) => thisTypeOfPath(rest)
- case _ => NoSymbol
+ val result = gen.paramToArg(v)
+ if (clazz != NoSymbol && (obj.tpe.typeSymbol isSubClass clazz)) // path-dependent type
+ gen.mkAsInstanceOf(result, pt.asSeenFrom(singleType(NoPrefix, obj), clazz))
+ else
+ result
}
/** Add an accessor for field, if needed, and return a selection tree for it .
@@ -375,34 +403,28 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
*/
private def makeSetter(tree: Select): Tree = {
val field = tree.symbol
- val clazz = hostForAccessorOf(field, currentOwner.enclClass)
+ val clazz = hostForAccessorOf(field, currentClass)
assert(clazz != NoSymbol, field)
- if (settings.debug.value)
- log("Decided for host class: " + clazz)
+ debuglog("Decided for host class: " + clazz)
+
val accName = nme.protSetterName(field.originalName)
- var protAcc = clazz.info.decl(accName)
- if (protAcc == NoSymbol) {
- protAcc = clazz.newMethod(field.pos, nme.protSetterName(field.originalName))
- protAcc.setInfo(MethodType(protAcc.newSyntheticValueParams(List(clazz.typeOfThis, field.tpe)),
- UnitClass.tpe))
+ val protectedAccessor = clazz.info decl accName orElse {
+ val protAcc = clazz.newMethod(accName, field.pos)
+ val paramTypes = List(clazz.typeOfThis, field.tpe)
+ val params = protAcc newSyntheticValueParams paramTypes
+ val accessorType = MethodType(params, UnitClass.tpe)
+
+ protAcc.setInfo(accessorType)
clazz.info.decls.enter(protAcc)
- val code = DefDef(protAcc, {
- val obj :: value :: Nil = protAcc.paramss.head;
- atPos(tree.pos) {
- Assign(
- Select(Ident(obj), field.name),
- Ident(value))
- }
- })
- if (settings.debug.value)
- log(code);
- accDefBuf(clazz) += typers(clazz).typed(code)
+ val obj :: value :: Nil = params
+ storeAccessorDefinition(clazz, DefDef(protAcc, Assign(Select(Ident(obj), field.name), Ident(value))))
+
+ protAcc
}
- var res: Tree = atPos(tree.pos) { Select(This(clazz), protAcc) }
- res
+ atPos(tree.pos)(Select(This(clazz), protectedAccessor))
}
- /** Does `sym' need an accessor when accessed from `currentOwner'?
+ /** Does `sym` need an accessor when accessed from `currentClass`?
* A special case arises for classes with explicit self-types. If the
* self type is a Java class, and a protected accessor is needed, we issue
* an error. If the self type is a Scala class, we don't add an accessor.
@@ -416,23 +438,20 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
* classes, this has to be signaled as error.
*/
private def needsProtectedAccessor(sym: Symbol, pos: Position): Boolean = {
- val clazz = currentOwner.enclClass
+ val clazz = currentClass
def accessibleThroughSubclassing =
validCurrentOwner && clazz.thisSym.isSubClass(sym.owner) && !clazz.isTrait
- def packageAccessBoundry(sym: Symbol) = {
- val b = sym.accessBoundary(sym.owner)
- if (b.isPackageClass) b
- else b.enclosingPackageClass
- }
+ def packageAccessBoundry(sym: Symbol) =
+ sym.accessBoundary(sym.enclosingPackageClass)
val isCandidate = (
sym.isProtected
&& sym.isJavaDefined
&& !sym.definedInPackage
&& !accessibleThroughSubclassing
- && (sym.owner.enclosingPackageClass != currentOwner.enclosingPackageClass)
- && (sym.owner.enclosingPackageClass == packageAccessBoundry(sym))
+ && (sym.enclosingPackageClass != currentPackage)
+ && (sym.enclosingPackageClass == sym.accessBoundary(sym.enclosingPackageClass))
)
val host = hostForAccessorOf(sym, clazz)
def isSelfType = !(host.tpe <:< host.typeOfThis) && {
@@ -442,15 +461,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
)
true
}
- def isJavaProtected = host.isTrait && sym.isJavaDefined && {
- restrictionError(pos, unit,
- """|%s accesses protected %s inside a concrete trait method.
- |Add an accessor in a class extending %s as a workaround.""".stripMargin.format(
- clazz, sym, sym.enclClass)
- )
- true
- }
- isCandidate && !host.isPackageClass && !isSelfType && !isJavaProtected
+ isCandidate && !host.isPackageClass && !isSelfType
}
/** Return the innermost enclosing class C of referencingClass for which either
@@ -462,23 +473,28 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
if (referencingClass.isSubClass(sym.owner.enclClass)
|| referencingClass.thisSym.isSubClass(sym.owner.enclClass)
|| referencingClass.enclosingPackageClass == sym.owner.enclosingPackageClass) {
- assert(referencingClass.isClass)
+ assert(referencingClass.isClass, referencingClass)
referencingClass
} else if(referencingClass.owner.enclClass != NoSymbol)
hostForAccessorOf(sym, referencingClass.owner.enclClass)
else referencingClass
}
+ /** For a path-dependent type, return the this type. */
+ private def thisTypeOfPath(path: Type): Symbol = path match {
+ case ThisType(outerSym) => outerSym
+ case SingleType(rest, _) => thisTypeOfPath(rest)
+ case _ => NoSymbol
+ }
+
/** Is 'tpe' the type of a member of an enclosing class? */
private def isThisType(tpe: Type): Boolean = tpe match {
- case ThisType(sym) => (sym.isClass && !sym.isPackageClass)
- case TypeRef(pref, _, _) => isThisType(pref)
- case SingleType(pref, _) => isThisType(pref)
- case RefinedType(parents, defs) =>
- parents.exists(isThisType(_))
- case AnnotatedType(_, tp, _) =>
- isThisType(tp)
- case _ => false
+ case ThisType(sym) => sym.isClass && !sym.isPackageClass
+ case TypeRef(pre, _, _) => isThisType(pre)
+ case SingleType(pre, _) => isThisType(pre)
+ case RefinedType(parents, _) => parents exists isThisType
+ case AnnotatedType(_, tp, _) => isThisType(tp)
+ case _ => false
}
}
}
View
14 src/library/scala/reflect/generic/HasFlags.scala
@@ -183,6 +183,20 @@ import Flags._
def hasTraitFlag = hasFlag(TRAIT)
def hasDefaultFlag = hasFlag(DEFAULTPARAM)
+ def accessString: String = {
+ val pw = if (hasAccessBoundary) privateWithin.toString else ""
+
+ if (pw == "") {
+ if (hasAllFlags(PRIVATE | LOCAL)) "private[this]"
+ else if (hasAllFlags(PROTECTED | LOCAL)) "protected[this]"
+ else if (hasFlag(PRIVATE)) "private"
+ else if (hasFlag(PROTECTED)) "protected"
+ else ""
+ }
+ else if (hasFlag(PROTECTED)) "protected[" + pw + "]"
+ else "private[" + pw + "]"
+ }
+
// Straightforwardly named accessors already being used differently.
// These names are most likely temporary.
def hasAbstractFlag = hasFlag(ABSTRACT)
View
2  test/files/run/t2296a.check
@@ -0,0 +1,2 @@
+J.foo()
+J.foo()
View
7 test/files/run/t2296a/J.java
@@ -0,0 +1,7 @@
+package j;
+
+public class J {
+ protected void foo() {
+ System.out.println("J.foo()");
+ }
+}
View
18 test/files/run/t2296a/S.scala
@@ -0,0 +1,18 @@
+package s {
+ import j.J
+
+ trait S extends J {
+ def bar() {
+ foo()
+ }
+ }
+
+ class SC extends J with S
+}
+
+object Test {
+ def main(args : Array[String]) {
+ (new s.SC).bar()
+ (new s.S { }).bar()
+ }
+}
View
2  test/files/run/t2296b.check
@@ -0,0 +1,2 @@
+J.foo()
+J.foo()
View
7 test/files/run/t2296b/J_1.java
@@ -0,0 +1,7 @@
+package j;
+
+public class J_1 {
+ protected void foo() {
+ System.out.println("J.foo()");
+ }
+}
View
18 test/files/run/t2296b/S_2.scala
@@ -0,0 +1,18 @@
+package s {
+ import j.J_1
+
+ trait S extends J_1 {
+ def bar() {
+ foo()
+ }
+ }
+
+ class SC extends J_1 with S
+}
+
+object Test {
+ def main(args : Array[String]) {
+ (new s.SC).bar()
+ (new s.S { }).bar()
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.