Skip to content

Commit

Permalink
Deriver fixes (#436)
Browse files Browse the repository at this point in the history
* Scala 3 only convenience method on Deriver to derive

* Do not summon implicit on top level in Scala 2 deriver

* Do not summon implicit on top level in Scala 3 deriver

* Fix high arity tuple support in deriver

* Support for unknown types

* ScalaFix

* Fix

* ScalaFix again
  • Loading branch information
vigoo authored Nov 18, 2022
1 parent 86870f7 commit a2df319
Show file tree
Hide file tree
Showing 8 changed files with 5,122 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ object Derive {
def toTupleSchemaType(tpes: Chunk[Type]): Tree =
tpes.tail.foldLeft(tq"${tpes.head}") { case (xs, x) => tq"_root_.zio.schema.Schema.Tuple2[$xs, $x]" }

def lefts(tschema: Tree, tpes: Chunk[Type]): Tree =
if (tpes.size < 2) tschema
else lefts(q"$tschema.left.asInstanceOf[${toTupleSchemaType(tpes)}]", tpes.init)
def lefts(tschema: Tree, tpes: Chunk[Type], depth: Int): Tree =
if (tpes.size < 2 || depth == 0) tschema
else lefts(q"$tschema.left.asInstanceOf[${toTupleSchemaType(tpes)}]", tpes.init, depth - 1)

def recurse(tpe: Type, schema: c.Tree, stack: List[Frame[c.type]]): Tree =
def recurse(tpe: Type, schema: c.Tree, stack: List[Frame[c.type]], top: Boolean): Tree =
stack.find(_.tpe =:= tpe) match {
case Some(f @ Frame(_, ref, _)) =>
if (f == stack.head)
Expand All @@ -116,7 +116,7 @@ object Derive {
val typeClassTpe = weakTypeOf[F[_]]
val appliedTpe = appliedType(typeClassTpe, tpe)
val appliedStandardTpe = appliedType(standardTypeTpe, tpe)
val summonedTree = c.inferImplicitValue(appliedTpe)
val summonedTree = if (top) EmptyTree else c.inferImplicitValue(appliedTpe)
val summoned = if (summonedTree == EmptyTree) q"None" else q"Some[$appliedTpe]($summonedTree)"

val selfRefName = c.freshName("instance")
Expand All @@ -140,15 +140,15 @@ object Derive {
if (idx == n) {
q"$tschema.right"
} else if (idx == 1) {
q"${lefts(q"$tschema", tpes.take(2))}.left"
q"${lefts(q"$tschema", tpes.init, n - 1)}.left"
} else {
q"${lefts(q"$tschema", tpes.take(idx))}.right"
q"${lefts(q"$tschema", tpes.init, n - idx)}.right"
}
}

val instances = tpes.zip(schemas).map {
case (t, schema) =>
recurse(concreteType(tpe, t), schema, stack)
recurse(concreteType(tpe, t), schema, stack, top = false)
}

val flatTupleType = tpe
Expand All @@ -172,7 +172,7 @@ object Derive {
} else if (tpe <:< optionTpe) {
val innerTpe = tpe.typeArgs.head
val innerSchema = q"$schemaRef.schema"
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack)
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack, top = false)
q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Optional[$innerTpe]]
lazy val $selfRefWithType = $deriver.deriveOption[$innerTpe]($schemaRef, $innerInstance, $summoned)
Expand All @@ -181,7 +181,7 @@ object Derive {
} else if (tpe <:< listTpe) {
val innerTpe = tpe.typeArgs.head
val innerSchema = q"$schemaRef.elementSchema"
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack)
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack, top = false)
q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Sequence[${appliedType(
listTpe,
Expand All @@ -193,7 +193,7 @@ object Derive {
} else if (tpe <:< vectorTpe) {
val innerTpe = tpe.typeArgs.head
val innerSchema = q"$schemaRef.elementSchema"
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack)
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack, top = false)
q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Sequence[${appliedType(
vectorTpe,
Expand All @@ -205,7 +205,7 @@ object Derive {
} else if (tpe <:< chunkTpe) {
val innerTpe = tpe.typeArgs.head
val innerSchema = q"$schemaRef.elementSchema"
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack)
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack, top = false)
q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Sequence[${appliedType(
chunkTpe,
Expand All @@ -217,7 +217,7 @@ object Derive {
} else if (tpe <:< setTpe) {
val innerTpe = tpe.typeArgs.head
val innerSchema = q"$schemaRef.elementSchema"
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack)
val innerInstance = recurse(concreteType(tpe, innerTpe), innerSchema, currentFrame +: stack, top = false)
q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Set[$innerTpe]]
lazy val $selfRefWithType = $deriver.deriveSet[$innerTpe]($schemaRef, $innerInstance, $summoned)
Expand All @@ -230,8 +230,8 @@ object Derive {
val leftSchema = q"$schemaRef.left"
val rightSchema = q"$schemaRef.right"

val leftInstance = recurse(concreteType(tpe, leftTpe), leftSchema, currentFrame +: stack)
val rightInstance = recurse(concreteType(tpe, rightTpe), rightSchema, currentFrame +: stack)
val leftInstance = recurse(concreteType(tpe, leftTpe), leftSchema, currentFrame +: stack, top = false)
val rightInstance = recurse(concreteType(tpe, rightTpe), rightSchema, currentFrame +: stack, top = false)

q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Either[$leftTpe, $rightTpe]]
Expand All @@ -245,8 +245,8 @@ object Derive {
val leftSchema = q"$schemaRef.left"
val rightSchema = q"$schemaRef.right"

val leftInstance = recurse(concreteType(tpe, leftTpe), leftSchema, currentFrame +: stack)
val rightInstance = recurse(concreteType(tpe, rightTpe), rightSchema, currentFrame +: stack)
val leftInstance = recurse(concreteType(tpe, leftTpe), leftSchema, currentFrame +: stack, top = false)
val rightInstance = recurse(concreteType(tpe, rightTpe), rightSchema, currentFrame +: stack, top = false)

q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Tuple2[$leftTpe, $rightTpe]]
Expand Down Expand Up @@ -305,7 +305,12 @@ object Derive {
val fieldInstances = fields.zipWithIndex.map {
case (termSymbol, idx) =>
val fieldSchema = q"$recordSchemaRef.fields($idx).schema"
val f = recurse(concreteType(tpe, termSymbol.typeSignature), fieldSchema, currentFrame +: stack)
val f = recurse(
concreteType(tpe, termSymbol.typeSignature),
fieldSchema,
currentFrame +: stack,
top = false
)
q"_root_.zio.schema.Deriver.wrap($f)"
}

Expand All @@ -318,7 +323,12 @@ object Derive {
val fieldInstances = fields.zipWithIndex.map {
case (termSymbol, idx) =>
val fieldSchema = q"$schemaRef.fields($idx).schema"
val f = recurse(concreteType(tpe, termSymbol.typeSignature), fieldSchema, currentFrame +: stack)
val f = recurse(
concreteType(tpe, termSymbol.typeSignature),
fieldSchema,
currentFrame +: stack,
top = false
)
q"_root_.zio.schema.Deriver.wrap($f)"
}

Expand All @@ -335,7 +345,7 @@ object Derive {
val subtypeInstances = subtypes.zipWithIndex.map {
case (subtype, idx) =>
val subtypeSchema = q"$schemaRef.cases($idx).schema"
val f = recurse(subtype, subtypeSchema, currentFrame +: stack)
val f = recurse(subtype, subtypeSchema, currentFrame +: stack, top = false)
q"_root_.zio.schema.Deriver.wrap($f)"
}
q"""{
Expand All @@ -350,22 +360,20 @@ object Derive {
val keySchema = q"$schemaRef.keySchema"
val valueSchema = q"$schemaRef.valueSchema"

val keyInstance = recurse(concreteType(tpe, keyTpe), keySchema, currentFrame +: stack)
val valueInstance = recurse(concreteType(tpe, valueTpe), valueSchema, currentFrame +: stack)
val keyInstance = recurse(concreteType(tpe, keyTpe), keySchema, currentFrame +: stack, top = false)
val valueInstance = recurse(concreteType(tpe, valueTpe), valueSchema, currentFrame +: stack, top = false)

q"""{
lazy val $schemaRef = $forcedSchema.asInstanceOf[_root_.zio.schema.Schema.Map[$keyTpe, $valueTpe]]
lazy val $selfRefWithType = $deriver.deriveMap[$keyTpe, $valueTpe]($schemaRef, $keyInstance, $valueInstance, $summoned)
$selfRef
}"""
} else
c.abort(
c.enclosingPosition,
s"Failed to derive type class for $tpe"
)
q"""$deriver.deriveUnknown[$tpe]($summoned)"""
}

val tree = recurse(weakTypeOf[A], schema.tree, List.empty[Frame[c.type]])
val tree = recurse(weakTypeOf[A], schema.tree, List.empty[Frame[c.type]], top = true)
//println(tree)
tree
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package zio.schema

trait VersionSpecificDeriver[F[_]] {}
Loading

0 comments on commit a2df319

Please sign in to comment.