Skip to content

Commit 38b2eee

Browse files
Backport "Improve error message for inaccessible types" to LTS (#20710)
Backports #18406 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents f08cd3c + b79bccf commit 38b2eee

File tree

9 files changed

+74
-29
lines changed

9 files changed

+74
-29
lines changed

compiler/src/dotty/tools/dotc/core/NameOps.scala

+11-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ object NameOps {
109109
false
110110
}
111111

112-
/** is this the name of an object enclosing packagel-level definitions? */
112+
/** is this the name of an object enclosing package-level definitions? */
113113
def isPackageObjectName: Boolean = name match {
114114
case name: TermName => name == nme.PACKAGE || name.endsWith(str.TOPLEVEL_SUFFIX)
115115
case name: TypeName =>
@@ -119,6 +119,16 @@ object NameOps {
119119
}
120120
}
121121

122+
/** is this the name of an object enclosing top-level definitions? */
123+
def isTopLevelPackageObjectName: Boolean = name match {
124+
case name: TermName => name.endsWith(str.TOPLEVEL_SUFFIX)
125+
case name: TypeName =>
126+
name.toTermName match {
127+
case ModuleClassName(original) => original.isTopLevelPackageObjectName
128+
case _ => false
129+
}
130+
}
131+
122132
/** Convert this module name to corresponding module class name */
123133
def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName
124134

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

+8-4
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,10 @@ object SymDenotations {
672672
def isPackageObject(using Context): Boolean =
673673
name.isPackageObjectName && owner.is(Package) && this.is(Module)
674674

675+
/** Is this symbol a package object containing top-level definitions? */
676+
def isTopLevelDefinitionsObject(using Context): Boolean =
677+
name.isTopLevelPackageObjectName && owner.is(Package) && this.is(Module)
678+
675679
/** Is this symbol a toplevel definition in a package object? */
676680
def isWrappedToplevelDef(using Context): Boolean =
677681
!isConstructor && owner.isPackageObject
@@ -911,17 +915,17 @@ object SymDenotations {
911915
true
912916
else
913917
val encl = if ctx.owner.isConstructor then ctx.owner.enclosingClass.owner.enclosingClass else ctx.owner.enclosingClass
918+
val location = if owner.is(Final) then owner.showLocated else owner.showLocated + " or one of its subclasses"
914919
fail(i"""
915-
| Access to protected $this not permitted because enclosing ${encl.showLocated}
916-
| is not a subclass of ${owner.showLocated} where target is defined""")
920+
| Protected $this can only be accessed from $location.""")
917921
else if isType || pre.derivesFrom(cls) || isConstructor || owner.is(ModuleClass) then
918922
// allow accesses to types from arbitrary subclasses fixes #4737
919923
// don't perform this check for static members
920924
true
921925
else
926+
val location = if cls.is(Final) then cls.showLocated else cls.showLocated + " or one of its subclasses"
922927
fail(i"""
923-
| Access to protected ${symbol.show} not permitted because prefix type ${pre.widen.show}
924-
| does not conform to ${cls.showLocated} where the access takes place""")
928+
| Protected $this can only be accessed from $location.""")
925929
end isProtectedAccessOK
926930

927931
if pre eq NoPrefix then true

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -1099,13 +1099,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
10991099
fullNameString(sym)
11001100
else if (sym.is(ModuleClass) && sym.isPackageObject && sym.name.stripModuleClassSuffix == tpnme.PACKAGE)
11011101
nameString(sym.owner.name)
1102+
else if (sym.is(ModuleClass) && sym.isTopLevelDefinitionsObject)
1103+
nameString(sym.owner.name)
11021104
else if (sym.is(ModuleClass))
11031105
nameString(sym.name.stripModuleClassSuffix) + idString(sym)
11041106
else if (hasMeaninglessName(sym))
11051107
simpleNameString(sym.owner) + idString(sym)
11061108
else
11071109
nameString(sym)
1108-
(keywordText(kindString(sym)) ~~ {
1110+
1111+
if sym.is(ModuleClass) && sym.isTopLevelDefinitionsObject then
1112+
"the top-level definitions in package " + nameString(sym.owner.name)
1113+
else (keywordText(kindString(sym)) ~~ {
11091114
if (sym.isAnonymousClass)
11101115
toTextParents(sym.info.parents) ~~ "{...}"
11111116
else

compiler/src/dotty/tools/dotc/reporting/messages.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -2961,7 +2961,7 @@ extends ReferenceMsg(CannotBeAccessedID):
29612961
i"${if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated} cannot"
29622962
case _ =>
29632963
i"none of the overloaded alternatives named $name can"
2964-
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
2964+
val where = if (ctx.owner.exists) i" from ${ctx.owner.enclosingClass}" else ""
29652965
val whyNot = new StringBuffer
29662966
alts.foreach(_.isAccessibleFrom(pre, superAccess, whyNot))
29672967
i"$whatCanNot be accessed as a member of $pre$where.$whyNot"

tests/neg-macros/annot-result-owner.check

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
-- Error: tests/neg-macros/annot-result-owner/Test_2.scala:1:0 ---------------------------------------------------------
33
1 |@insertVal // error
44
|^^^^^^^^^^
5-
|macro annotation @insertVal added value definitionWithWrongOwner$macro$1 with an inconsistent owner. Expected it to be owned by package object Test_2$package but was owned by method foo.
5+
|macro annotation @insertVal added value definitionWithWrongOwner$macro$1 with an inconsistent owner. Expected it to be owned by the top-level definitions in package <empty> but was owned by method foo.
66
-- Error: tests/neg-macros/annot-result-owner/Test_2.scala:5:2 ---------------------------------------------------------
77
5 | @insertVal // error
88
| ^^^^^^^^^^

tests/neg/i12573.check

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
-- [E008] Not Found Error: tests/neg/i12573.scala:23:38 ----------------------------------------------------------------
22
23 |val w: Value[8] = DFBits(Value[8](8)).getDFType.width // error
33
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4-
| value getDFType is not a member of DFBits[(8 : Int)].
5-
| Extension methods were tried, but the search failed with:
4+
|value getDFType is not a member of DFBits[(8 : Int)].
5+
|Extension methods were tried, but the search failed with:
66
|
7-
| method getDFType cannot be accessed as a member of DFType.type from module class i12573$package$.
8-
| Access to protected method getDFType not permitted because enclosing package object i12573$package
9-
| is not a subclass of object DFType where target is defined
7+
| method getDFType cannot be accessed as a member of DFType.type from the top-level definitions in package <empty>.
8+
| Protected method getDFType can only be accessed from object DFType.

tests/neg/i7709.check

+8-16
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,39 @@
22
5 | class B extends X.Y // error
33
| ^^^
44
| class Y cannot be accessed as a member of X.type from class B.
5-
| Access to protected class Y not permitted because enclosing object A
6-
| is not a subclass of object X where target is defined
5+
| Protected class Y can only be accessed from object X.
76
-- [E173] Reference Error: tests/neg/i7709.scala:6:21 ------------------------------------------------------------------
87
6 | class B2 extends X.Y: // error
98
| ^^^
109
| class Y cannot be accessed as a member of X.type from class B2.
11-
| Access to protected class Y not permitted because enclosing object A
12-
| is not a subclass of object X where target is defined
10+
| Protected class Y can only be accessed from object X.
1311
-- [E173] Reference Error: tests/neg/i7709.scala:9:28 ------------------------------------------------------------------
1412
9 | class B4 extends B3(new X.Y) // error
1513
| ^^^
1614
| class Y cannot be accessed as a member of X.type from class B4.
17-
| Access to protected class Y not permitted because enclosing object A
18-
| is not a subclass of object X where target is defined
15+
| Protected class Y can only be accessed from object X.
1916
-- [E173] Reference Error: tests/neg/i7709.scala:11:34 -----------------------------------------------------------------
2017
11 | def this(n: Int) = this(new X.Y().toString) // error
2118
| ^^^
2219
| class Y cannot be accessed as a member of X.type from class B5.
23-
| Access to protected class Y not permitted because enclosing object A
24-
| is not a subclass of object X where target is defined
20+
| Protected class Y can only be accessed from object X.
2521
-- [E173] Reference Error: tests/neg/i7709.scala:13:20 -----------------------------------------------------------------
2622
13 | class B extends X.Y // error
2723
| ^^^
2824
| class Y cannot be accessed as a member of X.type from class B.
29-
| Access to protected class Y not permitted because enclosing trait T
30-
| is not a subclass of object X where target is defined
25+
| Protected class Y can only be accessed from object X.
3126
-- [E173] Reference Error: tests/neg/i7709.scala:18:18 -----------------------------------------------------------------
3227
18 | def y = new xx.Y // error
3328
| ^^^^
3429
| class Y cannot be accessed as a member of XX from class C.
35-
| Access to protected class Y not permitted because enclosing class C
36-
| is not a subclass of class XX where target is defined
30+
| Protected class Y can only be accessed from class XX or one of its subclasses.
3731
-- [E173] Reference Error: tests/neg/i7709.scala:23:20 -----------------------------------------------------------------
3832
23 | def y = new xx.Y // error
3933
| ^^^^
4034
| class Y cannot be accessed as a member of XX from class D.
41-
| Access to protected class Y not permitted because enclosing class D
42-
| is not a subclass of class XX where target is defined
35+
| Protected class Y can only be accessed from class XX or one of its subclasses.
4336
-- [E173] Reference Error: tests/neg/i7709.scala:31:20 -----------------------------------------------------------------
4437
31 | class Q extends X.Y // error
4538
| ^^^
4639
| class Y cannot be accessed as a member of p.X.type from class Q.
47-
| Access to protected class Y not permitted because enclosing package p
48-
| is not a subclass of object X in package p where target is defined
40+
| Protected class Y can only be accessed from object X in package p.

tests/neg/not-accessible.check

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- [E173] Reference Error: tests/neg/not-accessible.scala:8:23 ---------------------------------------------------------
2+
8 | def test(a: A) = a.x // error
3+
| ^^^
4+
| value x cannot be accessed as a member of (a : foo.A) from class B.
5+
-- [E173] Reference Error: tests/neg/not-accessible.scala:10:23 --------------------------------------------------------
6+
10 | def test(a: A) = a.x // error
7+
| ^^^
8+
| value x cannot be accessed as a member of (a : foo.A) from object B.
9+
-- [E173] Reference Error: tests/neg/not-accessible.scala:13:23 --------------------------------------------------------
10+
13 | def test(a: A) = a.x // error
11+
| ^^^
12+
| value x cannot be accessed as a member of (a : foo.A) from the top-level definitions in package bar.
13+
-- [E173] Reference Error: tests/neg/not-accessible.scala:5:21 ---------------------------------------------------------
14+
5 | def test(a: A) = a.x // error
15+
| ^^^
16+
| value x cannot be accessed as a member of (a : foo.A) from the top-level definitions in package foo.
17+
-- [E173] Reference Error: tests/neg/not-accessible.scala:15:23 --------------------------------------------------------
18+
15 |def test(a: foo.A) = a.x // error
19+
| ^^^
20+
| value x cannot be accessed as a member of (a : foo.A) from the top-level definitions in package <empty>.

tests/neg/not-accessible.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package foo:
2+
3+
class A(private[A] val x: Int)
4+
5+
def test(a: A) = a.x // error
6+
7+
class B:
8+
def test(a: A) = a.x // error
9+
object B:
10+
def test(a: A) = a.x // error
11+
12+
package bar:
13+
def test(a: A) = a.x // error
14+
15+
def test(a: foo.A) = a.x // error

0 commit comments

Comments
 (0)