Skip to content

Commit e82cb7c

Browse files
committed
Fix #1567: Widen private constructor in value class
Private or protected constructors of value classes need to be widenened to public in order to enable boxing anywhere. Technically we should also do something about qualified private constructors, but since we want to get rid of them anyway it's urgent.
1 parent dac5b93 commit e82cb7c

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

src/dotty/tools/dotc/transform/ExtensionMethods.scala

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ import SymUtils._
3232
* in [[ElimErasedValueType]].
3333
* This is different from the implementation of value classes in Scala 2
3434
* (see SIP-15) which uses `asInstanceOf` which does not typecheck.
35+
*
36+
* Finally, if the constructor of a value class is private pr protected
37+
* it is widened to public.
3538
*/
3639
class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransformer =>
3740

@@ -96,11 +99,18 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
9699
case _ =>
97100
moduleClassSym
98101
}
99-
case ref: SymDenotation
100-
if isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnot) =>
101-
val ref1 = ref.copySymDenotation()
102-
ref1.removeAnnotation(defn.TailrecAnnot)
103-
ref1
102+
case ref: SymDenotation =>
103+
if (isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnot)) {
104+
val ref1 = ref.copySymDenotation()
105+
ref1.removeAnnotation(defn.TailrecAnnot)
106+
ref1
107+
}
108+
else if (ref.isConstructor && isDerivedValueClass(ref.owner) && ref.is(AccessFlags)) {
109+
val ref1 = ref.copySymDenotation()
110+
ref1.resetFlag(AccessFlags)
111+
ref1
112+
}
113+
else ref
104114
case _ =>
105115
ref
106116
}

tests/pos/1567/PosZInt_1.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
final class PosZInt private (val value: Int) extends AnyVal
2+
3+
object PosZInt {
4+
def from(value: Int): Option[PosZInt] =
5+
if (value >= 0) Some(new PosZInt(value)) else None
6+
}

tests/pos/1567/Test_2.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
scala.util.Try(PosZInt.from(1).get)
3+
}

0 commit comments

Comments
 (0)