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
cdinto the repo usinggit clone https://github.com/anatoliykmetyuk/dotty-macro-examples.git && cd dotty-macro-examples -
Use
./mill <example_name>.runcommand to run the example you are interested in. E.g../mill macroTypeClassDerivation.runrunsmacroTypeClassDerivationexample.
- 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
thiswhere the type ofthismay 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
SymbolandTerm. - referenceVariableFromOtherExpr - how to use a variable at an
Exprother than where it is defined at. - reflectionLambda - how to create a lambda via TASTy Reflection.
- 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 XMethodswhich defines all of the methods you can call onX. For example, forSymbol, you can search forSymbolMethodsinQuotes.scalato 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
Symbols. To get aSymbolgiven atpe: quoted.Type[T], useTypeTree.of[T].symbol. - If you have a
Symbol, you can useRefto get aTreereferring to that symbol – eitherIdentorSelect. For example, if you have asym: Symbolthat refers to aDefDefmethod definition and you want to obtain a tree referring to that method, you can get this tree viaRef(sym).