From 77d3f4be3c71f07485219c0b7b830c616a892419 Mon Sep 17 00:00:00 2001 From: Roman Janusz Date: Sun, 26 Jan 2025 01:01:53 +0100 Subject: [PATCH 1/3] added apply methods to import selectors in Quotes #21225 --- .../src/scala/quoted/runtime/impl/QuotesImpl.scala | 11 +++++++++++ library/src/scala/quoted/Quotes.scala | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index fd5b635e11e2..c35d259ffea8 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1694,6 +1694,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end SimpleSelectorTypeTest object SimpleSelector extends SimpleSelectorModule: + def apply(name: String): SimpleSelector = + withDefaultPos(untpd.ImportSelector(untpd.Ident(name.toTermName))) def unapply(x: SimpleSelector): Some[String] = Some(x.name.toString) end SimpleSelector @@ -1713,6 +1715,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end RenameSelectorTypeTest object RenameSelector extends RenameSelectorModule: + def apply(fromName: String, toName: String): RenameSelector = + withDefaultPos(untpd.ImportSelector(untpd.Ident(fromName.toTermName), untpd.Ident(toName.toTermName))) def unapply(x: RenameSelector): (String, String) = (x.fromName, x.toName) end RenameSelector @@ -1738,6 +1742,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end OmitSelectorTypeTest object OmitSelector extends OmitSelectorModule: + def apply(name: String): OmitSelector = + withDefaultPos(untpd.ImportSelector(untpd.Ident(name.toTermName), untpd.Ident(nme.WILDCARD))) def unapply(x: OmitSelector): Some[String] = Some(x.imported.name.toString) end OmitSelector @@ -1758,6 +1764,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler end GivenSelectorTypeTest object GivenSelector extends GivenSelectorModule: + def apply(bound: Option[TypeTree]): GivenSelector = + withDefaultPos(untpd.ImportSelector( + untpd.Ident(nme.EMPTY), + bound = bound.map(tpt => untpd.TypedSplice(tpt)).getOrElse(EmptyTree) + )) def unapply(x: GivenSelector): Some[Option[TypeTree]] = Some(GivenSelectorMethods.bound(x)) end GivenSelector diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 7a98d6f6f761..70505eb2e98b 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -2545,6 +2545,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val SimpleSelector` */ trait SimpleSelectorModule { this: SimpleSelector.type => + @experimental def apply(name: String): SimpleSelector def unapply(x: SimpleSelector): Some[String] } @@ -2570,6 +2571,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val RenameSelector` */ trait RenameSelectorModule { this: RenameSelector.type => + @experimental def apply(fromName: String, toName: String): RenameSelector def unapply(x: RenameSelector): (String, String) } @@ -2597,6 +2599,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val OmitSelector` */ trait OmitSelectorModule { this: OmitSelector.type => + @experimental def apply(name: String): OmitSelector def unapply(x: OmitSelector): Some[String] } @@ -2621,6 +2624,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Methods of the module object `val GivenSelector` */ trait GivenSelectorModule { this: GivenSelector.type => + @experimental def apply(bound: Option[TypeTree]): GivenSelector def unapply(x: GivenSelector): Some[Option[TypeTree]] } From 26935907d5ac4f081413834b548654126760558e Mon Sep 17 00:00:00 2001 From: Roman Janusz Date: Sun, 26 Jan 2025 10:11:41 +0100 Subject: [PATCH 2/3] added new methods to experimental definitions --- tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 65e3a730ee7e..3f7b10dc7707 100644 --- a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -73,6 +73,10 @@ val experimentalDefinitionInLibrary = Set( "scala.quoted.Quotes.reflectModule.MethodTypeMethods.hasErasedParams", "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.erasedArgs", "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.hasErasedArgs", + "scala.quoted.Quotes.reflectModule.GivenSelectorModule.apply", + "scala.quoted.Quotes.reflectModule.OmitSelectorModule.apply", + "scala.quoted.Quotes.reflectModule.RenameSelectorModule.apply", + "scala.quoted.Quotes.reflectModule.SimpleSelectorModule.apply", // New feature: fromNullable for explicit nulls "scala.Predef$.fromNullable", From 3cd45e992a39a3e55a363cb1643e51b3116795fa Mon Sep 17 00:00:00 2001 From: Roman Janusz Date: Fri, 31 Jan 2025 18:28:37 +0100 Subject: [PATCH 3/3] added tests for selector constructors --- tests/run-macros/i21225.check | 2 ++ tests/run-macros/i21225/Macro_1.scala | 33 +++++++++++++++++++++++++++ tests/run-macros/i21225/Test_2.scala | 14 ++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 tests/run-macros/i21225.check create mode 100644 tests/run-macros/i21225/Macro_1.scala create mode 100644 tests/run-macros/i21225/Test_2.scala diff --git a/tests/run-macros/i21225.check b/tests/run-macros/i21225.check new file mode 100644 index 000000000000..51779b7b89af --- /dev/null +++ b/tests/run-macros/i21225.check @@ -0,0 +1,2 @@ +bar codec +foo codec diff --git a/tests/run-macros/i21225/Macro_1.scala b/tests/run-macros/i21225/Macro_1.scala new file mode 100644 index 000000000000..2b7bfd3b969f --- /dev/null +++ b/tests/run-macros/i21225/Macro_1.scala @@ -0,0 +1,33 @@ +//> using options -experimental + +import scala.quoted.* + +trait Codec[-T] { def print(): Unit } +object Codec { + inline def derivedWithDeps[T](deps: Any): Codec[T] = ${derivedWithDepsImpl[T]('deps)} + + private def derivedWithDepsImpl[T](deps: Expr[Any])(using q: Quotes)(using Type[T]): Expr[Codec[T]] = { + import q.reflect.* + + val givenSelector: Selector = GivenSelector(None) + val theImport = Import(deps.asTerm, List(givenSelector)) + Block(List(theImport), '{scala.compiletime.summonInline[Codec[T]]}.asTerm).asExprOf[Codec[T]] + /* import deps.given + * summonInline[Codec[T]] + */ + } + + inline def derivedWithDepsWithNamedOmitted[T](deps: Any): Codec[T] = ${derivedWithDepsWithNamedOmittedImpl[T]('deps)} + + private def derivedWithDepsWithNamedOmittedImpl[T](deps: Expr[Any])(using q: Quotes)(using Type[T]): Expr[Codec[T]] = { + import q.reflect.* + + val givenSelector: Selector = GivenSelector(None) + val omitSelector: Selector = OmitSelector("named") + val theImport = Import(deps.asTerm, List(givenSelector, omitSelector)) + Block(List(theImport), '{scala.compiletime.summonInline[Codec[T]]}.asTerm).asExprOf[Codec[T]] + /* import deps.{given, named => _} + * summonInline[Codec[T]] + */ + } +} diff --git a/tests/run-macros/i21225/Test_2.scala b/tests/run-macros/i21225/Test_2.scala new file mode 100644 index 000000000000..bd9081588754 --- /dev/null +++ b/tests/run-macros/i21225/Test_2.scala @@ -0,0 +1,14 @@ +//> using options -experimental + +import scala.quoted.* + +sealed trait Foo +class Bar extends Foo +object CustomCodecs { + given named: Codec[Bar] = new Codec[Bar] { def print(): Unit = println("bar codec")} + given Codec[Foo] = new Codec[Foo] { def print(): Unit = println("foo codec") } +} + +@main def Test = + Codec.derivedWithDeps[Bar](CustomCodecs).print() + Codec.derivedWithDepsWithNamedOmitted[Bar](CustomCodecs).print()