From 984a9c4e341ccf51da6f327fc80ae8cdb8475286 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 23 Jan 2023 09:56:08 +0100 Subject: [PATCH] Add reflect `TypeRef.underlying` Fixes #15799 --- .../quoted/runtime/impl/QuotesImpl.scala | 1 + library/src/scala/quoted/Quotes.scala | 3 +++ .../stdlibExperimentalDefinitions.scala | 3 ++- tests/run-macros/i15799.check | 7 +++++++ tests/run-macros/i15799/Macro_1.scala | 14 +++++++++++++ tests/run-macros/i15799/Test_2.scala | 21 +++++++++++++++++++ 6 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/run-macros/i15799.check create mode 100644 tests/run-macros/i15799/Macro_1.scala create mode 100644 tests/run-macros/i15799/Test_2.scala diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index a575238f7cd4..f32467bf3088 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1844,6 +1844,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler extension (self: TypeRef) def isOpaqueAlias: Boolean = self.symbol.isOpaqueAlias def translucentSuperType: TypeRepr = self.translucentSuperType + def underlying: TypeRepr = self.underlying end extension end TypeRefMethods diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 7668617fa71c..0d719741799b 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -2775,6 +2775,9 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => extension (self: TypeRef) def isOpaqueAlias: Boolean def translucentSuperType: TypeRepr + /** The type bounds of the referenced type. */ + @experimental + def underlying: TypeRepr end extension end TypeRefMethods diff --git a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala index 2c49ca46349e..c1960b074384 100644 --- a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala @@ -66,8 +66,9 @@ val experimentalDefinitionInLibrary = Set( //// New feature: Macro annotations "scala.annotation.MacroAnnotation", - //// New APIs: Quotes + //// New APIs: Quotes // Should be stabilized in 3.4.0 + "scala.quoted.Quotes.reflectModule.TypeRefMethods.underlying", "scala.quoted.Quotes.reflectModule.defnModule.FunctionClass", // Can be stabilized in 3.4.0 (unsure) or later "scala.quoted.Quotes.reflectModule.CompilationInfoModule.XmacroSettings", diff --git a/tests/run-macros/i15799.check b/tests/run-macros/i15799.check new file mode 100644 index 000000000000..68eaef8bd2b8 --- /dev/null +++ b/tests/run-macros/i15799.check @@ -0,0 +1,7 @@ +Alias: (X.Alias,_ >: scala.Predef.String <: scala.Predef.String) +Opaque: (X.Opaque,_ >: scala.Nothing <: scala.Any) +Bound: (X.Bound,_ >: scala.Nothing <: scala.Predef.String) +OpaqueBound: (X.OpaqueBound,_ >: scala.Nothing <: scala.Predef.String) +Param T: (T,_ >: scala.Nothing <: scala.Any) +Param U: (U,_ >: scala.Nothing <: scala.Predef.String) +Param V: (V,_ >: scala.Int <: scala.Any) diff --git a/tests/run-macros/i15799/Macro_1.scala b/tests/run-macros/i15799/Macro_1.scala new file mode 100644 index 000000000000..7a4eea30f4b1 --- /dev/null +++ b/tests/run-macros/i15799/Macro_1.scala @@ -0,0 +1,14 @@ +import scala.quoted.* + +object exampleMacro { + + inline def typeDefRhs[T <: AnyKind]: (String, String) = ${ typeDefRhsImpl[T] } + + def typeDefRhsImpl[T <: AnyKind: Type](using Quotes): Expr[(String, String)] = { + import quotes.reflect.* + val underlyingTpe = + TypeRepr.of[T] match + case tpe: TypeRef => tpe.underlying + Expr((Type.show[T], underlyingTpe.show)) + } +} diff --git a/tests/run-macros/i15799/Test_2.scala b/tests/run-macros/i15799/Test_2.scala new file mode 100644 index 000000000000..ec1d6ad0c444 --- /dev/null +++ b/tests/run-macros/i15799/Test_2.scala @@ -0,0 +1,21 @@ +@main def Test = { + object X { + type Alias = String + opaque type Opaque = String + type Bound <: String + opaque type OpaqueBound <: String = String + } + import X.* + + println(s"Alias: ${exampleMacro.typeDefRhs[Alias]}") + println(s"Opaque: ${exampleMacro.typeDefRhs[Opaque]}") + println(s"Bound: ${exampleMacro.typeDefRhs[Bound]}") + println(s"OpaqueBound: ${exampleMacro.typeDefRhs[OpaqueBound]}") + + def testParams[T, U <: String, V >: Int](x: Int): Unit = + println(s"Param T: ${exampleMacro.typeDefRhs[T]}") + println(s"Param U: ${exampleMacro.typeDefRhs[U]}") + println(s"Param V: ${exampleMacro.typeDefRhs[V]}") + + testParams(3) +}