diff --git a/core/shared/src/main/scala-3/monocle/internal/IsoFields.scala b/core/shared/src/main/scala-3/monocle/internal/IsoFields.scala index 170e51622..bd3d2cb3f 100644 --- a/core/shared/src/main/scala-3/monocle/internal/IsoFields.scala +++ b/core/shared/src/main/scala-3/monocle/internal/IsoFields.scala @@ -1,28 +1,27 @@ package monocle.internal -import monocle.Iso +import monocle.{Iso, PIso} import scala.quoted.{quotes, Expr, Quotes, Type} import scala.deriving.Mirror object IsoFields { - transparent inline def apply[S <: Product](using mirror: Mirror.ProductOf[S]): Iso[S, Tuple] = + transparent inline def apply[S <: Product](using mirror: Mirror.ProductOf[S]): PIso[S, S, ? <: Tuple, ? <: Tuple] = ${ IsoFieldsImpl.apply[S]('mirror) } } private[monocle] object IsoFieldsImpl { - def apply[S <: Product](mirror: Expr[Mirror.ProductOf[S]])(using Quotes, Type[S]): Expr[Iso[S, Tuple]] = { - - def whitebox[A <: Tuple](e: Expr[Iso[S, A]]): Expr[Iso[S, Tuple]] = - e.asInstanceOf[Expr[Iso[S, Tuple]]] - + def apply[S <: Product]( + mirror: Expr[Mirror.ProductOf[S]] + )(using Quotes, Type[S]): Expr[PIso[S, S, ? <: Tuple, ? <: Tuple]] = mirror match { case '{ type a <: Tuple; $m: Mirror.ProductOf[S] { type MirroredElemTypes = `a` } } => - whitebox('{ + '{ val f: S => a = Tuple.fromProductTyped(_)(using $m) val g: a => S = $m.fromProduct(_) Iso[S, a](f)(g) - }) + } + case other => + quotes.reflect.report.errorAndAbort(s"Unexpected mirror type: ${other.show}") } - } } diff --git a/core/shared/src/main/scala-3/monocle/syntax/MacroSyntax.scala b/core/shared/src/main/scala-3/monocle/syntax/MacroSyntax.scala index e4a8492d7..b44a819e9 100644 --- a/core/shared/src/main/scala-3/monocle/syntax/MacroSyntax.scala +++ b/core/shared/src/main/scala-3/monocle/syntax/MacroSyntax.scala @@ -13,7 +13,7 @@ trait MacroSyntax { * Case classes with 0 fields will correspond with `EmptyTuple`, 1 with `Tuple1[field type]`, 2 or more with a * tuple of all field types in the same order as the fields themselves. */ - transparent inline def fields[S <: Product: Mirror.ProductOf]: Iso[S, Tuple] = + transparent inline def fields[S <: Product: Mirror.ProductOf]: PIso[S, S, ? <: Tuple, ? <: Tuple] = IsoFields[S] } diff --git a/core/shared/src/test/scala-3/monocle/internal/IsoFieldsTest.scala b/core/shared/src/test/scala-3/monocle/internal/IsoFieldsTest.scala index ea4d5c59b..08fdad14f 100644 --- a/core/shared/src/test/scala-3/monocle/internal/IsoFieldsTest.scala +++ b/core/shared/src/test/scala-3/monocle/internal/IsoFieldsTest.scala @@ -31,4 +31,13 @@ final class IsoFieldsTest extends munit.FunSuite { assertEquals(iso.reverseGet(("hi", 5)), Foo("hi", 5)) assertEquals(iso.reverseGet(iso.get(Foo("hi", 5))), Foo("hi", 5)) } + + test("fields extension method works") { + case class Foo(s: String, i: Int) + val foo = Foo("hi", 5) + val iso: Iso[Foo, (String, Int)] = Iso.fields[Foo] + + assertEquals(iso.get(foo), ("hi", 5)) + assertEquals(iso.reverseGet(("hi", 5)), foo) + } }