diff --git a/library/src/scala/deriving/Mirror.scala b/library/src/scala/deriving/Mirror.scala index d20ea3e5f01e..d091f4ee559e 100644 --- a/library/src/scala/deriving/Mirror.scala +++ b/library/src/scala/deriving/Mirror.scala @@ -49,4 +49,15 @@ 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`. */ + @annotation.experimental + 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`. */ + @annotation.experimental + def fromTuple(t: p.MirroredElemTypes): T = + p.fromProduct(t) } 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") 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/neg/deriving.scala b/tests/neg/deriving.scala index 6dd84d6e84c3..4d8d0f001cec 100644 --- a/tests/neg/deriving.scala +++ b/tests/neg/deriving.scala @@ -13,7 +13,6 @@ sealed trait B derives Generic // error: cannot take shape, its subclass class D class D(x: Int, y: String) extends B - class E derives Generic // 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 @@ -23,3 +22,4 @@ object G { case class H() extends F } } + 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))) + 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 {