diff --git a/core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala b/core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala new file mode 100644 index 000000000..d5f1ad4a1 --- /dev/null +++ b/core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala @@ -0,0 +1,45 @@ +package zio.prelude.newtypes + +import zio.prelude.newtypes.derivation.derive +import zio.prelude.{Newtype, Subtype} +import zio.test._ + +object DerivationSpec extends DefaultRunnableSpec { + trait Show[A]{ + def show(a: A): String + } + + implicit val showString: Show[String] = (a: String) => a + + // these are imported from an external library - we have no control over them + object External{ + object Secret extends Newtype[String] + type Secret = Secret.Type + + object Password extends Subtype[String] + type Password = Password.Type + } + + import External._ + + override def spec: ZSpec[Environment, Failure] = suite("external derivation for newtypes")( + test("works for Newtype"){ + val showSecret: Show[Secret] = derive + assertTrue(showSecret.show(Secret("foo")) == "foo") + }, + test("works for Subtype"){ + val showPassword: Show[Password] = derive + assertTrue(showPassword.show(Password("foo")) == "foo") + }, + testM("works with auto derivation"){ + typeCheck( + """ + |import zio.prelude.newtypes.derivation.auto._ + |implicitly[Show[Secret]] + |implicitly[Show[Password]] + |""".stripMargin) + .absolve + .as(assertCompletes) + } + ) +} diff --git a/core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala b/core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala new file mode 100644 index 000000000..10631bbcf --- /dev/null +++ b/core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala @@ -0,0 +1,14 @@ +package zio.prelude.newtypes + +import zio.prelude.Newtype + +object derivation { + def derive[A, STA <: Newtype[A], F[_]](implicit ev: STA <:< Newtype[A], typeClass: F[A]): F[STA#Type] = + typeClass.asInstanceOf[F[STA#Type]] + + trait Auto { + implicit def auto[A, STA <: Newtype[A], F[_]](implicit ev: STA <:< Newtype[A], typeClass: F[A]): F[STA#Type] = + derive + } + object auto extends Auto +}