Skip to content

Commit 2704de0

Browse files
authored
Merge pull request #251 from scala/backport-lts-3.3-22563
Backport "Constructor proxy is restricted if class is protected" to 3.3 LTS
2 parents 694f369 + ca09ca7 commit 2704de0

File tree

7 files changed

+77
-9
lines changed

7 files changed

+77
-9
lines changed

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,10 @@ object NamerOps:
110110
*/
111111
def addConstructorApplies(scope: MutableScope, cls: ClassSymbol, modcls: ClassSymbol)(using Context): scope.type =
112112
def proxy(constr: Symbol): Symbol =
113+
var flags = ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags)
114+
if cls.is(Protected) && !modcls.is(Protected) then flags |= Protected
113115
newSymbol(
114-
modcls, nme.apply, ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags),
116+
modcls, nme.apply, flags,
115117
ApplyProxyCompleter(constr), coord = constr.coord)
116118
for dcl <- cls.info.decls do
117119
if dcl.isConstructor then scope.enter(proxy(dcl))
@@ -133,9 +135,11 @@ object NamerOps:
133135

134136
/** A new symbol that is the constructor companion for class `cls` */
135137
def classConstructorCompanion(cls: ClassSymbol)(using Context): TermSymbol =
138+
var flags = ConstructorCompanionFlags
139+
if cls.is(Protected) then flags |= Protected
136140
val companion = newModuleSymbol(
137141
cls.owner, cls.name.toTermName,
138-
ConstructorCompanionFlags, ConstructorCompanionFlags,
142+
flags, flags,
139143
constructorCompanionCompleter(cls),
140144
coord = cls.coord,
141145
assocFile = cls.assocFile)

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,9 +1111,8 @@ trait Applications extends Compatibility {
11111111
//
11121112
// summonFrom {
11131113
// case given A[t] =>
1114-
// summonFrom
1114+
// summonFrom:
11151115
// case given `t` => ...
1116-
// }
11171116
// }
11181117
//
11191118
// the second `summonFrom` should expand only once the first `summonFrom` is

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3821,9 +3821,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
38213821
readapt(tree.appliedToNone) // insert () to primary constructors
38223822
else
38233823
errorTree(tree, em"Missing arguments for $methodStr")
3824-
case _ => tryInsertApplyOrImplicit(tree, pt, locked) {
3825-
errorTree(tree, MethodDoesNotTakeParameters(tree))
3826-
}
3824+
case _ =>
3825+
tryInsertApplyOrImplicit(tree, pt, locked):
3826+
errorTree(tree, MethodDoesNotTakeParameters(tree))
38273827
}
38283828

38293829
def adaptNoArgsImplicitMethod(wtp: MethodType): Tree = {

docs/_docs/reference/other-new-features/creator-applications.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ The precise rules are as follows:
3939
- the class has a companion object (which might have been generated in step 1), and
4040
- that companion object does not already define a member named `apply`.
4141

42-
Each generated `apply` method forwards to one constructor of the class. It has the
43-
same type and value parameters as the constructor.
42+
Each generated `apply` method forwards to one constructor of the class.
43+
It has the same type and value parameters as the constructor,
44+
as well as the same access restriction as the class.
45+
If the class is `protected`, then either the companion object must be `protected`
46+
or the `apply` method will be made `protected`.
4447

4548
Constructor proxy companions cannot be used as values by themselves. A proxy companion object must
4649
be selected with `apply` (or be applied to arguments, in which case the `apply` is implicitly

tests/neg/i22560.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
class A:
3+
protected class B
4+
5+
// This fails to compile, as expected
6+
val x = A().B() // error
7+
8+
object C:
9+
protected val p = "protected"
10+
protected def getString() = "Hello!"
11+
protected class D:
12+
def d = D() // ok
13+
14+
// This fails to compile
15+
// val y = C.p
16+
17+
// And this also fails to compile
18+
// val z = C.getString()
19+
20+
// However, this compiles just fine.
21+
val alpha = C.D() // error
22+
val beta = new C.D() // error

tests/neg/i22560b.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
class Enumeration:
3+
protected class Val(i: Int):
4+
def this() = this(42)
5+
object Val
6+
7+
class Test extends Enumeration:
8+
val Hearts = Val(27) // error
9+
val Diamonds = Val() // error
10+
11+
package p:
12+
private[p] class C(i: Int) // ctor proxy gets privateWithin of class
13+
private[p] class D(i: Int)
14+
object D
15+
16+
package q:
17+
def f() = p.C(42) // error
18+
def g() = p.D(42) // error

tests/pos/i22560.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
package companionless:
3+
4+
class Enumeration:
5+
protected class Val(i: Int):
6+
def this() = this(42)
7+
8+
class Test extends Enumeration:
9+
val Hearts = Val(27)
10+
val Diamonds = Val()
11+
12+
13+
package companioned:
14+
15+
class Enumeration:
16+
protected class Val(i: Int):
17+
def this() = this(42)
18+
protected object Val
19+
20+
class Test extends Enumeration:
21+
val Hearts = Val(27)
22+
val Diamonds = Val()

0 commit comments

Comments
 (0)