Skip to content

Commit 93ffd23

Browse files
authored
@publicInBinary has effect on secondary constructors (#22630)
Closes #22498
2 parents 28fa050 + 529f76f commit 93ffd23

File tree

7 files changed

+45
-3
lines changed

7 files changed

+45
-3
lines changed

Diff for: compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ object PrepareInlineable {
105105
def preTransform(tree: Tree)(using Context): Tree = tree match {
106106
case tree: RefTree if needsAccessor(tree.symbol) =>
107107
if (tree.symbol.isConstructor) {
108-
report.error("Implementation restriction: cannot use private constructors in inline methods", tree.srcPos)
109-
tree // TODO: create a proper accessor for the private constructor
108+
report.error("Private constructors used in inline methods require @publicInBinary", tree.srcPos)
109+
tree
110110
}
111111
else
112112
val accessor = useAccessor(tree)

Diff for: compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ import ValueClasses.*
2020
* Make private accessor in value class not-private. This is necessary to unbox
2121
* the value class when accessing it from separate compilation units
2222
*
23-
* Also, make non-private any private parameter forwarders that forward to an inherited
23+
* Make non-private any private parameter forwarders that forward to an inherited
2424
* public or protected parameter accessor with the same name as the forwarder.
2525
* This is necessary since private methods are not allowed to have the same name
2626
* as inherited public ones.
2727
*
28+
* Also, make non-private any private constructor that is annotated with `@publicInBinary`.
29+
* (See SIP-52)
30+
*
2831
* See discussion in https://github.com/scala/scala3/pull/784
2932
* and https://github.com/scala/scala3/issues/783
3033
*/
@@ -102,6 +105,8 @@ class ExpandPrivate extends MiniPhase with IdentityDenotTransformer { thisPhase
102105
override def transformDefDef(tree: DefDef)(using Context): DefDef = {
103106
val sym = tree.symbol
104107
tree.rhs match {
108+
case _ if sym.isConstructor && sym.hasPublicInBinary =>
109+
sym.ensureNotPrivate.installAfter(thisPhase)
105110
case Apply(sel @ Select(_: Super, _), _)
106111
if sym.isAllOf(PrivateParamAccessor) && sel.symbol.is(ParamAccessor) && sym.name == sel.symbol.name =>
107112
sym.ensureNotPrivate.installAfter(thisPhase)

Diff for: tests/neg/i22498.check

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg/i22498.scala:7:32 ----------------------------------------------------------------------------------
2+
7 | inline def proxy: Foo = new Foo(0) // error
3+
| ^^^
4+
| Private constructors used in inline methods require @publicInBinary

Diff for: tests/neg/i22498.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//> using options -experimental
2+
3+
import scala.annotation.publicInBinary
4+
5+
class Foo:
6+
private def this(x: Int) = this()
7+
inline def proxy: Foo = new Foo(0) // error

Diff for: tests/run/i22497.check

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public Foo()
2+
public Foo(int)
3+
public Foo(java.lang.String)

Diff for: tests/run/i22497.scala

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// scalajs: --skip
2+
3+
import scala.annotation.publicInBinary
4+
import scala.annotation.experimental
5+
6+
@experimental
7+
class Foo:
8+
@publicInBinary private def this(i: Int) = this()
9+
@publicInBinary protected def this(i: String) = this()
10+
11+
@experimental
12+
@main def Test =
13+
println(classOf[Foo].getConstructors().mkString("\n"))

Diff for: tests/run/i22498.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//> using options -experimental
2+
3+
import scala.annotation.publicInBinary
4+
5+
class Foo:
6+
@publicInBinary private def this(x: Int) = this()
7+
inline def proxy: Foo = new Foo(0)
8+
9+
@main def Test =
10+
val x = (new Foo).proxy

0 commit comments

Comments
 (0)