Skip to content

Commit

Permalink
Protected case class constructor -> private apply
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Feb 17, 2022
1 parent 847cce2 commit 4fd4142
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 29 deletions.
16 changes: 2 additions & 14 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -693,23 +693,11 @@ object desugar {
// For all other classes, the parent is AnyRef.
val companions =
if (isCaseClass) {

// true if access to the apply method has to be restricted
// i.e. if the case class constructor is either private or qualified private
def restrictedAccess = {
val mods = constr1.mods
mods.is(Private) || (!mods.is(Protected) && mods.hasPrivateWithin)
}

val applyMeths =
if (mods.is(Abstract)) Nil
else {
val copiedFlagsMask = copiedAccessFlags & Private
val appMods = {
val mods = Modifiers(Synthetic | constr1.mods.flags & copiedFlagsMask)
if (restrictedAccess) mods.withPrivateWithin(constr1.mods.privateWithin)
else mods
}
val appMods =
Modifiers(Synthetic | constr1.mods.flags & copiedAccessFlags).withPrivateWithin(constr1.mods.privateWithin)
val appParamss =
derivedVparamss.nestedZipWithConserve(constrVparamss)((ap, cp) =>
ap.withMods(ap.mods | (cp.mods.flags & HasDefault)))
Expand Down
16 changes: 12 additions & 4 deletions tests/neg/caseclass-access.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
case class A private (i: Int)
object A
object ATest {
def a0: A = new A(0) // error: constructor is private
def a1: A = A(1) // error: apply is private
def a2: A = a1.copy(2) // error: copy is private
}

case class B private (i: Int) // ok: no user-defined companion object
object BTest {
def b0: B = new B(0) // error: constructor is private
def b1: B = B(1) // error: apply is private
def b2: B = b1.copy(2) // error: copy is private
}
Expand All @@ -19,24 +21,30 @@ object qualified_private {
}
object QPrivTest {
import qualified_private.*
def c0: C = new C(0) // error: constructor is private
def c1: C = C(1) // error: apply is private
def c2: C = c1.copy(2) // error: copy is private

def d0: D = new D(0) // error: constructor is private
def d1: D = D(1) // error: apply is private
def d2: D = d1.copy(2) // error: copy is private
}

case class E protected (i: Int)
object ETest {
def e1: E = E(1)
def e2: E = e2.copy(2) // error: copy is protected
def e0: E = new E(0) // error: constructor is protected
def e1: E = E(1) // error: apply is protected
def e2: E = e1.copy(2) // error: copy is protected
def eta: Int => E = E // error: apply is protected
}

object qualified_protected {
case class F protected[qualified_protected] (i: Int)
}
object QProtTest {
import qualified_protected.*
def f1: F = F(1)
def f2: F = f2.copy(2) // error: copy is protected
def f0: F = new F(0) // error: constructor is protected
def f1: F = F(1) // error: apply is protected
def f2: F = f1.copy(2) // error: copy is protected
def eta: Int => F = F // error: apply is protected
}
7 changes: 7 additions & 0 deletions tests/neg/i14187.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
sealed case class Foo protected (i: Int, j: Int)

final class Bar(n: Int) extends Foo(n, n)

class Other:
def foo = Foo(1, 2) // error
def foo2 = Foo.apply(1, 2) // error
20 changes: 9 additions & 11 deletions tests/pos/caseclass-access.scala
Original file line number Diff line number Diff line change
@@ -1,47 +1,45 @@
case class A private (i: Int)
object A {
def a0 = new A(0) // constructor is accessible in companion
def a = A(1).copy(2) // apply and copy are accessible in companion
}

case class B private (i: Int) { // no user-defined companion object, should compile
def b0 = new B(0) // constructor is accessible
def b = B(1).copy(2) // apply and copy are accessible
}

object qualified_private {
case class A private[qualified_private] (i: Int)
object A {
def a0 = new A(0) // constructor is accessible in companion
def a = A(1).copy(2) // apply and copy are accessible in companion
}

def a0 = new A(0) // constructor is accessible in qualified_private object
def a = A(1).copy(2) // apply and copy are accessible in qualified_private object

case class B private[qualified_private] (i: Int) { // no user-defined companion object, should compile
def b0 = new B(0) // constructor is accessible
def b = B(1).copy(2) // apply and copy are accessible
}

def b0 = new B(0) // constructor is accessible in qualified_private object
def b = B(1).copy(2) // apply and copy are accessible in qualified_private object
}

case class C protected (i: Int)
class CSub extends C(1) {
def c = copy(2) // copy is accessible in subclass
}
object CTest {
def c = C(1) // apply is public
}

object qualified_protected {
case class C protected[qualified_protected] (i: Int)
class CSub extends C(1) {
def c = copy(2) // copy is accessible in subclass
}
object CTest {
def c = C(1) // apply is public
def checkExtendsFunction: Int => C = C // companion extends (Int => C)
}
def eta: Int => C = C // can eta-expand C.apply method

def c = C(1).copy(2)
}
object CQualifiedTest {
def c = qualified_protected.C(1) // apply is public
def c0 = new C(0) // constructor is accessible in qualified_protected object
def c = C(1).copy(2) // apply and copy are accessible in qualified_protected object
}

0 comments on commit 4fd4142

Please sign in to comment.