Macros in Scala 3

FAQ

Language
This doc page is specific to Scala 3, and may cover new concepts not available in Scala 2. Unless otherwise stated, all the code examples in this page assume you are using Scala 3.

Which should I use Expr(...) or '{...}?

If you can write your code using Expr(...), you will evaluate more at compile time. Only use '{...} if you really need to evaluate the code later at runtime, usually because it depends on runtime values.

Which is better between Expr(true) or '{true}?

All quotes containing a value of a primitive type is optimised to an Expr.apply. Choose one in your project and stick with a single notation to avoid confusion.

How do I get a value out of an Expr?

If the expression represents a value, you can use .value, .valueOrAbort or Expr.unapply

How can I get the precise type of an Expr?

We can get the precise type (Type) of an Expr using the following pattern match:

val x: Expr[X] = ...
x match
  case '{ $x: t } =>
    // `x: Expr[X & t]` where `t` is the precise type of `x`

How do I summon all types of a tuple type?

If I have a type (T1, T2, ...) how do I generate the term for (summon[T1], summon[T2], ...) or get the individual expressions with the summoned values?

Depending on your use case the way you will summon them will vary. In particular, the code you will need depends on the kind of output you want (Expr[Tuple], List[Expr[Any]], or something else) and how you need errors to be reported. Here are two examples that should give you the basic skeleton for two different variant of this code.

  def summonAllInList[T](using Type[T])(using Quotes): List[Expr[Any]] = {
    Type.of[T] match
      case '[ head *: tail ] =>
        Expr.summon[head] match
          case Some(headExpr) => headExpr :: summonAllInList[tail]
          case _ => quotes.reflect.report.throwError(s"Could not summon ${Type.show[head]}")
      case '[ EmptyTuple ] => Nil
      case _ => quotes.reflect.report.throwError(s"Could not `summonAllInList` of tuple with unknown size: ${Type.show[T]}")
  }
  def summonAll[T](using Type[T])(using Quotes): Option[Expr[Tuple]]] = {
    Type.of[T] match
      case '[ head *: tail ] =>
        for headExpr <- Expr.summon[head]
            tailExpr <- summonAll[tail]
        yield '{ headExpr *: tailExpr }
      case '[ EmptyTuple ] => Some('{ EmptyTuple })
      case _ => None
  }

How do I summon an expression for statically unknown types?

You can summon an expression from either a TypeRepr or a Type as shown below.

If you have a TypeRepr use:

val tpe: TypeRepr = ...
Implicits.search(tpe) match
  case result: ImplicitSearchSuccess => result.tree
  case _ =>

Instead, if you have a Type[_] use:

val tpe: Type[_] = ...
tpe match
  // (1) Use `a` as the name of the unknown type and (2) bring a given `Type[a]` into scope
  case '[a] => Expr.summon[a]

Contributors to this page: