From e82cb7cdb93306b5fccf6aeef0e087999f46a016 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 14 Oct 2016 09:12:58 +0200 Subject: [PATCH] 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. --- .../dotc/transform/ExtensionMethods.scala | 20 ++++++++++++++----- tests/pos/1567/PosZInt_1.scala | 6 ++++++ tests/pos/1567/Test_2.scala | 3 +++ 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 tests/pos/1567/PosZInt_1.scala create mode 100644 tests/pos/1567/Test_2.scala diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala index 62a21198d0d7..5ae4e8a54de9 100644 --- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -32,6 +32,9 @@ import SymUtils._ * in [[ElimErasedValueType]]. * This is different from the implementation of value classes in Scala 2 * (see SIP-15) which uses `asInstanceOf` which does not typecheck. + * + * Finally, if the constructor of a value class is private pr protected + * it is widened to public. */ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransformer => @@ -96,11 +99,18 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful case _ => moduleClassSym } - case ref: SymDenotation - if isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnot) => - val ref1 = ref.copySymDenotation() - ref1.removeAnnotation(defn.TailrecAnnot) - ref1 + case ref: SymDenotation => + if (isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnot)) { + val ref1 = ref.copySymDenotation() + ref1.removeAnnotation(defn.TailrecAnnot) + ref1 + } + else if (ref.isConstructor && isDerivedValueClass(ref.owner) && ref.is(AccessFlags)) { + val ref1 = ref.copySymDenotation() + ref1.resetFlag(AccessFlags) + ref1 + } + else ref case _ => ref } diff --git a/tests/pos/1567/PosZInt_1.scala b/tests/pos/1567/PosZInt_1.scala new file mode 100644 index 000000000000..60b4061e672b --- /dev/null +++ b/tests/pos/1567/PosZInt_1.scala @@ -0,0 +1,6 @@ +final class PosZInt private (val value: Int) extends AnyVal + +object PosZInt { + def from(value: Int): Option[PosZInt] = + if (value >= 0) Some(new PosZInt(value)) else None +} diff --git a/tests/pos/1567/Test_2.scala b/tests/pos/1567/Test_2.scala new file mode 100644 index 000000000000..db6ca7070a33 --- /dev/null +++ b/tests/pos/1567/Test_2.scala @@ -0,0 +1,3 @@ +object Test { + scala.util.Try(PosZInt.from(1).get) +}