File tree Expand file tree Collapse file tree 5 files changed +44
-9
lines changed
compiler/src/dotty/tools/dotc/transform Expand file tree Collapse file tree 5 files changed +44
-9
lines changed Original file line number Diff line number Diff line change @@ -33,12 +33,18 @@ object ProtectedAccessors {
3333 ctx.owner.isContainedIn(boundary) || ctx.owner.isContainedIn(boundary.linkedClass)
3434 }
3535
36- /** Do we need a protected accessor for accessing sym from the current context's owner? */
37- def needsAccessor (sym : Symbol )(using Context ): Boolean =
36+ /** Do we need a protected accessor if the current context's owner
37+ * is not in a subclass or subtrait of `sym`?
38+ */
39+ def needsAccessorIfNotInSubclass (sym : Symbol )(using Context ): Boolean =
3840 sym.isTerm && sym.is(Protected ) &&
3941 ! sym.owner.is(Trait ) && // trait methods need to be handled specially, are currently always public
40- ! insideBoundaryOf(sym) &&
41- (sym.is(JavaDefined ) || ! ctx.owner.enclosingClass.derivesFrom(sym.owner))
42+ ! insideBoundaryOf(sym)
43+
44+ /** Do we need a protected accessor for accessing sym from the current context's owner? */
45+ def needsAccessor (sym : Symbol )(using Context ): Boolean =
46+ needsAccessorIfNotInSubclass(sym) &&
47+ ! ctx.owner.enclosingClass.derivesFrom(sym.owner)
4248}
4349
4450class ProtectedAccessors extends MiniPhase {
Original file line number Diff line number Diff line change @@ -175,7 +175,7 @@ class SuperAccessors(thisPhase: DenotTransformer) {
175175 val sym = sel.symbol
176176
177177 def needsSuperAccessor =
178- ProtectedAccessors .needsAccessor (sym) &&
178+ ProtectedAccessors .needsAccessorIfNotInSubclass (sym) &&
179179 AccessProxies .hostForAccessorOf(sym).is(Trait )
180180 qual match {
181181 case _ : This if needsSuperAccessor =>
@@ -185,10 +185,19 @@ class SuperAccessors(thisPhase: DenotTransformer) {
185185 * If T extends C, then we can access it by casting
186186 * the qualifier of the select to C.
187187 *
188+ * That's because the protected method is actually public,
189+ * so we can call it. For truly protected methods, like from
190+ * Java, we error instead of emitting the wrong code (i17021.ext-java).
191+ *
188192 * Otherwise, we need to go through an accessor,
189193 * which the implementing class will provide an implementation for.
190194 */
191- superAccessorCall(sel)
195+ if ctx.owner.enclosingClass.derivesFrom(sym.owner) then
196+ if sym.is(JavaDefined ) then
197+ report.error(em " ${ctx.owner} accesses protected $sym inside a concrete trait method: use super. ${sel.name} instead " , sel.srcPos)
198+ sel
199+ else
200+ superAccessorCall(sel)
192201 case Super (_, mix) =>
193202 transformSuperSelect(sel)
194203 case _ =>
Original file line number Diff line number Diff line change 1+ // Derives from run/i17021.defs, but with a Java protected member
2+ package p1 ;
3+
4+ public class A {
5+ protected int foo () { return 1 ; }
6+ }
Original file line number Diff line number Diff line change 1+ // Derives from run/i17021.defs
2+ // but with a Java protected member
3+ // which leads to a compile error
4+ package p2:
5+ trait B extends p1.A :
6+ def bar : Int = foo // error: method bar accesses protected method foo inside a concrete trait method: use super.foo instead
7+
8+ class C extends B :
9+ override def foo : Int = 2
10+
11+ object Test :
12+ def main (args : Array [String ]): Unit =
13+ val n = new p2.C ().bar
14+ assert(n == 2 , n)
Original file line number Diff line number Diff line change 11// Derives from run/i17021.defs
22// but with a Java protected member
3- // which changes the behaviour
3+ // and fixed calling code, that uses super
44package p2:
55 trait B extends p1.A :
6- def bar : Int = foo
6+ def bar : Int = super . foo
77
88 class C extends B :
99 override def foo : Int = 2
1010
1111object Test :
1212 def main (args : Array [String ]): Unit =
1313 val n = new p2.C ().bar
14- assert(n == 1 , n) // B can only call super.foo
14+ assert(n == 1 , n)
You can’t perform that action at this time.
0 commit comments