Skip to content

Improve error message for inaccessible types #18406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion compiler/src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ object NameOps {
false
}

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

/** is this the name of an object enclosing top-level definitions? */
def isTopLevelPackageObjectName: Boolean = name match {
case name: TermName => name.endsWith(str.TOPLEVEL_SUFFIX)
case name: TypeName =>
name.toTermName match {
case ModuleClassName(original) => original.isTopLevelPackageObjectName
case _ => false
}
}

/** Convert this module name to corresponding module class name */
def moduleClassName: TypeName = name.derived(ModuleClassName).toTypeName

Expand Down
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,10 @@ object SymDenotations {
def isPackageObject(using Context): Boolean =
name.isPackageObjectName && owner.is(Package) && this.is(Module)

/** Is this symbol a package object containing top-level definitions? */
def isTopLevelDefinitionsObject(using Context): Boolean =
name.isTopLevelPackageObjectName && owner.is(Package) && this.is(Module)

/** Is this symbol a toplevel definition in a package object? */
def isWrappedToplevelDef(using Context): Boolean =
!isConstructor && owner.isPackageObject
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1113,13 +1113,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
fullNameString(sym)
else if (sym.is(ModuleClass) && sym.isPackageObject && sym.name.stripModuleClassSuffix == tpnme.PACKAGE)
nameString(sym.owner.name)
else if (sym.is(ModuleClass) && sym.isTopLevelDefinitionsObject)
nameString(sym.owner.name)
else if (sym.is(ModuleClass))
nameString(sym.name.stripModuleClassSuffix) + idString(sym)
else if (hasMeaninglessName(sym))
simpleNameString(sym.owner) + idString(sym)
else
nameString(sym)
(keywordText(kindString(sym)) ~~ {

if sym.is(ModuleClass) && sym.isTopLevelDefinitionsObject then
"top-level definition in package " + nameString(sym.owner.name)
else (keywordText(kindString(sym)) ~~ {
if (sym.isAnonymousClass)
toTextParents(sym.info.parents) ~~ "{...}"
else
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2976,7 +2976,7 @@ extends ReferenceMsg(CannotBeAccessedID):
i"${if (sym.owner == pre.typeSymbol) sym.show else sym.showLocated} cannot"
case _ =>
i"none of the overloaded alternatives named $name can"
val where = if (ctx.owner.exists) s" from ${ctx.owner.enclosingClass}" else ""
val where = if (ctx.owner.exists) i" from ${ctx.owner.enclosingClass}" else ""
val whyNot = new StringBuffer
alts.foreach(_.isAccessibleFrom(pre, superAccess, whyNot))
i"$whatCanNot be accessed as a member of $pre$where.$whyNot"
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-macros/annot-result-owner.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
-- Error: tests/neg-macros/annot-result-owner/Test_2.scala:1:0 ---------------------------------------------------------
1 |@insertVal // error
|^^^^^^^^^^
|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.
|macro annotation @insertVal added value definitionWithWrongOwner$macro$1 with an inconsistent owner. Expected it to be owned by top-level definition in package <empty> but was owned by method foo.
-- Error: tests/neg-macros/annot-result-owner/Test_2.scala:5:2 ---------------------------------------------------------
5 | @insertVal // error
| ^^^^^^^^^^
Expand Down
10 changes: 5 additions & 5 deletions tests/neg/i12573.check
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
-- [E008] Not Found Error: tests/neg/i12573.scala:23:38 ----------------------------------------------------------------
23 |val w: Value[8] = DFBits(Value[8](8)).getDFType.width // error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| value getDFType is not a member of DFBits[(8 : Int)].
| Extension methods were tried, but the search failed with:
|value getDFType is not a member of DFBits[(8 : Int)].
|Extension methods were tried, but the search failed with:
|
| method getDFType cannot be accessed as a member of DFType.type from module class i12573$package$.
| Access to protected method getDFType not permitted because enclosing package object i12573$package
| is not a subclass of object DFType where target is defined
| method getDFType cannot be accessed as a member of DFType.type from top-level definition in package <empty>.
| Access to protected method getDFType not permitted because enclosing top-level definition in package <empty>
| is not a subclass of object DFType where target is defined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be "from the top-level definitions" since we're talking about the object here, but also "top-level definitions is not a subclass of ..." isn't really meaningful, the explanation could be simplified to just say "Protected method getDFType can only be accessed from object DFType or one of its subclasses" (and the "or one of its subclasses" part could be dropped for objects too)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

20 changes: 20 additions & 0 deletions tests/neg/not-accessible.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- [E173] Reference Error: tests/neg/not-accessible.scala:8:23 ---------------------------------------------------------
8 | def test(a: A) = a.x // error
| ^^^
| value x cannot be accessed as a member of (a : foo.A) from class B.
-- [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.
-- [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 top-level definition in package bar.
-- [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 top-level definition 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 top-level definition in package <empty>.
15 changes: 15 additions & 0 deletions tests/neg/not-accessible.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package foo:

class A(private[A] val x: Int)

def test(a: A) = a.x // error

class B:
def test(a: A) = a.x // error
object B:
def test(a: A) = a.x // error

package bar:
def test(a: A) = a.x // error

def test(a: foo.A) = a.x // error