From 4fd4142042247b2279e96f2432f41dbfa9f903e9 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 13 Jan 2022 10:26:36 +0000 Subject: [PATCH] Protected case class constructor -> private apply --- .../src/dotty/tools/dotc/ast/Desugar.scala | 16 ++------------- tests/neg/caseclass-access.scala | 16 +++++++++++---- tests/neg/i14187.scala | 7 +++++++ tests/pos/caseclass-access.scala | 20 +++++++++---------- 4 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 tests/neg/i14187.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 7121f7e7370d..c12060e859ee 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -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))) diff --git a/tests/neg/caseclass-access.scala b/tests/neg/caseclass-access.scala index b14ee104ecca..de2305b6e3ec 100644 --- a/tests/neg/caseclass-access.scala +++ b/tests/neg/caseclass-access.scala @@ -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 } @@ -19,17 +21,21 @@ 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 { @@ -37,6 +43,8 @@ object qualified_protected { } 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 } diff --git a/tests/neg/i14187.scala b/tests/neg/i14187.scala new file mode 100644 index 000000000000..6e915dc02f38 --- /dev/null +++ b/tests/neg/i14187.scala @@ -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 diff --git a/tests/pos/caseclass-access.scala b/tests/pos/caseclass-access.scala index 1d8dc03089e7..6e5ed7a0f05e 100644 --- a/tests/pos/caseclass-access.scala +++ b/tests/pos/caseclass-access.scala @@ -1,24 +1,30 @@ 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 } @@ -26,22 +32,14 @@ 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 }