File tree 5 files changed +44
-9
lines changed
compiler/src/dotty/tools/dotc/transform
5 files changed +44
-9
lines changed Original file line number Diff line number Diff line change @@ -33,12 +33,18 @@ object ProtectedAccessors {
33
33
ctx.owner.isContainedIn(boundary) || ctx.owner.isContainedIn(boundary.linkedClass)
34
34
}
35
35
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 =
38
40
sym.isTerm && sym.is(Protected ) &&
39
41
! 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)
42
48
}
43
49
44
50
class ProtectedAccessors extends MiniPhase {
Original file line number Diff line number Diff line change @@ -175,7 +175,7 @@ class SuperAccessors(thisPhase: DenotTransformer) {
175
175
val sym = sel.symbol
176
176
177
177
def needsSuperAccessor =
178
- ProtectedAccessors .needsAccessor (sym) &&
178
+ ProtectedAccessors .needsAccessorIfNotInSubclass (sym) &&
179
179
AccessProxies .hostForAccessorOf(sym).is(Trait )
180
180
qual match {
181
181
case _ : This if needsSuperAccessor =>
@@ -185,10 +185,19 @@ class SuperAccessors(thisPhase: DenotTransformer) {
185
185
* If T extends C, then we can access it by casting
186
186
* the qualifier of the select to C.
187
187
*
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
+ *
188
192
* Otherwise, we need to go through an accessor,
189
193
* which the implementing class will provide an implementation for.
190
194
*/
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)
192
201
case Super (_, mix) =>
193
202
transformSuperSelect(sel)
194
203
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 1
1
// Derives from run/i17021.defs
2
2
// but with a Java protected member
3
- // which changes the behaviour
3
+ // and fixed calling code, that uses super
4
4
package p2:
5
5
trait B extends p1.A :
6
- def bar : Int = foo
6
+ def bar : Int = super . foo
7
7
8
8
class C extends B :
9
9
override def foo : Int = 2
10
10
11
11
object Test :
12
12
def main (args : Array [String ]): Unit =
13
13
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