After a short break for Passover, I am back and attempting to implement SchemaMeta
for Dotty-Quill, this requires more usage of Quoted Matching in some new ways and revisits some current issues.
-
My only real show-stopper is this: https://github.com/lampepfl/dotty/issues/8745.
It involves an issue where Dotty throws a Class Cast Exception whenever one attempts to match a method on a traitT
that was then extended into anobject O extends T
and statically imported viaimport O._
. This is howschemaMeta
,queryMeta
,insertMeta
andupdateMeta
all work. It’s very important to get this fixed otherwise everyone is going to have to doQueryDsl.schemaMeta
instead ofschemaMeta
everywhere. -
Quoted Matching is generally nicer then quasi-quotes but certain use-cases are not possible by design. For example, quasi-quotes allowed the matching of aribtrary selections
case q"$a.$b" =>
without requiring any knowledge of what$a
's type, we use this in Quill when parsing Query-Schema property mappings. This kind of functionality is intentially prohibited with Quoted Matching because it offers zero type safety (i.e. how the heck do you know$b
is available on$a
!?) however, the underlying Tasty-Reflect API can still be used to get this kind of behavior e.g:case Select(a, b) =>
, you just need to unseal theExpr[_]
into aTerm
first. -
I initially expected Quoted Matching to allow the same kinds of sugar as standard Scala. For example, matching
o.map(func)
(whereo
is aOption[T]
) could be done either in via the regularcase '{ $o.map[$t]($func) }` =>
as well as the shortened:
case '{ $o.map($func) }` =>
With the advent of #8695 this is finally possible! This is very exciting since the requirment of specifying all types is very unintuitive.
-
Matching a higher-order function as well as it’s lambda argument is currently not possible with Quoted Matching.
case '{ (o: Option[String]).map[$ot](($x: String) => $out) } => // does not match
Whereas using qusai-quotes it is:
case q"o.map($x => $out)" => // works!
Additionally, using the
$x
variable in a quoted match causes a Not-Found exception. I think this behavior is a bug: #8749.
This is not a show-stopper because I can work around it using theLambda(...)
matcher from Tasty-Reflect or matching on aDefDef
tree directly. -
Re-declaring a type via a type-ascription that has already been defined will cause an exception. For example, matching this:
object FunObject { def fun[T](t: T => String) = t } matchMacro(fun((x: String) => x.toUpperCase))
… by doing this:
case '{ FunObject.fun[$tt](($arg: $ttt) => $out) } =>
Will blow up because
$arg
is of type$tt
, not$ttt
!@bishabosha had a great solution for this issue:
case 'type $tt; { FunObject.fun[`$tt`](($arg: `$tt`) => $out) } =>
I would use this pattern throughout my codebase if it wasn’t for #8749.
-
In general, Quoted Matching is still rough around the edges and needs a little bit of production hardening. It is still relatively easy to get it to break (e.g. see my first issue #8745) or to freeze up the compiler e.g: #8746. However, I still firmly believe that it is a substantial improvement over quasi-quotes.
Thank you @biboudis, @liufengyun, @nicolasstucki, and @smarter for all of the assistance you have provided me up to this point as well as for your continuing help. It has been quite a challenge re-architecting Quill to Dotty paradigms but the light at the end of the tunnel is brighter every day!