Scala 3 Metaprogramming Examples
This repo contains a bunch of examples of doing metaprogramming in Scala 3 using the low level reflection API.
Every folder is a separate example. Each example contains a README.md file with a description of what the example does.
To run an example:
-
Clone and
cd
into the repo usinggit clone https://github.com/anatoliykmetyuk/dotty-macro-examples.git && cd dotty-macro-examples
-
Use
./mill <example_name>.run
command to run the example you are interested in. E.g../mill macroTypeClassDerivation.run
runsmacroTypeClassDerivation
example.
Examples
- abstractTypeclassBody β how to abstract a body of a function inside a macro-generated class into a separate macro.
- accessMembersByName β access an arbitrary member of a value given this member's name as a
String
. - accessEnclosingParameters - access the arguments passed to the enclosing method of the macro call.
- defaultParamsInference β given a case class with default parameters, obtain the values of these default parameters.
- fullClassName - get a fully qualified name of a class.
- isMemberOfSealedTraitHierarchy - check if a class inherits from a sealed trait.
- macroTypeClassDerivation β typeclass construction done with Quotes Reflection.
- outOfScopeMethodCall β get a reference to
this
where the type ofthis
may not be known on macro definition site, and call a method onthis
. - outOfScopeTypeParam β get a reference to a type that is not available to the macro definition's scope. Then use this reference as a type parameter to call a method.
- outOfScopeClassConstructor β get a reference to a type that is not available to the macro definition's scope. Then use this reference to construct an instance of that type via
new
. - buildingCustomASTs β Quotes Reflection ASTs are powerful, but how do you know the right way to build one? This example demonstrates how to inspect compiler-generated ASTs for a given Scala code. You can then mimic the compiler when constructing similar ASTs.
- contextParamResolution β showcases how to use Quotes Reflection to construct an AST for a method call that takes context parameters. Shows how to resolve those parameters using Quotes Reflection API.
- passVarargsIntoAST - showcases how to pass varargs as parameters into the AST of the method
- primaryConstructor - showcases how to use primary constructor
Symbol
andTerm
. - referenceVariableFromOtherExpr - how to use a variable at an
Expr
other than where it is defined at. - reflectionLambda - how to create a lambda via TASTy Reflection.
Tips and Tricks
- When working with reflect API, all of the API available to you is defined in the
dotty/library/src/scala/quoted/Quotes.scala
. As a rule, for every reflected typeX
, you have a group of extension methods intrait XMethods
which defines all of the methods you can call onX
. For example, forSymbol
, you can search forSymbolMethods
inQuotes.scala
to see what you can do with it. TypeTree.of[T]
gives you aquotes.reflect.TypeTree
. To get aquotes.reflect.TypeRepr
, you can callTypeRepr.of[T]
.- Most of the interesting data about the types reside in their
Symbol
s. To get aSymbol
given atpe: quoted.Type[T]
, useTypeTree.of[T].symbol
. - If you have a
Symbol
, you can useRef
to get aTree
referring to that symbol β eitherIdent
orSelect
. For example, if you have asym: Symbol
that refers to aDefDef
method definition and you want to obtain a tree referring to that method, you can get this tree viaRef(sym)
.