Skip to content

Commit fa08d00

Browse files
som-snyttTheElectronWillsmarter
authored
Allow override protected[C] in companion (#14105)
* 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. * RefChecks: add reference to related issue in comment Co-authored-by: Guillaume Martres <[email protected]> Co-authored-by: Guillaume Raffin <[email protected]> Co-authored-by: Guillaume Martres <[email protected]>
1 parent 29fc554 commit fa08d00

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
@@ -410,19 +410,21 @@ object RefChecks {
410410
overrideError("has weaker access privileges; it should not be private")
411411

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

507510
/* TODO enable; right now the annotation is scala-private, so cannot be seen
508511
* 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)