-
-
Notifications
You must be signed in to change notification settings - Fork 248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Codegen: Support union types as scala 3 union types #1926
Comments
I gave this a go some time ago and failed miserably, albeit my knowledge of macros goes as far as I can google things. Also things might have changed in the compiler since then. If you can make this work it'd be awesome :) |
I think I can make it work. Progress so far: Calling the macro like this: type A = Int | String | Types.QueryHeroArgs
Foo.typeAliasSchema[A]
gives this data: {
starwars.generated.Foo.TypeAndSchema.apply[scala.Int]("scala.Int", caliban.schema.Schema.intSchema)
starwars.generated.Foo.TypeAndSchema.apply[scala.Predef.String]("java.lang.String", caliban.schema.Schema.stringSchema)
starwars.generated.Foo.TypeAndSchema.apply[starwars.generated.Types.QueryHeroArgs]("starwars.generated.Types.QueryHeroArgs", starwars.generated.Types.QueryHeroArgs.derived$SemiAuto)
} It's obviously not in the correct shape yet, but I managed to pick apart the type union and resolve Code so far: case class TypeAndSchema[T](typeRef: String, schema: Schema[Any, T])
inline def typeAliasSchema[T]: TypeAndSchema[?] = ${ mirrorFieldsImpl[T] }
def mirrorFieldsImpl[T: Type](using Quotes): Expr[TypeAndSchema[?]] = {
import quotes.reflect.* // Import `Tree`, `TypeRepr`, `Symbol`, `Position`, .....
def rec[TT](using tpe: Type[TT]): List[Expr[TypeAndSchema[?]]] = TypeRepr.of(using tpe).dealias match {
case OrType(l, r) =>
quotes.reflect.report.warning(s"union ${l.show} | ${r.show}")
rec(using l.asType.asInstanceOf[Type[Any]]) ++ rec(using r.asType.asInstanceOf[Type[Any]])
case otherRepr =>
val otherString = otherRepr.show
val expr: Expr[TypeAndSchema[TT]] =
Expr.summon[Schema[Any, TT]] match {
case Some(found) =>
'{ TypeAndSchema[TT](${ Expr(otherString) }, ${found}) }
case None =>
quotes.reflect.report.errorAndAbort(s"Couldn't resolve Schema[Any, $otherString]")
}
List(expr)
}
val exprs = rec[T]
val expr = Expr.block(exprs.init, exprs.last)
quotes.reflect.report.errorAndAbort(expr.show)
expr
}
|
this library likely contains what we need https://github.com/iRevive/union-derivation |
With namespacing gone after #1925, we're quite close to being able to output union types as union types.
The remaining issue is basically this:
That's true. But, and I'm on very thin ice here, I think we can write a macro which pattern matches on the union type, picks out all the members and
summonAll
sSchema
s for them.Then we need to generate some code like this:
Originally posted by @oyvindberg in #1925 (comment)
The text was updated successfully, but these errors were encountered: