diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index b18c6993303f..f1f4be4e4999 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -877,7 +877,7 @@ object SymDenotations { * As a side effect, drop Local flags of members that are not accessed via the ThisType * of their owner. */ - final def isAccessibleFrom(pre: Type, superAccess: Boolean = false, whyNot: StringBuffer | Null = null)(using Context): Boolean = { + final def isAccessibleFrom(pre: Type, superAccess: Boolean = false)(using Context): Boolean = { /** Are we inside definition of `boundary`? * If this symbol is Java defined, package structure is interpreted to be flat. @@ -906,26 +906,13 @@ object SymDenotations { /** Is protected access to target symbol permitted? */ def isProtectedAccessOK: Boolean = - inline def fail(str: String): false = - if whyNot != null then whyNot.nn.append(str) - false val cls = owner.enclosingSubClass if !cls.exists then - if pre.termSymbol.isPackageObject && accessWithin(pre.termSymbol.owner) then - true - else - val encl = if ctx.owner.isConstructor then ctx.owner.enclosingClass.owner.enclosingClass else ctx.owner.enclosingClass - val location = if owner.is(Final) then owner.showLocated else owner.showLocated + " or one of its subclasses" - fail(i""" - | Protected $this can only be accessed from $location.""") - else if isType || pre.derivesFrom(cls) || isConstructor || owner.is(ModuleClass) then + pre.termSymbol.isPackageObject && accessWithin(pre.termSymbol.owner) + else // allow accesses to types from arbitrary subclasses fixes #4737 // don't perform this check for static members - true - else - val location = if cls.is(Final) then cls.showLocated else cls.showLocated + " or one of its subclasses" - fail(i""" - | Protected $this can only be accessed from $location.""") + isType || pre.derivesFrom(cls) || isConstructor || owner.is(ModuleClass) end isProtectedAccessOK if pre eq NoPrefix then true diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 6d115c0e18a9..db7f00914ddc 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -876,7 +876,7 @@ extends Message(PatternMatchExhaustivityID) { val pathes = List( ActionPatch( - srcPos = endPos, + srcPos = endPos, replacement = uncoveredCases.map(c => indent(s"case $c => ???", startColumn)) .mkString("\n", "\n", "") ), @@ -2986,7 +2986,13 @@ extends ReferenceMsg(CannotBeAccessedID): i"none of the overloaded alternatives named $name can" val where = if (ctx.owner.exists) i" from ${ctx.owner.enclosingClass}" else "" val whyNot = new StringBuffer - alts.foreach(_.isAccessibleFrom(pre, superAccess, whyNot)) + for alt <- alts do + if alt.is(Protected) then + val cls = alt.owner.enclosingSubClass + val owner = if cls.exists then cls else alt.owner + val location = if owner.is(Final) then owner.showLocated else owner.showLocated + " or one of its subclasses" + whyNot.append(i""" + | Protected $alt can only be accessed from $location.""") i"$whatCanNot be accessed as a member of $pre$where.$whyNot" def explain(using Context) = "" diff --git a/tests/neg/i18686.check b/tests/neg/i18686.check new file mode 100644 index 000000000000..cfecb5522248 --- /dev/null +++ b/tests/neg/i18686.check @@ -0,0 +1,13 @@ +-- [E173] Reference Error: tests/neg/i18686.scala:9:16 ----------------------------------------------------------------- +9 | println(Foo.Bar1) // error + | ^^^^^^^^ + | value Bar1 cannot be accessed as a member of Foo.type from object Main. +-- [E173] Reference Error: tests/neg/i18686.scala:10:16 ---------------------------------------------------------------- +10 | println(Foo.Bar2) // error + | ^^^^^^^^ + | value Bar2 cannot be accessed as a member of Foo.type from object Main. +-- [E173] Reference Error: tests/neg/i18686.scala:11:16 ---------------------------------------------------------------- +11 | println(Foo.Bar3) // error + | ^^^^^^^^ + | value Bar3 cannot be accessed as a member of Foo.type from object Main. + | Protected value Bar3 can only be accessed from object Foo. diff --git a/tests/neg/i18686.scala b/tests/neg/i18686.scala new file mode 100644 index 000000000000..d6a45b171394 --- /dev/null +++ b/tests/neg/i18686.scala @@ -0,0 +1,13 @@ +object Foo: + private val Bar1: Int = 3 + private[Foo] val Bar2: Int = 3 + protected val Bar3: Int = 3 +end Foo + +object Main: + def main(args: Array[String]): Unit = + println(Foo.Bar1) // error + println(Foo.Bar2) // error + println(Foo.Bar3) // error + end main +end Main