diff --git a/docs/docs/reference/metaprogramming/macros.md b/docs/docs/reference/metaprogramming/macros.md index bbc8f97f2a00..d8dee3eb49d0 100644 --- a/docs/docs/reference/metaprogramming/macros.md +++ b/docs/docs/reference/metaprogramming/macros.md @@ -569,13 +569,13 @@ sum ### Find implicits within a macro Similarly to the `summonFrom` construct, it is possible to make implicit search available -in a quote context. For this we simply provide `scala.quoted.matching.searchImplicitExpr: +in a quote context. For this we simply provide `scala.quoted.matching.summonExpr: ```scala inline def setFor[T]: Set[T] = ${ setForExpr[T] } def setForExpr[T: Type](given QuoteContext): Expr[Set[T]] = { - searchImplicitExpr[Ordering[T]] match { + summonExpr[Ordering[T]] match { case Some(ord) => '{ new TreeSet[T]()($ord) } case _ => '{ new HashSet[T] } } diff --git a/library/src/scala/quoted/matching/package.scala b/library/src/scala/quoted/matching/package.scala index 334b18615e0f..3da7ab8c1445 100644 --- a/library/src/scala/quoted/matching/package.scala +++ b/library/src/scala/quoted/matching/package.scala @@ -10,7 +10,7 @@ package object matching { * @param tpe quoted type of the implicit parameter * @param qctx current context */ - def searchImplicitExpr[T](given tpe: Type[T], qctx: QuoteContext): Option[Expr[T]] = { + def summonExpr[T](given tpe: Type[T], qctx: QuoteContext): Option[Expr[T]] = { import qctx.tasty.{_, given} searchImplicit(tpe.unseal.tpe) match { case iss: ImplicitSearchSuccess => Some(iss.tree.seal.asInstanceOf[Expr[T]]) diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index aa11d80feb31..e82b16cc77b1 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -25,6 +25,6 @@ class Reflection(private[scala] val internal: CompilerInterface) with TypeOrBoundsOps { self => def typeOf[T: scala.quoted.Type]: Type = - implicitly[scala.quoted.Type[T]].unseal.tpe + summon[scala.quoted.Type[T]].unseal.tpe } diff --git a/tests/run-macros/quote-implicitMatch/Macro_1.scala b/tests/run-macros/quote-implicitMatch/Macro_1.scala index 1014571a5214..180ab11ef5b6 100644 --- a/tests/run-macros/quote-implicitMatch/Macro_1.scala +++ b/tests/run-macros/quote-implicitMatch/Macro_1.scala @@ -6,7 +6,7 @@ import scala.quoted.matching._ inline def f1[T]() = ${ f1Impl[T] } def f1Impl[T: Type](given QuoteContext) = { - searchImplicitExpr[Ordering[T]] match { + summonExpr[Ordering[T]] match { case Some(ord) => '{ new TreeSet[T]()($ord) } case _ => '{ new HashSet[T] } } @@ -18,7 +18,7 @@ class B inline def g = ${ gImpl } def gImpl(given QuoteContext) = { - if (searchImplicitExpr[A].isDefined) '{ println("A") } - else if (searchImplicitExpr[B].isDefined) '{ println("B") } + if (summonExpr[A].isDefined) '{ println("A") } + else if (summonExpr[B].isDefined) '{ println("B") } else throw new MatchError("") } diff --git a/tests/run-macros/string-context-implicits.check b/tests/run-macros/string-context-implicits.check new file mode 100644 index 000000000000..0b2f318366b4 --- /dev/null +++ b/tests/run-macros/string-context-implicits.check @@ -0,0 +1,4 @@ +Int(1) Str(abc) +Int(1) Str(abc) +xyz +Int(1) Str(xyz) diff --git a/tests/run-macros/string-context-implicits/Macro_1.scala b/tests/run-macros/string-context-implicits/Macro_1.scala new file mode 100644 index 000000000000..75ed31e932bc --- /dev/null +++ b/tests/run-macros/string-context-implicits/Macro_1.scala @@ -0,0 +1,31 @@ +import scala.quoted._ +import scala.quoted.matching._ + +inline def (sc: StringContext) showMe(args: =>Any*): String = ${ showMeExpr('sc, 'args) } + +private def showMeExpr(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(given qctx: QuoteContext): Expr[String] = { + argsExpr match { + case ExprSeq(argExprs) => + val argShowedExprs = argExprs.map { + case '{ $arg: $tp } => + val showTp = '[Show[$tp]] + summonExpr(given showTp, summon[QuoteContext]) match { + case Some(showExpr) => '{ $showExpr.show($arg) } + case None => qctx.error(s"could not find implicit for ${showTp.show}", arg); '{???} + } + } + val newArgsExpr = Expr.ofSeq(argShowedExprs) + '{ $sc.s($newArgsExpr: _*) } + case _ => + // `new StringContext(...).showMeExpr(args: _*)` not an explicit `showMeExpr"..."` + qctx.error(s"Args must be explicit", argsExpr) + '{???} + } +} + +trait Show[-T] { + def show(x: T): String +} + +given Show[Int] = x => s"Int($x)" +given Show[String] = x => s"Str($x)" diff --git a/tests/run-macros/string-context-implicits/Test_2.scala b/tests/run-macros/string-context-implicits/Test_2.scala new file mode 100644 index 000000000000..6de9a61c9cfa --- /dev/null +++ b/tests/run-macros/string-context-implicits/Test_2.scala @@ -0,0 +1,9 @@ +object Test { + + def main(args: Array[String]): Unit = { + println(showMe"${1: Int} ${"abc": String}") + println(showMe"${1} ${"abc"}") + println(showMe"${1} ${println("xyz"); "xyz"}") + } + +} diff --git a/tests/run/string-context-implicits-with-conversion.check b/tests/run/string-context-implicits-with-conversion.check new file mode 100644 index 000000000000..0b2f318366b4 --- /dev/null +++ b/tests/run/string-context-implicits-with-conversion.check @@ -0,0 +1,4 @@ +Int(1) Str(abc) +Int(1) Str(abc) +xyz +Int(1) Str(xyz) diff --git a/tests/run/string-context-implicits-with-conversion.scala b/tests/run/string-context-implicits-with-conversion.scala new file mode 100644 index 000000000000..338d05488daa --- /dev/null +++ b/tests/run/string-context-implicits-with-conversion.scala @@ -0,0 +1,24 @@ + +object Lib { + def (sc: StringContext) showMe(args: Showed*): String = sc.s(args: _*) + + opaque type Showed = String + + given [T](given show: Show[T]): Conversion[T, Showed] = x => show(x) + + trait Show[T] { + def apply(x: T): String + } + + given Show[Int] = x => s"Int($x)" + given Show[String] = x => s"Str($x)" +} +object Test { + import Lib._ + def main(args: Array[String]): Unit = { + println(showMe"${1: Int} ${"abc": String}") + println(showMe"${1} ${"abc"}") + println(showMe"${1} ${println("xyz"); "xyz"}") + } + +}