diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala index 035cfd228302..2ae0ca5c9f21 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala @@ -1205,6 +1205,9 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend def Type_baseClasses(self: Type)(using Context): List[Symbol] = self.baseClasses + def Type_baseType(self: Type)(cls: Symbol)(using Context): Type = + self.baseType(cls) + def Type_derivesFrom(self: Type)(cls: Symbol)(using Context): Boolean = self.derivesFrom(cls) diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index edfee77e4aa2..238a2f7b320b 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -1812,6 +1812,17 @@ class Reflection(private[scala] val internal: CompilerInterface) { self => /** The base classes of this type with the class itself as first element. */ def baseClasses(using ctx: Context): List[Symbol] = internal.Type_baseClasses(self) + + /** The least type instance of given class which is a super-type + * of this type. Example: + * {{{ + * class D[T] + * class C extends p.D[Int] + * ThisType(C).baseType(D) = p.D[Int] + * }}} + */ + def baseType(cls: Symbol)(using ctx: Context): Type = internal.Type_baseType(self)(cls) + /** Is this type an instance of a non-bottom subclass of the given class `cls`? */ def derivesFrom(cls: Symbol)(using ctx: Context): Boolean = internal.Type_derivesFrom(self)(cls) diff --git a/library/src/scala/tasty/reflect/CompilerInterface.scala b/library/src/scala/tasty/reflect/CompilerInterface.scala index ad70193f8c17..ace40fcae909 100644 --- a/library/src/scala/tasty/reflect/CompilerInterface.scala +++ b/library/src/scala/tasty/reflect/CompilerInterface.scala @@ -876,6 +876,16 @@ trait CompilerInterface { /** The base classes of this type with the class itself as first element. */ def Type_baseClasses(self: Type)(using ctx: Context): List[Symbol] + /** The least type instance of given class which is a super-type + * of this type. Example: + * {{{ + * class D[T] + * class C extends p.D[Int] + * ThisType(C).baseType(D) = p.D[Int] + * }}} + */ + def Type_baseType(self: Type)(cls: Symbol)(using ctx: Context): Type + /** Is this type an instance of a non-bottom subclass of the given class `cls`? */ def Type_derivesFrom(self: Type)(cls: Symbol)(using ctx: Context): Boolean diff --git a/tests/run-macros/i8514b.check b/tests/run-macros/i8514b.check new file mode 100644 index 000000000000..fcf27e623f06 --- /dev/null +++ b/tests/run-macros/i8514b.check @@ -0,0 +1,4 @@ +B +A[[T >: scala.Nothing <: scala.Any] => P[T], scala.Predef.String] +java.lang.Object +scala.Any diff --git a/tests/run-macros/i8514b/Macro_1.scala b/tests/run-macros/i8514b/Macro_1.scala new file mode 100644 index 000000000000..be6268f55bb3 --- /dev/null +++ b/tests/run-macros/i8514b/Macro_1.scala @@ -0,0 +1,18 @@ +import scala.quoted._ + +class A[+X[_], -Y] +class P[T] +class B extends A[P, String] + +inline def test(): Unit = ${ testExpr } + +def testExpr(using QuoteContext): Expr[Unit] = { + import qctx.tasty._ + + val t = '[B].unseal.tpe + val baseTypes = t.baseClasses.map(b => t.baseType(b)) + + '{ + println(${Expr(baseTypes.map(_.show).mkString("\n"))}) + } +} diff --git a/tests/run-macros/i8514b/Test_2.scala b/tests/run-macros/i8514b/Test_2.scala new file mode 100644 index 000000000000..c96956b4554d --- /dev/null +++ b/tests/run-macros/i8514b/Test_2.scala @@ -0,0 +1 @@ +@main def Test = test()