diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 97f61c6664bd..c2e81b18c348 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1088,8 +1088,11 @@ class Namer { typer: Typer => // allow such type aliases. If we forbid them at some point (requiring the referred type to be // fully applied), we'd have to change the scheme here as well. else { + def refersToPrivate(tp: Type): Boolean = tp match + case tp: TermRef => tp.termSymbol.is(Private) || refersToPrivate(tp.prefix) + case _ => false val (maybeStable, mbrInfo) = - if (sym.isStableMember && sym.isPublic) + if sym.isStableMember && sym.isPublic && !refersToPrivate(path.tpe) then (StableRealizable, ExprType(path.tpe.select(sym))) else (EmptyFlags, mbr.info.ensureMethodic) diff --git a/docs/docs/reference/other-new-features/export.md b/docs/docs/reference/other-new-features/export.md index 11ed1c55c229..e84725ea91ef 100644 --- a/docs/docs/reference/other-new-features/export.md +++ b/docs/docs/reference/other-new-features/export.md @@ -77,7 +77,9 @@ Export aliases are always `final`. Aliases of given instances are again defined not marked `override`. - However, export aliases can implement deferred members of base classes. -Export aliases for public value definitions are marked by the compiler as "stable" and their result types are the singleton types of the aliased definitions. This means that they can be used as parts of stable identifier paths, even though they are technically methods. For instance, the following is OK: +Export aliases for public value definitions that are accessed without +referring to private values in the qualifier path +are marked by the compiler as "stable" and their result types are the singleton types of the aliased definitions. This means that they can be used as parts of stable identifier paths, even though they are technically methods. For instance, the following is OK: ```scala class C { type T } object O { val c: C = ... } diff --git a/tests/neg/exports.check b/tests/neg/exports.check index f691b66444f6..e59b11771d2b 100644 --- a/tests/neg/exports.check +++ b/tests/neg/exports.check @@ -11,7 +11,7 @@ 25 | export printUnit.bitmap // error: no eligible member | ^ | non-private method bitmap in class Copier refers to private value printUnit - | in its type signature => Copier.this.printUnit.bitmap.type + | in its type signature => Copier.this.printUnit.bitmap$ -- [E120] Duplicate Symbol Error: tests/neg/exports.scala:23:33 -------------------------------------------------------- 23 | export printUnit.{stat => _, _} // error: double definition | ^ diff --git a/tests/run/exports.scala b/tests/run/exports.scala index 6fb5de88322b..c796f330b9c7 100644 --- a/tests/run/exports.scala +++ b/tests/run/exports.scala @@ -39,9 +39,17 @@ object Test extends App { 1.scanned } test() + + val _: Int = B.x } final class Foo { lazy val foo : Foo = new Foo export foo._ // nothing is exported -} \ No newline at end of file +} + +class A: + val x: Int = 1 +class B(a: A): + export a.x +object B extends B(A()) \ No newline at end of file