Skip to content

Commit

Permalink
Make toplevel protected qualified protected
Browse files Browse the repository at this point in the history
For private toplevel definitions we expand `private` to `private[p]`
where `p` is the enclosing package. This PR applies the same scheme to
protected toplevel definitions.

Rationale: scala#18057 fixed an issue where toplevel protected members were always accessible
because explicit package object prefixes were added after the accessibility check was done,
and would re-establish the previous members without doing an accessibility check. The fix was
done by adding package objects first, then doing he rest of the checks. But that also means
that protected toplevel objects now get checked as members of their synthetic package object
instead of as members of their package. To avoid that we make the package explicit as qalifier.

Thsi shouls also make specs2 compile again.
  • Loading branch information
odersky committed Jul 4, 2023
1 parent f6389d0 commit 8062bb5
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,7 @@ class CommunityBuildTestC:
@Test def sconfig = projects.sconfig.run()
@Test def shapeless = projects.shapeless.run()
@Test def sourcecode = projects.sourcecode.run()

// Disabled. Currently fails in FutureMatchers.scala. The call to
// `checkResultFailure` goes to a protected method which is not accessible.
// I tried to fix it, but get test failures.
// @Test def specs2 = projects.specs2.run()
@Test def specs2 = projects.specs2.run()

@Test def stdLib213 = projects.stdLib213.run()
@Test def ujson = projects.ujson.run()
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ object Flags {
val TermParamOrAccessor: FlagSet = Param | ParamAccessor
val PrivateParamAccessor: FlagSet = ParamAccessor | Private
val PrivateOrArtifact: FlagSet = Private | Artifact
val PrivateOrProtected: FlagSet = Private | Protected
val ClassTypeParam: FlagSet = Private | TypeParam
val Scala2Trait: FlagSet = Scala2x | Trait
val SyntheticArtifact: FlagSet = Synthetic | Artifact
Expand Down
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,10 @@ class Namer { typer: Typer =>
var flags1 = flags
var privateWithin = privateWithinClass(tree.mods)
val effectiveOwner = owner.skipWeakOwner
if (flags.is(Private) && effectiveOwner.is(Package)) {
// If effective owner is a package p, widen private to private[p]
flags1 = flags1 &~ PrivateLocal
if (flags.isOneOf(PrivateOrProtected) && !privateWithin.exists) && effectiveOwner.is(Package) then
// If effective owner is a package p, widen private to private[p] and protected to protected[p]
flags1 = flags1 &~ PrivateLocal // drop private but keep protected
privateWithin = effectiveOwner
}

val sym =
if (prev.exists) {
Expand Down
15 changes: 15 additions & 0 deletions tests/pos/i18124/definition.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// definition.scala
package oolong.bson:

trait BsonValue
protected def merge(
base: BsonValue,
patch: BsonValue,
arraySubvalues: Boolean = false
): BsonValue = ???

private def foo: Int = 1

package inner:
protected[bson] def bar = 2

8 changes: 8 additions & 0 deletions tests/pos/i18124/usage.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// usage.scala
package oolong.bson

extension (bv: BsonValue)
def :+(other: BsonValue): BsonValue = merge(other, bv, false)

val x = foo
val y = inner.bar

0 comments on commit 8062bb5

Please sign in to comment.