Skip to content

Commit 991fceb

Browse files
committed
Better fix that handles the missing corner case
1 parent 52d2e02 commit 991fceb

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,14 @@ object Contexts {
441441
.setScope(this.scope)
442442
}
443443

444+
/** Is this a super call context?
445+
* This is the case if we are in a primary constructor and
446+
* the outer context has as owner the owner of the enclosing class.
447+
* The enclosing class is `owner.owner`, hence `outer.owner == owner.owner.owner`.
448+
*/
449+
def isSuperCallContext: Boolean =
450+
owner.isPrimaryConstructor && outer.owner == owner.owner.owner
451+
444452
/** The super- or this-call context with given owner and locals. */
445453
private def superOrThisCallContext(owner: Symbol, locals: Scope): FreshContext = {
446454
val classCtx = outersIterator.dropWhile(!_.isClassDefContext).next()

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -942,19 +942,16 @@ object SymDenotations {
942942
}
943943

944944
/** Is protected access to target symbol permitted? */
945-
def isProtectedAccessOK: Boolean =
945+
def isProtectedAccessOK: Boolean = {
946946
val cls = owner.enclosingSubClass
947947
if !cls.exists then
948948
pre.termSymbol.isPackageObject && accessWithin(pre.termSymbol.owner)
949-
else {
950-
val isConstructorAccessOK =
951-
isConstructor && ctx.owner.isPrimaryConstructor
952-
&& cls.info.parents.exists(_.classSymbol == owner)
949+
else
950+
val isConstructorAccessOK = isConstructor && ctx.isSuperCallContext
953951
// allow accesses to types from arbitrary subclasses fixes #4737
954952
// don't perform this check for static members
955953
isType || pre.derivesFrom(cls) || isConstructorAccessOK || owner.is(ModuleClass)
956-
}
957-
end isProtectedAccessOK
954+
}
958955

959956
if pre eq NoPrefix then true
960957
else if isAbsent() then false

tests/neg/i25442.check

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
-- [E173] Reference Error: tests/neg/i25442/protected-constructors.scala:7:22 ------------------------------------------
2+
7 |class C extends B(new A(1)) // error
3+
| ^
4+
| constructor A cannot be accessed as a member of protectedCtors.A from class C.
5+
| protected constructor A can only be accessed from class C in package protectedCtors or one of its subclasses.
6+
-- [E173] Reference Error: tests/neg/i25442/protected-constructors.scala:10:22 -----------------------------------------
7+
10 |class E extends D(new D(1)) // error
8+
| ^
9+
| constructor D cannot be accessed as a member of protectedCtors.D from class E.
10+
| protected constructor D can only be accessed from class E in package protectedCtors or one of its subclasses.
11+
-- Error: tests/neg/i25442/protected-constructors.scala:18:24 ----------------------------------------------------------
12+
18 |class J extends G(new F(1)) // error: protected primary in super args
13+
| ^
14+
| too many arguments for constructor F in class F: (): protectedCtors.F
15+
-- [E173] Reference Error: tests/neg/i25442/protected-constructors.scala:22:14 -----------------------------------------
16+
22 | val k = new A(1) // error
17+
| ^
18+
| constructor A cannot be accessed as a member of protectedCtors.A from class K.
19+
| protected constructor A can only be accessed from class K in package protectedCtors or one of its subclasses.
20+
-- [E173] Reference Error: tests/neg/i25442/protected-constructors.scala:27:28 -----------------------------------------
21+
27 |class N extends M(() => new A(2)) // error
22+
| ^
23+
| constructor A cannot be accessed as a member of protectedCtors.A from class N.
24+
| protected constructor A can only be accessed from class N in package protectedCtors or one of its subclasses.
25+
-- [E173] Reference Error: tests/neg/i25442/test.scala:7:15 ------------------------------------------------------------
26+
7 | def t2 = new I(42) // error
27+
| ^
28+
| constructor I cannot be accessed as a member of I from class M.
29+
| protected constructor I can only be accessed from class M or one of its subclasses.
30+
-- [E173] Reference Error: tests/neg/i25442/test.scala:8:35 ------------------------------------------------------------
31+
8 | def this(x: Int) = { this(); new I(x) } // error
32+
| ^
33+
| constructor I cannot be accessed as a member of I from class M.
34+
| protected constructor I can only be accessed from class M or one of its subclasses.

tests/neg/i25442/protected-constructors.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ class A protected (x: Int)
66
class B(a: A) extends A(a.hashCode)
77
class C extends B(new A(1)) // error
88

9+
class D protected (x: Any)
10+
class E extends D(new D(1)) // error
11+
912
// Mixed visibility constructors
1013
class F protected (x: Int) {
1114
def this() = this(0) // public secondary

0 commit comments

Comments
 (0)