From 05fb25da98a414def2ee0d374e8b006ff7a7614c Mon Sep 17 00:00:00 2001 From: oronpo Date: Sat, 18 Dec 2021 18:44:41 -0500 Subject: [PATCH 1/6] wip --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 6 +++++- compiler/src/dotty/tools/dotc/core/Definitions.scala | 1 + library/src/scala/reflect/Enum.scala | 8 ++++++++ tests/init/neg/enum-desugared.scala | 2 +- tests/pos/enum-companion-first.scala | 7 ++++--- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 7121f7e7370d..d983d20a98e4 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -736,7 +736,11 @@ object desugar { companionDefs(anyRef, applyMeths ::: unapplyMeth :: toStringMeth :: companionMembers) } - else if (companionMembers.nonEmpty || companionDerived.nonEmpty || isEnum) + else if (isEnum) + val r = ref(defn.EnumCompanionClass.typeRef) + val r2 = appliedTypeTree(r, ref(requiredClass(className).typeRef) :: Nil) + companionDefs(r2, companionMembers) + else if (companionMembers.nonEmpty || companionDerived.nonEmpty) companionDefs(anyRef, companionMembers) else if (isValueClass) companionDefs(anyRef, Nil) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 464c7900a54f..845e480cc28c 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -740,6 +740,7 @@ class Definitions { @tu lazy val EnumClass: ClassSymbol = requiredClass("scala.reflect.Enum") @tu lazy val Enum_ordinal: Symbol = EnumClass.requiredMethod(nme.ordinal) + @tu lazy val EnumCompanionClass: ClassSymbol = requiredClass("scala.reflect.EnumCompanion") @tu lazy val EnumValueSerializationProxyClass: ClassSymbol = requiredClass("scala.runtime.EnumValueSerializationProxy") @tu lazy val EnumValueSerializationProxyConstructor: TermSymbol = diff --git a/library/src/scala/reflect/Enum.scala b/library/src/scala/reflect/Enum.scala index 92efa34cf430..a251197abe6f 100644 --- a/library/src/scala/reflect/Enum.scala +++ b/library/src/scala/reflect/Enum.scala @@ -5,3 +5,11 @@ package scala.reflect /** A number uniquely identifying a case of an enum */ def ordinal: Int + +//@annotation.transparentTrait trait EnumCompanion extends AnyRef + +/** A base trait of all Scala enum companion definitions */ +@annotation.transparentTrait trait EnumCompanion[E <: Enum] extends AnyRef: + + def values : Array[E] + def valueOf(name : String) : E \ No newline at end of file diff --git a/tests/init/neg/enum-desugared.scala b/tests/init/neg/enum-desugared.scala index eb80f112a06c..9438124efcfc 100644 --- a/tests/init/neg/enum-desugared.scala +++ b/tests/init/neg/enum-desugared.scala @@ -8,7 +8,7 @@ sealed abstract class ErrorMessageID($name: String, _$ordinal: Int) def errorNumber: Int = this.ordinal() - 2 } -object ErrorMessageID { +object ErrorMessageID extends scala.reflect.EnumCompanion[ErrorMessageID]{ final val LazyErrorId = $new(0, "LazyErrorId") final val NoExplanationID = $new(1, "NoExplanationID") diff --git a/tests/pos/enum-companion-first.scala b/tests/pos/enum-companion-first.scala index d4c1eb370031..505d9bf0cb46 100644 --- a/tests/pos/enum-companion-first.scala +++ b/tests/pos/enum-companion-first.scala @@ -1,9 +1,10 @@ -object Planet: - final val G = 6.67300E-11 +final val G = 6.67300E-11 enum Planet(mass: Double, radius: Double) extends Enum[Planet]: - def surfaceGravity = Planet.G * mass / (radius * radius) + def surfaceGravity = G * mass / (radius * radius) def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity case Mercury extends Planet(3.303e+23, 2.4397e6) case Venus extends Planet(4.869e+24, 6.0518e6) + +val check = summon[Planet.type <:< scala.reflect.EnumCompanion[Planet]] \ No newline at end of file From 257aae5e31a3170cea1f24410024af18d48ff5d7 Mon Sep 17 00:00:00 2001 From: oronpo Date: Sat, 18 Dec 2021 20:32:22 -0500 Subject: [PATCH 2/6] wip --- compiler/src/dotty/tools/dotc/ast/Desugar.scala | 5 ++--- tests/pos/enum-companion-first.scala | 7 +++---- tests/pos/enum-reflect-companion.scala | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 tests/pos/enum-reflect-companion.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index d983d20a98e4..bf0f08b06d05 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -737,9 +737,8 @@ object desugar { companionDefs(anyRef, applyMeths ::: unapplyMeth :: toStringMeth :: companionMembers) } else if (isEnum) - val r = ref(defn.EnumCompanionClass.typeRef) - val r2 = appliedTypeTree(r, ref(requiredClass(className).typeRef) :: Nil) - companionDefs(r2, companionMembers) + val parent = appliedTypeTree(ref(defn.EnumCompanionClass.typeRef), Ident(className) :: Nil) + companionDefs(parent, companionMembers) else if (companionMembers.nonEmpty || companionDerived.nonEmpty) companionDefs(anyRef, companionMembers) else if (isValueClass) diff --git a/tests/pos/enum-companion-first.scala b/tests/pos/enum-companion-first.scala index 505d9bf0cb46..d4c1eb370031 100644 --- a/tests/pos/enum-companion-first.scala +++ b/tests/pos/enum-companion-first.scala @@ -1,10 +1,9 @@ -final val G = 6.67300E-11 +object Planet: + final val G = 6.67300E-11 enum Planet(mass: Double, radius: Double) extends Enum[Planet]: - def surfaceGravity = G * mass / (radius * radius) + def surfaceGravity = Planet.G * mass / (radius * radius) def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity case Mercury extends Planet(3.303e+23, 2.4397e6) case Venus extends Planet(4.869e+24, 6.0518e6) - -val check = summon[Planet.type <:< scala.reflect.EnumCompanion[Planet]] \ No newline at end of file diff --git a/tests/pos/enum-reflect-companion.scala b/tests/pos/enum-reflect-companion.scala new file mode 100644 index 000000000000..b10897935a79 --- /dev/null +++ b/tests/pos/enum-reflect-companion.scala @@ -0,0 +1,17 @@ +enum Foo1: + case Baz, Bar + +val check1 = summon[Foo1.type <:< scala.reflect.EnumCompanion[Foo1]] + +//enum Foo2[T]: +// case Baz extends Foo2[1] +// case Bar extends Foo2[2] +// +//val check2 = summon[Foo2.type <:< scala.reflect.EnumCompanion[Foo2]] + +enum Foo3: + case Baz, Bar + +object Foo3 + +val check3 = summon[Foo3.type <:< scala.reflect.EnumCompanion[Foo3]] From 941fa532413d2a998f1a722255a94414f08672a0 Mon Sep 17 00:00:00 2001 From: oronpo Date: Sat, 18 Dec 2021 21:42:34 -0500 Subject: [PATCH 3/6] wip --- tests/pos/enum-reflect-companion.scala | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/pos/enum-reflect-companion.scala b/tests/pos/enum-reflect-companion.scala index b10897935a79..2f0047633dd2 100644 --- a/tests/pos/enum-reflect-companion.scala +++ b/tests/pos/enum-reflect-companion.scala @@ -1,3 +1,4 @@ +import scala.reflect.EnumCompanion enum Foo1: case Baz, Bar @@ -12,6 +13,13 @@ val check1 = summon[Foo1.type <:< scala.reflect.EnumCompanion[Foo1]] enum Foo3: case Baz, Bar -object Foo3 +//trait Hello +//object Foo3 extends Hello +//val x = Foo3.Bar +//val check3 = summon[Foo3.type <:< scala.reflect.EnumCompanion[Foo3]] -val check3 = summon[Foo3.type <:< scala.reflect.EnumCompanion[Foo3]] +extension [T <: reflect.Enum](enumCompanion : EnumCompanion[T]) + def check(arg : T) : Unit = println(enumCompanion.values.map(_.ordinal).mkString("\n")) + +@main def main : Unit = + Foo3.check(Foo3.Bar) \ No newline at end of file From 5c9af018222656f5bdfb2609335e885ca4ff6751 Mon Sep 17 00:00:00 2001 From: oronpo Date: Sat, 18 Dec 2021 22:40:44 -0500 Subject: [PATCH 4/6] wip --- .../src/dotty/tools/dotc/ast/Desugar.scala | 10 +++++++- .../dotty/tools/dotc/core/Definitions.scala | 1 + library/src/scala/reflect/Enum.scala | 6 ++--- tests/pos/enum-reflect-companion.scala | 23 ++++++++++++------- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index bf0f08b06d05..05ef9df76d76 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -737,7 +737,15 @@ object desugar { companionDefs(anyRef, applyMeths ::: unapplyMeth :: toStringMeth :: companionMembers) } else if (isEnum) - val parent = appliedTypeTree(ref(defn.EnumCompanionClass.typeRef), Ident(className) :: Nil) + val isSingletonEnum = companionMembers.forall { + case _ : PatDef => true + case _ : ModuleDef => true + case _ => false + } + val enumCompClass = + if (isSingletonEnum) defn.SingletonEnumCompanionClass.typeRef + else defn.EnumCompanionClass.typeRef + val parent = appliedTypeTree(ref(enumCompClass), Ident(className) :: Nil) companionDefs(parent, companionMembers) else if (companionMembers.nonEmpty || companionDerived.nonEmpty) companionDefs(anyRef, companionMembers) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 845e480cc28c..1fe6ad038059 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -741,6 +741,7 @@ class Definitions { @tu lazy val EnumClass: ClassSymbol = requiredClass("scala.reflect.Enum") @tu lazy val Enum_ordinal: Symbol = EnumClass.requiredMethod(nme.ordinal) @tu lazy val EnumCompanionClass: ClassSymbol = requiredClass("scala.reflect.EnumCompanion") + @tu lazy val SingletonEnumCompanionClass: ClassSymbol = requiredClass("scala.reflect.SingletonEnumCompanion") @tu lazy val EnumValueSerializationProxyClass: ClassSymbol = requiredClass("scala.runtime.EnumValueSerializationProxy") @tu lazy val EnumValueSerializationProxyConstructor: TermSymbol = diff --git a/library/src/scala/reflect/Enum.scala b/library/src/scala/reflect/Enum.scala index a251197abe6f..ffd38a0754d4 100644 --- a/library/src/scala/reflect/Enum.scala +++ b/library/src/scala/reflect/Enum.scala @@ -6,10 +6,10 @@ package scala.reflect /** A number uniquely identifying a case of an enum */ def ordinal: Int -//@annotation.transparentTrait trait EnumCompanion extends AnyRef - /** A base trait of all Scala enum companion definitions */ -@annotation.transparentTrait trait EnumCompanion[E <: Enum] extends AnyRef: +@annotation.transparentTrait trait EnumCompanion[E <: Enum] extends AnyRef +/** A base trait of all Scala singleton enum companion definitions */ +@annotation.transparentTrait trait SingletonEnumCompanion[E <: Enum] extends EnumCompanion[E]: def values : Array[E] def valueOf(name : String) : E \ No newline at end of file diff --git a/tests/pos/enum-reflect-companion.scala b/tests/pos/enum-reflect-companion.scala index 2f0047633dd2..7f86ebdc813c 100644 --- a/tests/pos/enum-reflect-companion.scala +++ b/tests/pos/enum-reflect-companion.scala @@ -1,8 +1,8 @@ -import scala.reflect.EnumCompanion +//import scala.reflect.EnumCompanion enum Foo1: case Baz, Bar -val check1 = summon[Foo1.type <:< scala.reflect.EnumCompanion[Foo1]] +val check1 = summon[Foo1.type <:< scala.reflect.SingletonEnumCompanion[Foo1]] //enum Foo2[T]: // case Baz extends Foo2[1] @@ -10,16 +10,23 @@ val check1 = summon[Foo1.type <:< scala.reflect.EnumCompanion[Foo1]] // //val check2 = summon[Foo2.type <:< scala.reflect.EnumCompanion[Foo2]] -enum Foo3: - case Baz, Bar +//enum Foo3: +// case Baz, Bar //trait Hello //object Foo3 extends Hello //val x = Foo3.Bar //val check3 = summon[Foo3.type <:< scala.reflect.EnumCompanion[Foo3]] -extension [T <: reflect.Enum](enumCompanion : EnumCompanion[T]) - def check(arg : T) : Unit = println(enumCompanion.values.map(_.ordinal).mkString("\n")) +//extension [T <: reflect.Enum](enumCompanion : EnumCompanion[T]) +// def check(arg : T) : Unit = println(enumCompanion.values.map(_.ordinal).mkString("\n")) + +enum Foo4: + case Yes + case No(whyNot: String) + case Skip + +val check4 = summon[Foo4.type <:< scala.reflect.EnumCompanion[Foo4]] -@main def main : Unit = - Foo3.check(Foo3.Bar) \ No newline at end of file +//@main def main : Unit = +// Foo3.check(Foo3.Bar) \ No newline at end of file From d4528516e11a625353b6571e4570e35f78423a5a Mon Sep 17 00:00:00 2001 From: oronpo Date: Sat, 18 Dec 2021 23:51:47 -0500 Subject: [PATCH 5/6] wip --- .../src/dotty/tools/dotc/ast/Desugar.scala | 3 +- tests/pos/enum-reflect-companion.scala | 32 ------------- tests/run/enum-reflect-companion.scala | 48 +++++++++++++++++++ 3 files changed, 50 insertions(+), 33 deletions(-) delete mode 100644 tests/pos/enum-reflect-companion.scala create mode 100644 tests/run/enum-reflect-companion.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 05ef9df76d76..e0beb323da51 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -745,7 +745,8 @@ object desugar { val enumCompClass = if (isSingletonEnum) defn.SingletonEnumCompanionClass.typeRef else defn.EnumCompanionClass.typeRef - val parent = appliedTypeTree(ref(enumCompClass), Ident(className) :: Nil) + val clsWithArgs = appliedTypeTree(Ident(className), impliedTparams.map(_ => WildcardTypeBoundsTree())) + val parent = appliedTypeTree(ref(enumCompClass), clsWithArgs :: Nil) companionDefs(parent, companionMembers) else if (companionMembers.nonEmpty || companionDerived.nonEmpty) companionDefs(anyRef, companionMembers) diff --git a/tests/pos/enum-reflect-companion.scala b/tests/pos/enum-reflect-companion.scala deleted file mode 100644 index 7f86ebdc813c..000000000000 --- a/tests/pos/enum-reflect-companion.scala +++ /dev/null @@ -1,32 +0,0 @@ -//import scala.reflect.EnumCompanion -enum Foo1: - case Baz, Bar - -val check1 = summon[Foo1.type <:< scala.reflect.SingletonEnumCompanion[Foo1]] - -//enum Foo2[T]: -// case Baz extends Foo2[1] -// case Bar extends Foo2[2] -// -//val check2 = summon[Foo2.type <:< scala.reflect.EnumCompanion[Foo2]] - -//enum Foo3: -// case Baz, Bar - -//trait Hello -//object Foo3 extends Hello -//val x = Foo3.Bar -//val check3 = summon[Foo3.type <:< scala.reflect.EnumCompanion[Foo3]] - -//extension [T <: reflect.Enum](enumCompanion : EnumCompanion[T]) -// def check(arg : T) : Unit = println(enumCompanion.values.map(_.ordinal).mkString("\n")) - -enum Foo4: - case Yes - case No(whyNot: String) - case Skip - -val check4 = summon[Foo4.type <:< scala.reflect.EnumCompanion[Foo4]] - -//@main def main : Unit = -// Foo3.check(Foo3.Bar) \ No newline at end of file diff --git a/tests/run/enum-reflect-companion.scala b/tests/run/enum-reflect-companion.scala new file mode 100644 index 000000000000..49eb50a75029 --- /dev/null +++ b/tests/run/enum-reflect-companion.scala @@ -0,0 +1,48 @@ +import scala.reflect.{EnumCompanion, SingletonEnumCompanion} +enum Foo1: + case Baz, Bar + +val check1 = summon[Foo1.type <:< SingletonEnumCompanion[Foo1]] + +enum Foo2[T]: + case Baz extends Foo2[1] + case Bar extends Foo2[2] + +val check2 = summon[Foo2.type <:< SingletonEnumCompanion[Foo2[?]]] + +enum Foo3[A, B[_]]: + case Baz extends Foo3[Int, List] + case Bar extends Foo3[Int, List] + +val check3 = summon[Foo3.type <:< SingletonEnumCompanion[Foo3[?, ?]]] + +extension [T <: reflect.Enum](enumCompanion : SingletonEnumCompanion[T]) + def check(arg : T) : Unit = assert(enumCompanion.values.contains(arg)) + +enum Foo4: + case Yes + case No(whyNot: String) + case Skip + +val check4 = summon[Foo4.type <:< EnumCompanion[Foo4]] + +@main def main : Unit = + Foo3.check(Foo3.Bar) + (Foo3 : AnyRef) match + case _ : SingletonEnumCompanion[?] => + case _ : EnumCompanion[?] => assert(false) + case _ => assert(false) + + (Foo4 : AnyRef) match + case _ : SingletonEnumCompanion[?] => assert(false) + case _ : EnumCompanion[?] => + case _ => assert(false) + +enum Foo5: + case Baz, Bar + +trait Hello +object Foo5 extends Hello + +//TODO: fix implementation so this would work +//val check5 = summon[Foo5.type <:< scala.reflect.EnumCompanion[Foo5] with Hello] From a77b2fba7b9244ba3197b544edc912ed9ff2c7f6 Mon Sep 17 00:00:00 2001 From: oronpo Date: Sun, 19 Dec 2021 11:56:27 -0500 Subject: [PATCH 6/6] wip --- tests/run/enum-reflect-companion.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run/enum-reflect-companion.scala b/tests/run/enum-reflect-companion.scala index 49eb50a75029..7d7c4d59447c 100644 --- a/tests/run/enum-reflect-companion.scala +++ b/tests/run/enum-reflect-companion.scala @@ -26,7 +26,7 @@ enum Foo4: val check4 = summon[Foo4.type <:< EnumCompanion[Foo4]] -@main def main : Unit = +@main def Test : Unit = Foo3.check(Foo3.Bar) (Foo3 : AnyRef) match case _ : SingletonEnumCompanion[?] =>