From cec3285154bc030152a7efa69ef724b0c7c90615 Mon Sep 17 00:00:00 2001 From: Nabil Abdel-Hafeez <7283535+987Nabil@users.noreply.github.com> Date: Fri, 30 Jun 2023 01:54:08 +0200 Subject: [PATCH] Fix: generic fields default for Scala 3, find default value for Scala 2 --- .../scala-2/zio/schema/DeriveSchema.scala | 3 +- .../scala-3/zio/schema/DeriveSchema.scala | 8 ++++-- .../test/scala/zio/schema/DeriveSpec.scala | 28 +++++++++++++++++-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala index ca36d8a63..94709ff49 100644 --- a/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala +++ b/zio-schema-derivation/shared/src/main/scala-2/zio/schema/DeriveSchema.scala @@ -233,8 +233,7 @@ object DeriveSchema { val defaultApply = tpe.companion.member(TermName(s"apply$$default$$${i + 1}")) Some(i -> defaultInit) .filter(_ => defaultInit != NoSymbol) - .orElse(Some(i -> defaultApply)) - .filter(_ => defaultApply != NoSymbol) + .orElse(Some(i -> defaultApply).filter(_ => defaultApply != NoSymbol)) } else None } .toMap diff --git a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala index 0596a1540..8162b1aa0 100644 --- a/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala +++ b/zio-schema-derivation/shared/src/main/scala-3/zio/schema/DeriveSchema.scala @@ -288,8 +288,12 @@ private case class DeriveSchema()(using val ctx: Quotes) extends ReflectionUtils .declaredMethod(s"$$apply$$default$$$i") .headOption ) - .map(Select(Ref(from.companionModule), _).asExpr) - ).zip(from.primaryConstructor.paramSymss.flatten.map(_.name)).collect{case (Some(expr), name) => name -> expr}.toMap + .map { s => + val select = Select(Ref(from.companionModule), s) + if (select.isExpr) select.asExpr + else select.appliedToType(TypeRepr.of[Any]).asExpr + } + ).zip(from.primaryConstructor.paramSymss.flatten.filter(!_.isTypeParam).map(_.name)).collect{ case (Some(expr), name) => name -> expr }.toMap private def fromConstructor(from: Symbol): scala.collection.Map[String, List[Expr[Any]]] = { val defaults = defaultValues(from) diff --git a/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala b/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala index da157f402..a5bf6a2c8 100644 --- a/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala +++ b/zio-schema-derivation/shared/src/test/scala/zio/schema/DeriveSpec.scala @@ -2,12 +2,12 @@ package zio.schema import scala.annotation.nowarn import scala.reflect.ClassTag - import zio.schema.Deriver.WrappedF import zio.schema.Schema.Field +import zio.schema.StandardType.IntType import zio.schema.annotation.fieldDefaultValue -import zio.test.{ Spec, TestEnvironment, ZIOSpecDefault, assertTrue } -import zio.{ Chunk, Scope } +import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertTrue} +import zio.{Chunk, Scope} object DeriveSpec extends ZIOSpecDefault with VersionSpecificDeriveSpec { override def spec: Spec[TestEnvironment with Scope, Any] = @@ -174,6 +174,19 @@ object DeriveSpec extends ZIOSpecDefault with VersionSpecificDeriveSpec { .exists(a => a.isInstanceOf[fieldDefaultValue[_]] && a.asInstanceOf[fieldDefaultValue[Int]].value == 42) ) }, + test("use case class default values of generic class") { + val capturedSchema = Derive.derive[CapturedSchema, GenericRecordWithDefaultValue[Int]](schemaCapturer) + val annotations = capturedSchema.schema + .asInstanceOf[Schema.Record[GenericRecordWithDefaultValue[Int]]] + .fields(0) + .annotations + assertTrue { + annotations.exists { a => + a.isInstanceOf[fieldDefaultValue[_]] && + a.asInstanceOf[fieldDefaultValue[Option[Int]]].value == None + } + } + }, test("prefer field annotations over case class default values") { val capturedSchema = Derive.derive[CapturedSchema, RecordWithDefaultValue](schemaCapturer) val annotations = capturedSchema.schema @@ -304,6 +317,15 @@ object DeriveSpec extends ZIOSpecDefault with VersionSpecificDeriveSpec { implicit val schema: Schema[RecordWithDefaultValue] = DeriveSchema.gen[RecordWithDefaultValue] } + case class GenericRecordWithDefaultValue[T](int: Option[T] = None, @fieldDefaultValue(52) int2: Int = 42) + + object GenericRecordWithDefaultValue { + //explicitly Int, because generic implicit definition leads to "Schema derivation exceeded" error + implicit def schema: Schema[GenericRecordWithDefaultValue[Int]] = { + DeriveSchema.gen[GenericRecordWithDefaultValue[Int]] + } + } + sealed trait Enum1 object Enum1 {