Skip to content

Commit d3ce551

Browse files
committed
Erasure#typedSelect: Proper accessibility checking
We only need to avoid things which are inaccessible from the JVM point of view, so `c.a` should typecheck because `protected[foo] trait A` will be emitted as a public interface.
1 parent aeafe2d commit d3ce551

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,21 @@ object Erasure {
685685
qual
686686
}
687687

688+
/** Can we safely use `cls` as a qualifier without getting a runtime error on
689+
* the JVM due to its accessibility checks?
690+
*/
691+
def isJvmAccessible(cls: Symbol): Boolean =
692+
// Scala classes are always emitted as public, unless the
693+
// `private` modifier is used, but a non-private class can never
694+
// extend a private class, so such a class will never be a cast target.
695+
!cls.is(Flags.JavaDefined) || {
696+
// We can't rely on `isContainedWith` here because packages are
697+
// not nested from the JVM point of view.
698+
val boundary = cls.accessBoundary(cls.owner)(using preErasureCtx)
699+
(boundary eq defn.RootClass) ||
700+
(ctx.owner.enclosingPackageClass eq boundary)
701+
}
702+
688703
def recur(qual: Tree): Tree = {
689704
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
690705
val symIsPrimitive = sym.owner.isPrimitiveValueClass
@@ -704,7 +719,7 @@ object Erasure {
704719
select(qual1, sym)
705720
else
706721
val castTarget = // Avoid inaccessible cast targets, see i8661
707-
if sym.owner.isAccessibleFrom(qual1.tpe)(using preErasureCtx)
722+
if isJvmAccessible(sym.owner)
708723
then
709724
sym.owner.typeRef
710725
else

tests/pos/trait-access.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package foo {
2+
protected[foo] trait A {
3+
def a: Unit = {}
4+
}
5+
class B extends A
6+
}
7+
trait C extends foo.B
8+
object Test {
9+
def test: Unit = {
10+
val c = new C {}
11+
c.a
12+
}
13+
}

0 commit comments

Comments
 (0)