Skip to content

Commit

Permalink
Refactor CannotBeAccessed/isAccessibleFrom
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Oct 13, 2023
1 parent 231ca72 commit 8aec15b
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 19 deletions.
21 changes: 4 additions & 17 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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", "")
),
Expand Down Expand Up @@ -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) = ""

Expand Down
13 changes: 13 additions & 0 deletions tests/neg/i18686.check
Original file line number Diff line number Diff line change
@@ -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.
13 changes: 13 additions & 0 deletions tests/neg/i18686.scala
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 8aec15b

Please sign in to comment.