Skip to content

Commit 1501dcb

Browse files
committed
Disable generation of protected accessors in SuperAccessors phase
Fix remaining problems, mostly having to do with choosing between super accessors and protected accessors.
1 parent 8fc2165 commit 1501dcb

File tree

5 files changed

+120
-311
lines changed

5 files changed

+120
-311
lines changed

compiler/src/dotty/tools/dotc/transform/AccessProxies.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import config.Printers.transforms
2121
*/
2222
abstract class AccessProxies {
2323
import ast.tpd._
24+
import AccessProxies._
2425

2526
def getterName: ClassifiedNameKind
2627
def setterName: ClassifiedNameKind
@@ -76,17 +77,13 @@ abstract class AccessProxies {
7677

7778
def refersToAccessed(sym: Symbol) = accessedBy.get(sym) == Some(accessed)
7879

79-
val accessorClass = {
80-
def owningClass(start: Symbol) =
81-
start.ownersIterator.findSymbol(_.derivesFrom(accessed.owner))
80+
var accessorClass = hostForAccessorOf(accessed: Symbol)
81+
if (!accessorClass.exists) {
8282
val curCls = ctx.owner.enclosingClass
83-
var owner = owningClass(curCls) //`orElse` owningClass(curCls.linkedClass)
84-
if (!owner.exists) {
85-
transforms.println(i"${curCls.ownersIterator.toList}%, %")
86-
ctx.error(i"illegal access to protected ${accessed.showLocated} from $curCls", reference.pos)
87-
owner = curCls
88-
}
89-
owner
83+
transforms.println(i"${curCls.ownersIterator.toList}%, %")
84+
ctx.error(i"illegal access to protected ${accessed.showLocated} from $curCls",
85+
reference.pos)
86+
accessorClass = curCls
9087
}
9188

9289
val accessorRawInfo =
@@ -125,4 +122,8 @@ abstract class AccessProxies {
125122
tree
126123
}
127124
}
125+
}
126+
object AccessProxies {
127+
def hostForAccessorOf(accessed: Symbol)(implicit ctx: Context): Symbol =
128+
ctx.owner.ownersIterator.findSymbol(_.derivesFrom(accessed.owner))
128129
}

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
216216
case sel: Select =>
217217
val args1 = transform(args)
218218
val sel1 = transformSelect(sel, args1)
219-
if (superAcc.isProtectedAccessor(sel1)) sel1 else cpy.TypeApply(tree1)(sel1, args1)
219+
cpy.TypeApply(tree1)(sel1, args1)
220220
case _ =>
221221
super.transform(tree1)
222222
}
223-
case tree @ Assign(sel: Select, _) =>
224-
super.transform(superAcc.transformAssign(tree))
225223
case Inlined(call, bindings, expansion) =>
226224
// Leave only a call trace consisting of
227225
// - a reference to the top-level class from which the call was inlined,

compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,50 @@ import core.Flags._
88
import core.Decorators._
99
import MegaPhase.MiniPhase
1010
import ast.Trees._
11+
import util.Property
1112

