From 899dc4614bc7482a6d615ed9099cd7831d84ed5f Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 13 Oct 2023 15:34:18 +0200 Subject: [PATCH] Explain accessible scope of private members in error message Fixes #18686 --- .../dotty/tools/dotc/reporting/messages.scala | 18 ++++++++----- tests/neg/i12573.check | 2 +- tests/neg/i14432c.check | 1 + tests/neg/i18686.check | 25 ++++++++++++------- tests/neg/i18686.scala | 7 ++++-- tests/neg/i7709.check | 16 ++++++------ tests/neg/not-accessible.check | 5 ++++ 7 files changed, 48 insertions(+), 26 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index db7f00914ddc..14887606b54b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2987,12 +2987,18 @@ 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 = + if alt.is(Protected) && !owner.is(Final) then owner.showLocated + " or one of its subclasses" + else if alt.privateWithin.exists then alt.privateWithin.showLocated + else owner.showLocated + val accessMod = + if alt.is(Protected) then "protected" + else if alt.is(Private) then "private" + else i"private[${alt.privateWithin.name}]" + whyNot.append(i""" + | $accessMod $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/i12573.check b/tests/neg/i12573.check index 8c744fda685b..50fe36aa2aa9 100644 --- a/tests/neg/i12573.check +++ b/tests/neg/i12573.check @@ -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 . - | Protected method getDFType can only be accessed from object DFType. + | protected method getDFType can only be accessed from object DFType. diff --git a/tests/neg/i14432c.check b/tests/neg/i14432c.check index c0f69a1095d7..2710f0dfb3ed 100644 --- a/tests/neg/i14432c.check +++ b/tests/neg/i14432c.check @@ -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 | ^ diff --git a/tests/neg/i18686.check b/tests/neg/i18686.check index cfecb5522248..89187e2e6cd6 100644 --- a/tests/neg/i18686.check +++ b/tests/neg/i18686.check @@ -1,13 +1,20 @@ --- [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:11:16 ---------------------------------------------------------------- +11 | 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:12:16 ---------------------------------------------------------------- +12 | 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:13:16 ---------------------------------------------------------------- +13 | 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:14:20 ---------------------------------------------------------------- +14 | println(Foo.Baz.Bar4) // error + | ^^^^^^^^^^^^ + | value Bar4 cannot be accessed as a member of Foo.Baz.type from object Main. + | private[Foo] value Bar4 can only be accessed from object Foo. diff --git a/tests/neg/i18686.scala b/tests/neg/i18686.scala index d6a45b171394..9bab33e87c27 100644 --- a/tests/neg/i18686.scala +++ b/tests/neg/i18686.scala @@ -1,7 +1,9 @@ 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 + object Baz: + private[Foo] val Bar4: Int = 4 end Foo object Main: @@ -9,5 +11,6 @@ object Main: println(Foo.Bar1) // error println(Foo.Bar2) // error println(Foo.Bar3) // error + println(Foo.Baz.Bar4) // error end main end Main diff --git a/tests/neg/i7709.check b/tests/neg/i7709.check index b3b4e21b9db9..14d2dbaf4cde 100644 --- a/tests/neg/i7709.check +++ b/tests/neg/i7709.check @@ -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. diff --git a/tests/neg/not-accessible.check b/tests/neg/not-accessible.check index 00206d281016..54585460a1d8 100644 --- a/tests/neg/not-accessible.check +++ b/tests/neg/not-accessible.check @@ -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 . + | private[A] value x can only be accessed from class A in package foo.