Skip to content

Commit

Permalink
Explain accessible scope of private members in error message
Browse files Browse the repository at this point in the history
Fixes #18686
  • Loading branch information
nicolasstucki committed Oct 17, 2023
1 parent 8aec15b commit 6c1fce0
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 27 deletions.
2 changes: 1 addition & 1 deletion community-build/community-projects/stdLib213
Submodule stdLib213 updated 489 files
23 changes: 17 additions & 6 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2987,12 +2987,23 @@ extends ReferenceMsg(CannotBeAccessedID):
val where = if (ctx.owner.exists) i" from ${ctx.owner.enclosingClass}" else ""
val whyNot = new StringBuffer
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.""")
val cls = alt.owner.enclosingSubClass
val owner = if cls.exists then cls else alt.owner
val location: String =
if alt.is(Protected) then
if alt.privateWithin.exists && alt.privateWithin != owner then
if owner.is(Final) then alt.privateWithin.showLocated
else alt.privateWithin.showLocated + ", or " + owner.showLocated + " or one of its subclasses"
else
if owner.is(Final) then owner.showLocated
else owner.showLocated + " or one of its subclasses"
else
alt.privateWithin.orElse(owner).showLocated
val accessMod = if alt.is(Protected) then "protected" else "private"
val within = if alt.privateWithin.exists then i"[${alt.privateWithin.name}]"
else ""
whyNot.append(i"""
| $accessMod$within $alt can only be accessed from $location.""")
i"$whatCanNot be accessed as a member of $pre$where.$whyNot"
def explain(using Context) = ""

Expand Down
1 change: 1 addition & 0 deletions compiler/test-resources/repl/i1370
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ scala> object Lives { class Private { def foo1: Any = new Private.C1; def foo2:
1 | object Lives { class Private { def foo1: Any = new Private.C1; def foo2: Any = new Private.C2 }; object Private { class C1 private {}; private class C2 {} } }
| ^^^^^^^^^^
|constructor C1 cannot be accessed as a member of Lives.Private.C1 from class Private.
| private constructor C1 can only be accessed from class C1 in object Private.
1 error found
2 changes: 1 addition & 1 deletion tests/neg/i12573.check
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
|Extension methods were tried, but the search failed with:
|
| method getDFType cannot be accessed as a member of DFType.type from the top-level definitions in package <empty>.
| Protected method getDFType can only be accessed from object DFType.
| protected method getDFType can only be accessed from object DFType.
1 change: 1 addition & 0 deletions tests/neg/i14432c.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
12 |class Bar extends example.Foo(23) { // error: cant access private[example] ctor
| ^^^^^^^^^^^
| constructor Foo cannot be accessed as a member of example.Foo from class Bar.
| private[example] constructor Foo can only be accessed from package example.
-- [E172] Type Error: tests/neg/i14432c.scala:16:43 --------------------------------------------------------------------
16 | val mFoo = summon[Mirror.Of[example.Foo]] // error: no mirror
| ^
Expand Down
35 changes: 26 additions & 9 deletions tests/neg/i18686.check
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
-- [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
-- [E173] Reference Error: tests/neg/i18686.scala:13:16 ----------------------------------------------------------------
13 | println(Foo.Bar1) // error
| ^^^^^^^^
| value Bar1 cannot be accessed as a member of Foo.type from object Main.
| private value Bar1 can only be accessed from object Foo.
-- [E173] Reference Error: tests/neg/i18686.scala:14:16 ----------------------------------------------------------------
14 | 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
| private[Foo] value Bar2 can only be accessed from object Foo.
-- [E173] Reference Error: tests/neg/i18686.scala:15:16 ----------------------------------------------------------------
15 | 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.
| protected value Bar3 can only be accessed from object Foo.
-- [E173] Reference Error: tests/neg/i18686.scala:16:16 ----------------------------------------------------------------
16 | println(Foo.Bar4) // error
| ^^^^^^^^
| value Bar4 cannot be accessed as a member of Foo.type from object Main.
| protected[Foo] value Bar4 can only be accessed from object Foo.
-- [E173] Reference Error: tests/neg/i18686.scala:17:20 ----------------------------------------------------------------
17 | println(Foo.Baz.Bar5) // error
| ^^^^^^^^^^^^
| value Bar5 cannot be accessed as a member of Foo.Baz.type from object Main.
| private[Foo] value Bar5 can only be accessed from object Foo.
-- [E173] Reference Error: tests/neg/i18686.scala:18:20 ----------------------------------------------------------------
18 | println(Foo.Baz.Bar6) // error
| ^^^^^^^^^^^^
| value Bar6 cannot be accessed as a member of Foo.Baz.type from object Main.
| protected[Foo] value Bar6 can only be accessed from object Foo.
11 changes: 9 additions & 2 deletions tests/neg/i18686.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
object Foo:
private val Bar1: Int = 3
private[Foo] val Bar2: Int = 3
private val Bar1: Int = 1
private[Foo] val Bar2: Int = 2
protected val Bar3: Int = 3
protected[Foo] val Bar4: Int = 5
object Baz:
private[Foo] val Bar5: Int = 5
protected[Foo] val Bar6: Int = 6
end Foo

object Main:
def main(args: Array[String]): Unit =
println(Foo.Bar1) // error
println(Foo.Bar2) // error
println(Foo.Bar3) // error
println(Foo.Bar4) // error
println(Foo.Baz.Bar5) // error
println(Foo.Baz.Bar6) // error
end main
end Main
28 changes: 28 additions & 0 deletions tests/neg/i18686b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- [E173] Reference Error: tests/neg/i18686b.scala:15:16 ---------------------------------------------------------------
15 | println(foo.Bar1) // error
| ^^^^^^^^
| value Bar1 cannot be accessed as a member of Foo from object Main.
| private value Bar1 can only be accessed from class Foo.
-- [E173] Reference Error: tests/neg/i18686b.scala:16:16 ---------------------------------------------------------------
16 | println(foo.Bar2) // error
| ^^^^^^^^
| value Bar2 cannot be accessed as a member of Foo from object Main.
| private[Foo] value Bar2 can only be accessed from class Foo.
-- [E173] Reference Error: tests/neg/i18686b.scala:17:16 ---------------------------------------------------------------
17 | println(foo.Bar3) // error
| ^^^^^^^^
| value Bar3 cannot be accessed as a member of Foo from object Main.
| protected value Bar3 can only be accessed from class Foo or one of its subclasses.
-- [E173] Reference Error: tests/neg/i18686b.scala:18:16 ---------------------------------------------------------------
18 | println(foo.Bar4) // error
| ^^^^^^^^
| value Bar4 cannot be accessed as a member of Foo from object Main.
| protected[Foo] value Bar4 can only be accessed from class Foo or one of its subclasses.
-- [E008] Not Found Error: tests/neg/i18686b.scala:19:20 ---------------------------------------------------------------
19 | println(foo.Baz.Bar5) // error
| ^^^^^^^^^^^^
| value Bar5 is not a member of object Foo#Baz
-- [E008] Not Found Error: tests/neg/i18686b.scala:20:20 ---------------------------------------------------------------
20 | println(foo.Baz.Bar6) // error
| ^^^^^^^^^^^^
| value Bar6 is not a member of object Foo#Baz
22 changes: 22 additions & 0 deletions tests/neg/i18686b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Foo:
private val Bar1: Int = 1
private[Foo] val Bar2: Int = 2
protected val Bar3: Int = 3
protected[Foo] val Bar4: Int = 5
class Baz:
private[Foo] val Bar5: Int = 5
protected[Foo] val Bar6: Int = 6
end Foo

def foo = new Foo

object Main:
def main(args: Array[String]): Unit =
println(foo.Bar1) // error
println(foo.Bar2) // error
println(foo.Bar3) // error
println(foo.Bar4) // error
println(foo.Baz.Bar5) // error
println(foo.Baz.Bar6) // error
end main
end Main
8 changes: 8 additions & 0 deletions tests/neg/i18686c.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- [E173] Reference Error: tests/neg/i18686c.scala:8:6 -----------------------------------------------------------------
8 | foo.foo // error
| ^^^^^^^
|method foo cannot be accessed as a member of (foo² : Bar.Foo) from the top-level definitions in package <empty>.
| protected[Bar] method foo can only be accessed from object Bar, or class Foo in object Bar or one of its subclasses.
|
|where: foo is a method in class Foo
| foo² is a parameter in method test
8 changes: 8 additions & 0 deletions tests/neg/i18686c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
object Bar:
class Foo:
protected[Bar] def foo = 23
class Qux extends Foo:
val qux = foo

def test(foo: Bar.Foo) =
foo.foo // error
16 changes: 8 additions & 8 deletions tests/neg/i7709.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,39 @@
5 | class B extends X.Y // error
| ^^^
| class Y cannot be accessed as a member of X.type from class B.
| Protected class Y can only be accessed from object X.
| protected class Y can only be accessed from object X.
-- [E173] Reference Error: tests/neg/i7709.scala:6:21 ------------------------------------------------------------------
6 | class B2 extends X.Y: // error
| ^^^
| class Y cannot be accessed as a member of X.type from class B2.
| Protected class Y can only be accessed from object X.
| protected class Y can only be accessed from object X.
-- [E173] Reference Error: tests/neg/i7709.scala:9:28 ------------------------------------------------------------------
9 | class B4 extends B3(new X.Y) // error
| ^^^
| class Y cannot be accessed as a member of X.type from class B4.
| Protected class Y can only be accessed from object X.
| protected class Y can only be accessed from object X.
-- [E173] Reference Error: tests/neg/i7709.scala:11:34 -----------------------------------------------------------------
11 | def this(n: Int) = this(new X.Y().toString) // error
| ^^^
| class Y cannot be accessed as a member of X.type from class B5.
| Protected class Y can only be accessed from object X.
| protected class Y can only be accessed from object X.
-- [E173] Reference Error: tests/neg/i7709.scala:13:20 -----------------------------------------------------------------
13 | class B extends X.Y // error
| ^^^
| class Y cannot be accessed as a member of X.type from class B.
| Protected class Y can only be accessed from object X.
| protected class Y can only be accessed from object X.
-- [E173] Reference Error: tests/neg/i7709.scala:18:18 -----------------------------------------------------------------
18 | def y = new xx.Y // error
| ^^^^
| class Y cannot be accessed as a member of XX from class C.
| Protected class Y can only be accessed from class XX or one of its subclasses.
| protected class Y can only be accessed from class XX or one of its subclasses.
-- [E173] Reference Error: tests/neg/i7709.scala:23:20 -----------------------------------------------------------------
23 | def y = new xx.Y // error
| ^^^^
| class Y cannot be accessed as a member of XX from class D.
| Protected class Y can only be accessed from class XX or one of its subclasses.
| protected class Y can only be accessed from class XX or one of its subclasses.
-- [E173] Reference Error: tests/neg/i7709.scala:31:20 -----------------------------------------------------------------
31 | class Q extends X.Y // error
| ^^^
| class Y cannot be accessed as a member of p.X.type from class Q.
| Protected class Y can only be accessed from object X in package p.
| protected class Y can only be accessed from object X in package p.
5 changes: 5 additions & 0 deletions tests/neg/not-accessible.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@
8 | def test(a: A) = a.x // error
| ^^^
| value x cannot be accessed as a member of (a : foo.A) from class B.
| private[A] value x can only be accessed from class A in package foo.
-- [E173] Reference Error: tests/neg/not-accessible.scala:10:23 --------------------------------------------------------
10 | def test(a: A) = a.x // error
| ^^^
| value x cannot be accessed as a member of (a : foo.A) from object B.
| private[A] value x can only be accessed from class A in package foo.
-- [E173] Reference Error: tests/neg/not-accessible.scala:13:23 --------------------------------------------------------
13 | def test(a: A) = a.x // error
| ^^^
| value x cannot be accessed as a member of (a : foo.A) from the top-level definitions in package bar.
| private[A] value x can only be accessed from class A in package foo.
-- [E173] Reference Error: tests/neg/not-accessible.scala:5:21 ---------------------------------------------------------
5 | def test(a: A) = a.x // error
| ^^^
| value x cannot be accessed as a member of (a : foo.A) from the top-level definitions in package foo.
| private[A] value x can only be accessed from class A in package foo.
-- [E173] Reference Error: tests/neg/not-accessible.scala:15:23 --------------------------------------------------------
15 |def test(a: foo.A) = a.x // error
| ^^^
| value x cannot be accessed as a member of (a : foo.A) from the top-level definitions in package <empty>.
| private[A] value x can only be accessed from class A in package foo.

0 comments on commit 6c1fce0

Please sign in to comment.