1213
/** Add accessors for all protected accesses. An accessor is needed if
1314
* according to the rules of the JVM a protected class member is not accesissible
1415
* from the point of access, but is accessible if the access is from an enclosing
1516
* class. In this point a public access method is placed in that enclosing class.
1617
*/
18+
object ProtectedAccessors {
19+
val name = "protectedAccessors"
20+
21+
private val LHS = new Property.StickyKey[Unit]
22+
23+
/** Is the current context's owner inside the access boundary established by `sym`? */
24+
def insideBoundaryOf(sym: Symbol)(implicit ctx: Context): Boolean = {
25+
if (sym.is(JavaDefined)) {
26+
sym.is(JavaStatic) || // Java's static protected definitions are treated as public
27+
ctx.owner.enclosingPackageClass == sym.enclosingPackageClass
28+
}
29+
else {
30+
// For Scala-defined symbols we currently allow private and protected accesses
31+
// from inner packages, and compensate by widening accessibility of such symbols to public.
32+
// It would be good if we could revisit this at some point.
33+
val boundary = sym.accessBoundary(sym.enclosingPackageClass)
34+
ctx.owner.isContainedIn(boundary) || ctx.owner.isContainedIn(boundary.linkedClass)
35+
}
36+
}
37+
38+
/** Do we need a protected accessor if the current context's owner
39+
* is not in a subclass or subtrait of `sym`?
40+
*/
41+
def needsAccessorIfNotInSubclass(sym: Symbol)(implicit ctx: Context): Boolean =
42+
sym.isTerm && sym.is(Protected) &&
43+
!sym.owner.is(Trait) && // trait methods need to be handled specially, are currently always public
44+
!insideBoundaryOf(sym)
45+
46+
/** Do we need a protected accessor for accessing sym from the current context's owner? */
47+
def needsAccessor(sym: Symbol)(implicit ctx: Context): Boolean =
48+
needsAccessorIfNotInSubclass(sym) &&
49+
!ctx.owner.enclosingClass.derivesFrom(sym.owner)
50+
}
51+
1752
class ProtectedAccessors extends MiniPhase {
1853
import ast.tpd._
54+
import ProtectedAccessors._
1955

2056
override def phaseName = ProtectedAccessors.name
2157

@@ -24,39 +60,19 @@ class ProtectedAccessors extends MiniPhase {
2460
def setterName = ProtectedSetterName
2561

2662
val insert = new Insert {
27-
def needsAccessor(sym: Symbol)(implicit ctx: Context): Boolean = {
28-
def insideBoundary = {
29-
if (sym.is(JavaDefined)) {
30-
sym.is(JavaStatic) || // Java's static protected definitions are treated as public
31-
ctx.owner.enclosingPackageClass == sym.enclosingPackageClass
32-
}
33-
else {
34-
// For Scala-defined symbols we currently allow private and protected accesses
35-
// from inner packages, and compensate by widening accessibility of such symbols to public.
36-
// It would be good if we could revisit this at some point.
37-
val boundary = sym.accessBoundary(sym.enclosingPackageClass)
38-
ctx.owner.isContainedIn(boundary) || ctx.owner.isContainedIn(boundary.linkedClass)
39-
}
40-
}
41-
sym.isTerm && sym.is(Protected) &&
42-
!sym.owner.is(Trait) && // trait methods need to be handled specially, are currently always public
43-
!insideBoundary &&
44-
!ctx.owner.enclosingClass.derivesFrom(sym.owner)
45-
}
63+
def needsAccessor(sym: Symbol)(implicit ctx: Context) = ProtectedAccessors.needsAccessor(sym)
4664
}
4765
}
4866

49-
override def prepareForAssign(tree: Assign)(implicit ctx: Context) = tree.lhs match {
50-
case tree: RefTree if Accessors.insert.needsAccessor(tree.symbol) =>
51-
ctx.fresh.setTree(tree)
52-
case _ =>
53-
ctx
67+
override def prepareForAssign(tree: Assign)(implicit ctx: Context) = {
68+
tree.lhs match {
69+
case lhs: RefTree if needsAccessor(lhs.symbol) => lhs.putAttachment(LHS, ())
70+
case _ =>
71+
}
72+
ctx
5473
}
5574

56-
def isLHS(tree: RefTree)(implicit ctx: Context) = ctx.tree match {
57-
case Assign(lhs, _) => tree.symbol == lhs.symbol
58-
case _ => false
59-
}
75+
private def isLHS(tree: RefTree) = tree.removeAttachment(LHS).isDefined
6076

6177
override def transformIdent(tree: Ident)(implicit ctx: Context): Tree =
6278
if (isLHS(tree)) tree else Accessors.insert.accessorIfNeeded(tree)
@@ -70,5 +86,3 @@ class ProtectedAccessors extends MiniPhase {
7086
override def transformTemplate(tree: Template)(implicit ctx: Context): Tree =
7187
cpy.Template(tree)(body = Accessors.addAccessorDefs(tree.symbol.owner, tree.body))
7288
}
73-
object ProtectedAccessors { val name = "protectedAccessors" }
74-

0 commit comments

Comments
 (0)