From 55ee4c9bf8a58fdb68b2f5b1a6ce2919ac7aa4cc Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Tue, 14 Dec 2021 19:16:35 -0500 Subject: [PATCH 1/5] Add typed versions of Mirror.ProductOf#fromProduct --- library/src/scala/deriving/Mirror.scala | 9 +++++++++ tests/neg/deriving.scala | 21 ++++++++++++++++----- tests/run/deriving.scala | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/library/src/scala/deriving/Mirror.scala b/library/src/scala/deriving/Mirror.scala index d20ea3e5f01e..c2487933bd25 100644 --- a/library/src/scala/deriving/Mirror.scala +++ b/library/src/scala/deriving/Mirror.scala @@ -49,4 +49,13 @@ object Mirror { type Of[T] = Mirror { type MirroredType = T; type MirroredMonoType = T ; type MirroredElemTypes <: Tuple } type ProductOf[T] = Mirror.Product { type MirroredType = T; type MirroredMonoType = T ; type MirroredElemTypes <: Tuple } type SumOf[T] = Mirror.Sum { type MirroredType = T; type MirroredMonoType = T; type MirroredElemTypes <: Tuple } + + extension [T](p: ProductOf[T]) + /** Create a new instance of type `T` with elements taken from product `a`. */ + def fromProductTyped[A <: scala.Product](a: A)(using m: ProductOf[A], ev: p.MirroredElemTypes =:= m.MirroredElemTypes): T = + p.fromProduct(a) + + /** Create a new instance of type `T` with elements taken from tuple `t`. */ + def fromTuple(t: p.MirroredElemTypes): T = + p.fromProduct(t) } diff --git a/tests/neg/deriving.scala b/tests/neg/deriving.scala index 6dd84d6e84c3..d2ade97c1544 100644 --- a/tests/neg/deriving.scala +++ b/tests/neg/deriving.scala @@ -1,6 +1,6 @@ -import reflect.Generic +import deriving.MirrorOf -sealed trait A derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses +sealed trait A object A { def f() = { @@ -9,17 +9,28 @@ object A { } } -sealed trait B derives Generic // error: cannot take shape, its subclass class D is not a case class +def aMirror = summon[Mirror.Of[A]] // error: cannot take shape, it has anonymous or inaccessible subclasses + +sealed trait B class D(x: Int, y: String) extends B +def bMirror = summon[Mirror.Of[B]] // error: cannot take shape, its subclass class D is not a case class -class E derives Generic // error: cannot take shape, it is neither sealed nor a case class +class E +def eMirror = summon[Mirror.Of[E]] // error: cannot take shape, it is neither sealed nor a case class -sealed trait F derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses +sealed trait F +def fMirror = summon[Mirror.Of[F]] // error: cannot take shape, it has anonymous or inaccessible subclasses object G { def f() = { case class H() extends F } } + +case class I(x: Int, y: String) +object I: + def f = summon[deriving.Mirror.ProductOf[I]].fromProductTyped((1, 2)) // error + def g = summon[deriving.Mirror.ProductOf[I]].fromTuple((1, 2)) // error + diff --git a/tests/run/deriving.scala b/tests/run/deriving.scala index b995241c58dd..743b1662977c 100644 --- a/tests/run/deriving.scala +++ b/tests/run/deriving.scala @@ -13,6 +13,8 @@ object Test extends App { case class AA[X >: Null <: AnyRef](x: X, y: X, z: String) println(summon[Mirror.ProductOf[A]].fromProduct(A(1, 2))) + summon[Mirror.ProductOf[A]].fromProductTyped(A(1, 2)) + summon[Mirror.ProductOf[A]].fromTuple((1, 2)) assert(summon[Mirror.SumOf[T]].ordinal(A(1, 2)) == 0) assert(summon[Mirror.Sum { type MirroredType = T }].ordinal(B) == 1) summon[Mirror.Of[A]] match { From 54a17120e8d30f68892ab76960e82594b43879dc Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Tue, 14 Dec 2021 20:06:24 -0500 Subject: [PATCH 2/5] Update mima filters --- project/MiMaFilters.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index cac81eecc141..73b7e9ca674e 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -17,6 +17,8 @@ object MiMaFilters { ProblemFilters.exclude[MissingClassProblem]("scala.compiletime.ops.long$"), ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#CompilationInfoModule.XmacroSettings"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#CompilationInfoModule.XmacroSettings"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.deriving.Mirror.fromProductTyped"), + ProblemFilters.exclude[DirectMissingMethodProblem]("scala.deriving.Mirror.fromTuple"), // Private to the compiler - needed for forward binary compatibility ProblemFilters.exclude[MissingClassProblem]("scala.annotation.since") From 136fafc32efa7633d97e8247031629dc210bf298 Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Wed, 15 Dec 2021 07:57:49 -0500 Subject: [PATCH 3/5] Add experimental annotation to new operations --- library/src/scala/deriving/Mirror.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/src/scala/deriving/Mirror.scala b/library/src/scala/deriving/Mirror.scala index c2487933bd25..5cbb423fc2c8 100644 --- a/library/src/scala/deriving/Mirror.scala +++ b/library/src/scala/deriving/Mirror.scala @@ -52,10 +52,12 @@ object Mirror { extension [T](p: ProductOf[T]) /** Create a new instance of type `T` with elements taken from product `a`. */ + @annotation.experimental def fromProductTyped[A <: scala.Product](a: A)(using m: ProductOf[A], ev: p.MirroredElemTypes =:= m.MirroredElemTypes): T = p.fromProduct(a) /** Create a new instance of type `T` with elements taken from tuple `t`. */ + @annotation.experimental def fromTuple(t: p.MirroredElemTypes): T = p.fromProduct(t) } From e700581e9570237897123a49f539e95042713742 Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Thu, 16 Dec 2021 07:52:46 -0500 Subject: [PATCH 4/5] Address review comments --- library/src/scala/deriving/Mirror.scala | 2 +- tests/neg/deriving.scala | 21 +++++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/library/src/scala/deriving/Mirror.scala b/library/src/scala/deriving/Mirror.scala index 5cbb423fc2c8..d091f4ee559e 100644 --- a/library/src/scala/deriving/Mirror.scala +++ b/library/src/scala/deriving/Mirror.scala @@ -53,7 +53,7 @@ object Mirror { extension [T](p: ProductOf[T]) /** Create a new instance of type `T` with elements taken from product `a`. */ @annotation.experimental - def fromProductTyped[A <: scala.Product](a: A)(using m: ProductOf[A], ev: p.MirroredElemTypes =:= m.MirroredElemTypes): T = + def fromProductTyped[A <: scala.Product, Elems <: p.MirroredElemTypes](a: A)(using m: ProductOf[A] { type MirroredElemTypes = Elems }): T = p.fromProduct(a) /** Create a new instance of type `T` with elements taken from tuple `t`. */ diff --git a/tests/neg/deriving.scala b/tests/neg/deriving.scala index d2ade97c1544..4d8d0f001cec 100644 --- a/tests/neg/deriving.scala +++ b/tests/neg/deriving.scala @@ -1,6 +1,6 @@ -import deriving.MirrorOf +import reflect.Generic -sealed trait A +sealed trait A derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses object A { def f() = { @@ -9,19 +9,13 @@ object A { } } -def aMirror = summon[Mirror.Of[A]] // error: cannot take shape, it has anonymous or inaccessible subclasses - -sealed trait B +sealed trait B derives Generic // error: cannot take shape, its subclass class D is not a case class class D(x: Int, y: String) extends B -def bMirror = summon[Mirror.Of[B]] // error: cannot take shape, its subclass class D is not a case class - -class E -def eMirror = summon[Mirror.Of[E]] // error: cannot take shape, it is neither sealed nor a case class +class E derives Generic // error: cannot take shape, it is neither sealed nor a case class -sealed trait F -def fMirror = summon[Mirror.Of[F]] // error: cannot take shape, it has anonymous or inaccessible subclasses +sealed trait F derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses object G { def f() = { @@ -29,8 +23,3 @@ object G { } } -case class I(x: Int, y: String) -object I: - def f = summon[deriving.Mirror.ProductOf[I]].fromProductTyped((1, 2)) // error - def g = summon[deriving.Mirror.ProductOf[I]].fromTuple((1, 2)) // error - From 6e6e0d2d7da1ec2c5ed73e9a3a16c201ff995c70 Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Thu, 16 Dec 2021 07:53:13 -0500 Subject: [PATCH 5/5] Add fromProductTyped tests --- tests/neg/deriving-from-product-typed.scala | 10 ++++++++++ tests/run/deriving-from-product-typed.scala | 11 +++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/neg/deriving-from-product-typed.scala create mode 100644 tests/run/deriving-from-product-typed.scala diff --git a/tests/neg/deriving-from-product-typed.scala b/tests/neg/deriving-from-product-typed.scala new file mode 100644 index 000000000000..91537af9d08c --- /dev/null +++ b/tests/neg/deriving-from-product-typed.scala @@ -0,0 +1,10 @@ +import deriving.Mirror + +case class A(x: Int, y: String) +case class B(a: Any, b: Any) +object A: + def f = summon[Mirror.ProductOf[A]].fromProductTyped((1, 2)) // error + def g = summon[Mirror.ProductOf[A]].fromTuple((1, 2)) // error + def h = summon[Mirror.ProductOf[B]].fromProductTyped(A(1, "")) + def i = summon[Mirror.ProductOf[A]].fromProductTyped(B(1, "")) // error + diff --git a/tests/run/deriving-from-product-typed.scala b/tests/run/deriving-from-product-typed.scala new file mode 100644 index 000000000000..7b68c40c7ad1 --- /dev/null +++ b/tests/run/deriving-from-product-typed.scala @@ -0,0 +1,11 @@ +case class A(x: Option[Int], y: Option[Any]) +case class B(x: Some[Int], y: Some[Boolean]) + +object Test extends App: + import deriving.* + + val ma = summon[Mirror.ProductOf[A]] + + ma.fromProductTyped(B(Some(1), Some(true))) + ma.fromProductTyped((Some(1), Some(false))) +