Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How to use TypeDef.apply reflect API to create a type alias? #19344

Unanswered
joroKr21 asked this question in Metaprogramming
Discussion options

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?

You must be logged in to vote

Replies: 5 comments 9 replies

Comment options

joroKr21
Jan 14, 2024
Collaborator Author

This is blocking migrating cats-tagless to Scala 3:typelevel/cats-tagless#442

You must be logged in to vote
0 replies
Comment options

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.

You must be logged in to vote
2 replies
Comment options

Follow #19448

Comment options

joroKr21 Mar 25, 2024
Collaborator Author

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

Comment options

joroKr21
Jan 15, 2024
Collaborator Author

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?

You must be logged in to vote
3 replies
Comment options

joroKr21 Jan 15, 2024
Collaborator Author

Alternatively it would work if I could create export x.T in the reflection API but that's also not possible

Comment options

I am missing some context. What are you trying to implement with this?

Comment options

joroKr21 Jan 15, 2024
Collaborator Author

A trait which has a type member

Comment options

joroKr21
Mar 24, 2024
Collaborator Author

Also TypeRepr.contains is missing - how can I check if a type contains a particular type symbol?

You must be logged in to vote
3 replies
Comment options

joroKr21 Mar 25, 2024
Collaborator Author

My workaround:

 extension (tpe: TypeRepr)
 def contains(sym: Symbol): Boolean =
 tpe != tpe.substituteTypes(sym :: Nil, TypeRepr.of[Any] :: Nil)
Comment options

jchyb Mar 29, 2024
Collaborator

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

Comment options

joroKr21 Mar 30, 2024
Collaborator Author

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.

Comment options

joroKr21
May 21, 2024
Collaborator Author

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.

You must be logged in to vote
1 reply
Comment options

joroKr21 May 21, 2024
Collaborator Author

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /