Skip to content

Commit 5979401

Browse files
committed
Allow override protected[C] in companion
When extending C in its companion, allow override protected[C] where C denotes the enclosing companion module of C. Lookup of local companion is broken under `-from-tasty`, so this accommodation is disallowed for local companions.
1 parent 8bb2453 commit 5979401

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -409,19 +409,21 @@ object RefChecks {
409409
overrideError("has weaker access privileges; it should not be private")
410410

411411
// todo: align accessibility implication checking with isAccessible in Contexts
412-
val ob = other.accessBoundary(member.owner)
413-
val mb = member.accessBoundary(member.owner)
414412
def isOverrideAccessOK =
415-
(member.flags & AccessFlags).isEmpty
416-
&& !member.privateWithin.exists // member is public, or
417-
|| (!other.is(Protected) || member.is(Protected))
418-
// if o is protected, so is m, and
419-
&& (ob.isContainedIn(mb) || other.isAllOf(JavaProtected))
420-
// m relaxes o's access boundary,
421-
// or o is Java defined and protected (see #3946)
413+
val memberIsPublic = (member.flags & AccessFlags).isEmpty && !member.privateWithin.exists
414+
def protectedOK = !other.is(Protected) || member.is(Protected) // if o is protected, so is m
415+
def accessBoundaryOK =
416+
val ob = other.accessBoundary(member.owner)
417+
val mb = member.accessBoundary(member.owner)
418+
// restriction isLocalToBlock because companionModule fails under -from-tasty
419+
def companionBoundaryOK = ob.isClass && !ob.isLocalToBlock && mb.is(Module) && (ob.companionModule eq mb.companionModule)
420+
ob.isContainedIn(mb) || companionBoundaryOK // m relaxes o's access boundary,
421+
def otherIsJavaProtected = other.isAllOf(JavaProtected) // or o is Java defined and protected (see #3946)
422+
memberIsPublic || protectedOK && (accessBoundaryOK || otherIsJavaProtected)
423+
end isOverrideAccessOK
422424
if !member.hasTargetName(other.targetName) then
423425
overrideTargetNameError()
424-
else if (!isOverrideAccessOK)
426+
else if !isOverrideAccessOK then
425427
overrideAccessError()
426428
else if (other.isClass)
427429
// direct overrides were already checked on completion (see Checking.chckWellFormed)
@@ -502,6 +504,7 @@ object RefChecks {
502504
else
503505
checkOverrideDeprecated()
504506
}
507+
end checkOverride
505508

506509
/* TODO enable; right now the annotation is scala-private, so cannot be seen
507510
* here.

tests/neg/t12494.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
object X {
3+
// restriction in Scala 2 for local companions
4+
// restriction in Scala 3 under -from-tasty
5+
def m: Int = {
6+
trait C {
7+
protected[C] def f: Int
8+
}
9+
object C {
10+
class C2 extends C {
11+
protected[C] def f: Int = 42 // error // ok except for restrictions noted
12+
def test = f
13+
}
14+
}
15+
C.C2().test
16+
}
17+
}

tests/pos/t12494.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
trait Base {
3+
protected[Base] def f: Int
4+
}
5+
object Base {
6+
class Child extends Base {
7+
protected[Base] def f: Int = 42 // ok
8+
def test = f
9+
}
10+
}

0 commit comments

Comments
 (0)