Skip to content

Commit 88cfc02

Browse files
authored
Merge pull request #10794 from lrytz/t13007
Avoid call to inaccessible protected java method through self type
2 parents d800253 + 549ee23 commit 88cfc02

File tree

13 files changed

+192
-2
lines changed

13 files changed

+192
-2
lines changed

src/compiler/scala/tools/nsc/transform/Erasure.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,9 +1287,11 @@ abstract class Erasure extends InfoTransform
12871287

12881288
if (qualSym != owner)
12891289
tree.updateAttachment(new QualTypeSymAttachment(qualSym))
1290-
} else if (!isJvmAccessible(owner, context)) {
1290+
} else if (!isJvmAccessible(owner, context) ||
1291+
// scala/bug#13007: isJvmAccessible is true for a protected java method, even if accessed through erased self type
1292+
sym.isJavaDefined && sym.isProtected && !qual.tpe.typeSymbol.isSubClass(sym.owner)) {
12911293
val qualSym = qual.tpe.typeSymbol
1292-
if (qualSym != owner && isJvmAccessible(qualSym, context) && definesMemberAfterErasure(qualSym, sym))
1294+
if (qualSym != owner && isJvmAccessible(qualSym, context) && (definesMemberAfterErasure(qualSym, sym) || sym.overridingSymbol(qualSym).exists))
12931295
tree.updateAttachment(new QualTypeSymAttachment(qualSym))
12941296
else
12951297
reporter.error(tree.pos, s"Unable to emit reference to ${sym.fullLocationString}, $owner is not accessible in ${context.enclClass.owner}")

test/files/neg/t13007.check

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Test.scala:9: error: Unable to emit reference to method j in class J, class J is not accessible in trait T
2+
def t4 = j()
3+
^
4+
Test.scala:10: error: Unable to emit reference to method j in class J, class J is not accessible in trait T
5+
def t5 = this.j()
6+
^
7+
Test.scala:11: error: Unable to emit reference to method j in class J, class J is not accessible in trait T
8+
def t6 = self.j()
9+
^
10+
3 errors

test/files/neg/t13007/J.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package j;
2+
3+
public class J {
4+
protected boolean i() { return false; }
5+
protected boolean j() { return false; }
6+
public boolean k() { return false; }
7+
}

test/files/neg/t13007/Test.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package s
2+
3+
trait T { self: j.J =>
4+
override def i(): Boolean = true
5+
def t1 = i()
6+
def t2 = this.i()
7+
def t3 = self.i()
8+
9+
def t4 = j()
10+
def t5 = this.j()
11+
def t6 = self.j()
12+
13+
def t7 = k()
14+
def t8 = this.k()
15+
def t9 = self.k()
16+
}
17+
18+
class C extends j.J with T

test/files/neg/t13307b.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Test.scala:8: error: Implementation restriction: trait T accesses protected method j inside a concrete trait method.
2+
Add an accessor in a class extending class J as a workaround.
3+
def t4 = j()
4+
^
5+
Test.scala:9: error: Implementation restriction: trait T accesses protected method j inside a concrete trait method.
6+
Add an accessor in a class extending class J as a workaround.
7+
def t5 = this.j()
8+
^
9+
2 errors

test/files/neg/t13307b/J.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package j;
2+
3+
public class J {
4+
protected boolean i() { return false; }
5+
protected boolean j() { return false; }
6+
public boolean k() { return false; }
7+
}

test/files/neg/t13307b/Test.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package s
2+
3+
trait T extends j.J {
4+
override def i(): Boolean = true
5+
def t1 = i()
6+
def t2 = this.i()
7+
8+
def t4 = j()
9+
def t5 = this.j()
10+
11+
def t7 = k()
12+
def t8 = this.k()
13+
}
14+
15+
class C extends j.J with T

test/files/run/t13007/J.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package j;
2+
3+
public class J {
4+
protected boolean i() { return false; }
5+
protected boolean j() { return false; }
6+
public boolean k() { return false; }
7+
}

test/files/run/t13007/Test.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package s {
2+
3+
trait T {
4+
self: j.J =>
5+
override def i(): Boolean = true
6+
7+
def t1 = i()
8+
def t2 = this.i()
9+
def t3 = self.i()
10+
11+
// def t4 = j()
12+
// def t5 = this.j()
13+
// def t6 = self.j()
14+
15+
def t7 = k()
16+
def t8 = this.k()
17+
def t9 = self.k()
18+
}
19+
20+
class C extends j.J with T
21+
}
22+
23+
object Test {
24+
def main(args: Array[String]): Unit = {
25+
val c = new s.C
26+
assert(c.t1)
27+
assert(c.t2)
28+
assert(c.t3)
29+
assert(!c.t7)
30+
assert(!c.t8)
31+
assert(!c.t9)
32+
}
33+
}

test/files/run/t13307b/J.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package j;
2+
3+
public class J {
4+
protected boolean i() { return false; }
5+
protected boolean j() { return false; }
6+
public boolean k() { return false; }
7+
}

test/files/run/t13307b/Test.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package s {
2+
3+
trait T extends j.J {
4+
override def i(): Boolean = true
5+
6+
def t1 = i()
7+
def t2 = this.i()
8+
9+
// def t4 = j()
10+
// def t5 = this.j()
11+
12+
def t7 = k()
13+
def t8 = this.k()
14+
}
15+
16+
class C extends j.J with T
17+
}
18+
19+
object Test {
20+
def main(args: Array[String]): Unit = {
21+
val c = new s.C
22+
assert(c.t1)
23+
assert(c.t2)
24+
assert(!c.t7)
25+
assert(!c.t8)
26+
}
27+
}

test/junit/scala/lang/traits/BytecodeTest.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,22 @@ class BytecodeTest extends BytecodeTesting {
277277
assert(cls.isEmpty, cls.map(_.name))
278278
}
279279

280+
@Test
281+
def sd143a(): Unit = {
282+
val code =
283+
"""trait A { def m = 1 }
284+
|class B extends A { override def m = 2 }
285+
|trait T extends A
286+
|class C extends B with T {
287+
| override def m = super[T].m
288+
|}
289+
""".stripMargin
290+
291+
val List(a, b, c, t) = compileClasses(code)
292+
val ins = getInstructions(c, "m")
293+
assert(ins contains Invoke(INVOKESTATIC, "A", "m$", "(LA;)I", itf = true), ins.stringLines)
294+
}
295+
280296
@Test
281297
def sd143b(): Unit = {
282298
val jCode = List("interface A { default int m() { return 1; } }" -> "A.java")

test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,4 +1045,36 @@ class BytecodeTest extends BytecodeTesting {
10451045
assertSame(1, sm3.instructions.count(_.opcode == TABLESWITCH))
10461046
assertSame(1, sm3.instructions.count(_.opcode == LOOKUPSWITCH))
10471047
}
1048+
1049+
@Test def t13007(): Unit = {
1050+
val jc =
1051+
"""package j;
1052+
|public class J {
1053+
| protected boolean i() { return false; }
1054+
| public boolean k() { return false; }
1055+
|}
1056+
|""".stripMargin
1057+
1058+
val code =
1059+
"""package s
1060+
|trait T { self: j.J =>
1061+
| override def i(): Boolean = true
1062+
| def t1 = i()
1063+
| def t2 = this.i()
1064+
| def t3 = self.i()
1065+
|
1066+
| def t4 = k()
1067+
| def t5 = this.k()
1068+
| def t6 = self.k()
1069+
|}
1070+
|""".stripMargin
1071+
1072+
val List(t) = compileClasses(code, List((jc, "J.java")))
1073+
assertInvoke(getMethod(t, "t1"), "s/T", "i")
1074+
assertInvoke(getMethod(t, "t2"), "s/T", "i")
1075+
assertInvoke(getMethod(t, "t3"), "s/T", "i")
1076+
assertInvoke(getMethod(t, "t4"), "j/J", "k")
1077+
assertInvoke(getMethod(t, "t5"), "j/J", "k")
1078+
assertInvoke(getMethod(t, "t6"), "j/J", "k")
1079+
}
10481080
}

0 commit comments

Comments
 (0)