-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Summoning a typeclass in a macro #12404
-
(from gitter)
I'm having a slight problem understanding the behaviour of summoning in macro. I have a method which takes a given parameter (def myMethod[T: MyTypeclass]
), I can use it in a macro as follows:
'{myMethod[f](${Expr.summon[MyTypeclass[f]].get})}
the f here is a type of a case class field, and the type parameter is obtained using the field.tpe.asType match case '[f] => ... trick
, though I don't think that's relevant here. The important part is that I have a Type[f]
instance.
So for a concrete invocation we have e.g. f == String
and the appropriate typeclass is summoned.
However, if I do either:
'{myMethod[f]} // or
'{myMethod[tf.Underlying]} // where tf: Type[f]
I get an error, that a given MyTypeclass[f]
cannot be found (with the abstract type f
/tf.Underlying
, instead of the concrete one). Why do I have to spell out the givens explicitly?
Beta Was this translation helpful? Give feedback.
All reactions
Could you show a complete example? This might be a bug.
Replies: 2 comments 7 replies
-
Could you show a complete example? This might be a bug.
Beta Was this translation helpful? Give feedback.
All reactions
-
Thanks. Though I don't really understand why during typechecking of the quoted code '{myMethod[T]}
dotty tries to search for MyTypeclass[T]
instead of MyTypeclass[String]
(where at invocation-site, we have T == String
)?
If I'm understanding the docs correctly, the T
in '{myMethod[T]}
is in fact a splice - sth like an equivalent of '{myMethod[${summon[Type[T]].Underlying}]}
. So I'd expect the T
to be substituted with String
before the typechecking is done - and hence having the correct implicit instance looked up.
Beta Was this translation helpful? Give feedback.
All reactions
-
Though I don't really understand why during typechecking of the quoted code '{myMethod[T]} dotty tries to search for MyTypeclass[T] instead of MyTypeclass[String] (where at invocation-site, we have T == String)?
'{myMethod[T]}
is type-checked in testImpl
where we do not know the concrete type of T
. It is not type-checked at the invocation site.
Beta Was this translation helpful? Give feedback.
All reactions
-
'{myMethod[T]} is type-checked in testImpl where we do not know the concrete type of T. It is not type-checked at the invocation site.
Ok, thanks, though I'm still confused ;) I thought that the T
in there is an incognito splice of whatever is represented by the implicit Type[T]
, which would mean that we know very well what's the concrete type. I'll re-read the docs :)
Beta Was this translation helpful? Give feedback.
All reactions
-
Long story short:
- We type check
'{myMethod[T]}
usingT
and the knowledge of its bounds (>: Nothing <: Any
in this case) - When we expand the macro with
T =:= String
we simply replaceT
withString
. No need to retype check.
Beta Was this translation helpful? Give feedback.
All reactions
-
Thanks, my mental model which assumed T
meant +/- $T
(splicing) was wrong then. Or maybe not wrong, but it happens later - typechecking comes first, and splicing happens only after that's done. Thanks again for the patience :)
Beta Was this translation helpful? Give feedback.
All reactions
-
Use compiletime.summonInline. This delays the search until after the macro is expanded.
That doesn't sound quite true. It looks like summonInline
is expanded earlier in some cases.
See the discussion here: typelevel/cats-tagless#556 (comment)
In this case we are transforming a trait inside the macro:
trait ShowFAlgebra[F[_]]: def showF[A: Show](a: A): F[String] def showAll[A: Show](as: A*): F[String] def showProduct[A: Show](a: A): F[(A, String)] def logF[A: Show](message: => A): F[Unit] object ShowFAlgebra: given Aspect.Function[ShowFAlgebra, Show] = Derive.aspect
But inside the Derive.aspect
macro, when we are generating the body of methods like showF
, we can't access the Show[A]
from the implicit parameters of the method itself.
Beta Was this translation helpful? Give feedback.