-
Notifications
You must be signed in to change notification settings - Fork 1.1k
How to use TypeDef.apply reflect API to create a type alias? #19344
-
Here is the TypeDef
API exposed by the reflect API:
/** Methods of the module object `val TypeDef` */ trait TypeDefModule { this: TypeDef.type => def apply(symbol: Symbol): TypeDef def copy(original: Tree)(name: String, rhs: Tree): TypeDef def unapply(tdef: TypeDef): (String, Tree) }
How can I get a type symbol for a type alias to use TypeDef.apply
?
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 5 comments 9 replies
-
This is blocking migrating cats-tagless to Scala 3:typelevel/cats-tagless#442
Beta Was this translation helpful? Give feedback.
All reactions
-
How can I get a type symbol for a type alias to use TypeDef.apply?
You can get it from an existing type alias. We currently do not have a method to create new type symbol. We might want to add this as Symbol.newType
or Symbol.newTypeAlias
.
Beta Was this translation helpful? Give feedback.
All reactions
-
Follow #19448
Beta Was this translation helpful? Give feedback.
All reactions
-
I think this would be also very useful for macro annotations. Where you might actually want to provide a RHS for the TypeDef
.
E.g. we could create a macro annotation in shapeless 3 to generate kinds: typelevel/shapeless-3#204
Beta Was this translation helpful? Give feedback.
All reactions
-
You can get it from an existing type alias.
I need to forward a type alias, so I need to define the RHS somehow like this:
type T[A1, ..., An] = x.T[A1, ..., An]
I guess that doesn't qualify as an existing type alias?
Beta Was this translation helpful? Give feedback.
All reactions
-
Alternatively it would work if I could create export x.T
in the reflection API but that's also not possible
Beta Was this translation helpful? Give feedback.
All reactions
-
I am missing some context. What are you trying to implement with this?
Beta Was this translation helpful? Give feedback.
All reactions
-
A trait which has a type member
Beta Was this translation helpful? Give feedback.
All reactions
-
Also TypeRepr.contains
is missing - how can I check if a type contains a particular type symbol?
Beta Was this translation helpful? Give feedback.
All reactions
-
My workaround:
extension (tpe: TypeRepr) def contains(sym: Symbol): Boolean = tpe != tpe.substituteTypes(sym :: Nil, TypeRepr.of[Any] :: Nil)
Beta Was this translation helpful? Give feedback.
All reactions
-
Usually I would just go through the whole of the TypeRepr ADT, something like this:
def containsSymbol(using quotes: Quotes)(typeRepr: quotes.reflect.TypeRepr, sym: quotes.reflect.Symbol): Boolean = import quotes.reflect._ def containsIn(typeRepr: TypeRepr): Boolean = (typeRepr.typeSymbol == sym) || (typeRepr match case AppliedType(tycon, args) => containsIn(tycon) || args.contains(containsIn(_)) case AndType(tpe1, tpe2) => containsIn(tpe1) || containsIn(tpe2) case OrType(tpe1, tpe2) => containsIn(tpe1) || containsIn(tpe2) case SuperType(thisTpe, superType) => containsIn(thisTpe) || containsIn(superType) case Refinement(parent, _, info) => containsIn(parent) || containsIn(parent) // (...) not all cases implemented case _ => false ) containsIn(typeRepr)
It probably seems a bit much looking at it, but something like this could be integrated into a some kind of macro utils library outside of the compiler. May I ask for a use case? Usually I would need to know precisely where that symbol is (and not only whether it can be found there at all), thus the adt method. I suspect the reason TypeRepr.contains(Symbol)
is not in the API might be that no one asked for it before
Beta Was this translation helpful? Give feedback.
All reactions
-
Here is my use case: https://github.com/typelevel/cats-tagless/blob/master/core%2Fsrc%2Fmain%2Fscala-3%2Fcats%2Ftagless%2Fmacros%2FmacroFunctorK.scala
I don't need to know where it is because I substitute it with a type lambda's parameter.
Beta Was this translation helpful? Give feedback.
All reactions
-
Another issue that I have is term.select(sym)
doesn't handle overloads. I think it should be using selectWithSig
under the hood or else I need access to selectWithSig
. If I'm giving it a symbol I know which overload I want, it would be really hard to come up with the correct arguments to Select.overloaded
.
Beta Was this translation helpful? Give feedback.
All reactions
-
For reference, here are the gymnastics necessary:
extension (term: Term) def appliedToAll(argss: List[List[Tree]]): Term = argss.foldLeft(term): (term, args) => val typeArgs = for case arg: TypeTree <- args yield arg val termArgs = for case arg: Term <- args yield arg if typeArgs.isEmpty then term.appliedToArgs(termArgs) else term.appliedToTypeTrees(typeArgs) def call(method: Symbol)(argss: List[List[Tree]]): Term = argss match case args1 :: args2 :: argss if !args1.exists(_.isExpr) && args2.forall(_.isExpr) => val typeArgs = for case arg: TypeTree <- args1 yield arg.tpe val termArgs = for case arg: Term <- args2 yield arg Select.overloaded(term, method.name, typeArgs, termArgs).appliedToAll(argss) case args :: argss if !args.exists(_.isExpr) => val typeArgs = for case arg: TypeTree <- args yield arg.tpe Select.overloaded(term, method.name, typeArgs, Nil).appliedToAll(argss) case args :: argss if args.forall(_.isExpr) => val termArgs = for case arg: Term <- args yield arg Select.overloaded(term, method.name, Nil, termArgs).appliedToAll(argss) case argss => term.select(method).appliedToAll(argss)
Beta Was this translation helpful? Give feedback.