Skip to content

Commit 6d3fe1d

Browse files
Merge pull request #7728 from dotty-staging/add-macro-docs
Add docs on getting precise type within quotes
2 parents 2d2d3c0 + 7dd089d commit 6d3fe1d

File tree

3 files changed

+46
-2
lines changed

3 files changed

+46
-2
lines changed

docs/docs/reference/metaprogramming/macros.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,50 @@ private def sumExpr(args1: Seq[Expr[Int]])(given QuoteContext): Expr[Int] = {
689689
}
690690
```
691691

692+
#### Recovering precise types using patterns
693+
694+
Sometimes it is necessary to get a more precise type for an expression. This can be achived using the following pattern match.
695+
696+
```scala
697+
def f(exp: Expr[Any]) =
698+
expr match
699+
case '{ $x: $t } =>
700+
// If the pattern match succeeds, then there is some type `T` such that
701+
// - `x` is bound to a variable of type `Expr[T]`
702+
// - `t` is bound to a given instance of type `Type[T]`
703+
// That is, we have `x: Expr[T]` and `given t: Type[T]`, for some (unknown) type `T`.
704+
```
705+
706+
This might be used to then perform an implicit search as in:
707+
708+
709+
```scala
710+
inline def (sc: StringContext) showMe(args: =>Any*): String = ${ showMeExpr('sc, 'args) }
711+
712+
private def showMeExpr(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(given qctx: QuoteContext): Expr[String] = {
713+
argsExpr match {
714+
case ExprSeq(argExprs) =>
715+
val argShowedExprs = argExprs.map {
716+
case '{ $arg: $tp } =>
717+
val showTp = '[Show[$tp]]
718+
summonExpr(given showTp)) match {
719+
case Some(showExpr) => '{ $showExpr.show($arg) }
720+
case None => qctx.error(s"could not find implicit for ${showTp.show}", arg); '{???}
721+
}
722+
}
723+
val newArgsExpr = Expr.ofSeq(argShowedExprs)
724+
'{ $sc.s($newArgsExpr: _*) }
725+
case _ =>
726+
// `new StringContext(...).showMeExpr(args: _*)` not an explicit `showMeExpr"..."`
727+
qctx.error(s"Args must be explicit", argsExpr)
728+
'{???}
729+
}
730+
}
731+
732+
trait Show[-T] {
733+
def show(x: T): String
734+
}
735+
```
692736

693737
### More details
694738
[More details](./macros-spec.md)

library/src/scala/quoted/matching/package.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ package object matching {
1010
* @param tpe quoted type of the implicit parameter
1111
* @param qctx current context
1212
*/
13-
def summonExpr[T](given tpe: Type[T], qctx: QuoteContext): Option[Expr[T]] = {
13+
def summonExpr[T](given tpe: Type[T])(given qctx: QuoteContext): Option[Expr[T]] = {
1414
import qctx.tasty.{_, given}
1515
searchImplicit(tpe.unseal.tpe) match {
1616
case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[Expr[T]])

tests/run-macros/string-context-implicits/Macro_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ private def showMeExpr(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(given
99
val argShowedExprs = argExprs.map {
1010
case '{ $arg: $tp } =>
1111
val showTp = '[Show[$tp]]
12-
summonExpr(given showTp, summon[QuoteContext]) match {
12+
summonExpr(given showTp) match {
1313
case Some(showExpr) => '{ $showExpr.show($arg) }
1414
case None => qctx.error(s"could not find implicit for ${showTp.show}", arg); '{???}
1515
}

0 commit comments

Comments
 (0)