diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 7cc602a20141..bdb01a079148 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -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 => @@ -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 diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index f4e8c08241e6..b18c6993303f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -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 @@ -911,17 +915,17 @@ object SymDenotations { 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""" - | Access to protected $this not permitted because enclosing ${encl.showLocated} - | is not a subclass of ${owner.showLocated} where target is defined""") + | Protected $this can only be accessed from $location.""") else if isType || pre.derivesFrom(cls) || isConstructor || owner.is(ModuleClass) then // 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""" - | Access to protected ${symbol.show} not permitted because prefix type ${pre.widen.show} - | does not conform to ${cls.showLocated} where the access takes place""") + | Protected $this can only be accessed from $location.""") end isProtectedAccessOK if pre eq NoPrefix then true diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 114037fd0bd0..7465b5c60aa3 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -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 + "the top-level definitions in package " + nameString(sym.owner.name) + else (keywordText(kindString(sym)) ~~ { if (sym.isAnonymousClass) toTextParents(sym.info.parents) ~~ "{...}" else diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 673e3dcc243d..6d115c0e18a9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -2984,7 +2984,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" diff --git a/tests/neg-macros/annot-result-owner.check b/tests/neg-macros/annot-result-owner.check index 5d67be058fdf..e2209998579c 100644 --- a/tests/neg-macros/annot-result-owner.check +++ b/tests/neg-macros/annot-result-owner.check @@ -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 the top-level definitions in package but was owned by method foo. -- Error: tests/neg-macros/annot-result-owner/Test_2.scala:5:2 --------------------------------------------------------- 5 | @insertVal // error | ^^^^^^^^^^ diff --git a/tests/neg/i12573.check b/tests/neg/i12573.check index d250f4beabbe..8c744fda685b 100644 --- a/tests/neg/i12573.check +++ b/tests/neg/i12573.check @@ -1,9 +1,8 @@ -- [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 \ No newline at end of file + | 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. diff --git a/tests/neg/i7709.check b/tests/neg/i7709.check index 180cf1939d16..b3b4e21b9db9 100644 --- a/tests/neg/i7709.check +++ b/tests/neg/i7709.check @@ -2,47 +2,39 @@ 5 | class B extends X.Y // error | ^^^ | class Y cannot be accessed as a member of X.type from class B. - | Access to protected class Y not permitted because enclosing object A - | is not a subclass of object X where target is defined + | 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. - | Access to protected class Y not permitted because enclosing object A - | is not a subclass of object X where target is defined + | 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. - | Access to protected class Y not permitted because enclosing object A - | is not a subclass of object X where target is defined + | 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. - | Access to protected class Y not permitted because enclosing object A - | is not a subclass of object X where target is defined + | 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. - | Access to protected class Y not permitted because enclosing trait T - | is not a subclass of object X where target is defined + | 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. - | Access to protected class Y not permitted because enclosing class C - | is not a subclass of class XX where target is defined + | 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. - | Access to protected class Y not permitted because enclosing class D - | is not a subclass of class XX where target is defined + | 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. - | Access to protected class Y not permitted because enclosing package p - | is not a subclass of object X in package p where target is defined + | 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 new file mode 100644 index 000000000000..00206d281016 --- /dev/null +++ b/tests/neg/not-accessible.check @@ -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 the top-level definitions 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 the top-level definitions 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 . diff --git a/tests/neg/not-accessible.scala b/tests/neg/not-accessible.scala new file mode 100644 index 000000000000..a0ff791e966f --- /dev/null +++ b/tests/neg/not-accessible.scala @@ -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