From f95a0a679a461252ae5fc47dfa0b17b7f7c2f7f3 Mon Sep 17 00:00:00 2001 From: Jan Chyb Date: Mon, 20 Jan 2025 17:14:14 +0100 Subject: [PATCH] Add documentation and test for indirect summons --- library/src/scala/quoted/Expr.scala | 11 ++++ library/src/scala/quoted/Quotes.scala | 10 ++++ .../summonIgnoring-nonrecursive.check | 3 ++ .../summonIgnoring-nonrecursive/Macro_1.scala | 50 +++++++++++++++++++ .../summonIgnoring-nonrecursive/Test_2.scala | 6 +++ .../stdlibExperimentalDefinitions.scala | 3 ++ 6 files changed, 83 insertions(+) create mode 100644 tests/run-macros/summonIgnoring-nonrecursive.check create mode 100644 tests/run-macros/summonIgnoring-nonrecursive/Macro_1.scala create mode 100644 tests/run-macros/summonIgnoring-nonrecursive/Test_2.scala diff --git a/library/src/scala/quoted/Expr.scala b/library/src/scala/quoted/Expr.scala index 5a687006979a..f9b291cf60fd 100644 --- a/library/src/scala/quoted/Expr.scala +++ b/library/src/scala/quoted/Expr.scala @@ -280,6 +280,17 @@ object Expr { } } + /** Find a given instance of type `T` in the current scope, + * while excluding certain symbols from the initial implicit search. + * Return `Some` containing the expression of the implicit or + * `None` if implicit resolution failed. + * + * @tparam T type of the implicit parameter + * @param ignored Symbols ignored during the initial implicit search + * + * @note if the found given requires additional search for other given instances, + * this additional search will NOT exclude the symbols from the `ignored` list. + */ @scala.annotation.experimental def summonIgnoring[T](using Type[T])(using quotes: Quotes)(ignored: quotes.reflect.Symbol*): Option[Expr[T]] = { import quotes.reflect._ Implicits.searchIgnoring(TypeRepr.of[T])(ignored*) match { diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 2794bedf8fdb..3baa0f198068 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3706,6 +3706,16 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => */ def search(tpe: TypeRepr): ImplicitSearchResult + /** Find a given instance of type `T` in the current scope provided by the current enclosing splice, + * while excluding certain symbols from the initial implicit search. + * Return an `ImplicitSearchResult`. + * + * @param tpe type of the implicit parameter + * @param ignored Symbols ignored during the initial implicit search + * + * @note if an found given requires additional search for other given instances, + * this additional search will NOT exclude the symbols from the `ignored` list. + */ @experimental def searchIgnoring(tpe: TypeRepr)(ignored: Symbol*): ImplicitSearchResult } diff --git a/tests/run-macros/summonIgnoring-nonrecursive.check b/tests/run-macros/summonIgnoring-nonrecursive.check new file mode 100644 index 000000000000..643b49550f62 --- /dev/null +++ b/tests/run-macros/summonIgnoring-nonrecursive.check @@ -0,0 +1,3 @@ +TC[C2] generated in macro using: +TC2[_] generated in macro using: +TC[C1] generated in macro diff --git a/tests/run-macros/summonIgnoring-nonrecursive/Macro_1.scala b/tests/run-macros/summonIgnoring-nonrecursive/Macro_1.scala new file mode 100644 index 000000000000..517513075458 --- /dev/null +++ b/tests/run-macros/summonIgnoring-nonrecursive/Macro_1.scala @@ -0,0 +1,50 @@ +//> using options -experimental +import scala.quoted._ +class C1 +trait TC[T] { + def print(): Unit +} + +object TC { + implicit transparent inline def auto[T]: TC[T] = ${autoImpl[T]} + def autoImpl[T: Type](using Quotes): Expr[TC[T]] = + import quotes.reflect._ + if (TypeRepr.of[T].typeSymbol == Symbol.classSymbol("C1")){ + '{ + new TC[T] { + def print() = { + println("TC[C1] generated in macro") + } + } + } + } else { + Expr.summonIgnoring[TC2[C1]](Symbol.classSymbol("TC").companionModule.methodMember("auto")*) match + case Some(a) => + '{ + new TC[T] { + def print(): Unit = + println(s"TC[${${Expr(TypeRepr.of[T].show)}}] generated in macro using:") + $a.print() + } + } + case None => + '{ + new TC[T]{ + def print(): Unit = + println(s"TC[${${Expr(TypeRepr.of[T].show)}}] generated in macro without TC2[_]") + } + } + } +} + +trait TC2[T] { + def print(): Unit +} + +object TC2 { + implicit def auto2[T](using tc: TC[T]): TC2[T] = new TC2[T] { + def print(): Unit = + println(s"TC2[_] generated in macro using:") + tc.print() + } +} \ No newline at end of file diff --git a/tests/run-macros/summonIgnoring-nonrecursive/Test_2.scala b/tests/run-macros/summonIgnoring-nonrecursive/Test_2.scala new file mode 100644 index 000000000000..e92a077d4719 --- /dev/null +++ b/tests/run-macros/summonIgnoring-nonrecursive/Test_2.scala @@ -0,0 +1,6 @@ +//> using options -experimental + +@main def Test(): Unit = { + class C2 + summon[TC[C2]].print() +} \ No newline at end of file diff --git a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 65e3a730ee7e..70c3e6b70fcb 100644 --- a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -66,6 +66,9 @@ val experimentalDefinitionInLibrary = Set( // Added for 3.6.0, stabilize after feedback. "scala.quoted.Quotes.reflectModule.SymbolModule.newBoundedType", "scala.quoted.Quotes.reflectModule.SymbolModule.newTypeAlias", + // Added for 3.7.0, stabilise after feedback + "scala.quoted.Quotes.reflectModule.ImplicitsModule.searchIgnoring", + "scala.quoted.Expr.summonIgnoring", // New feature: functions with erased parameters. // Need erasedDefinitions enabled.