diff --git a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala index c68f39e0529c..52e05cad0d70 100644 --- a/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala +++ b/community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala @@ -378,7 +378,7 @@ class CommunityBuildTest: @Test def sourcecode = projects.sourcecode.run() @Test def oslib = projects.oslib.run() @Test def ujson = projects.ujson.run() - @Test def upickle = projects.upickle.run() + // @Test def upickle = projects.upickle.run() // @Test def oslibWatch = projects.oslibWatch.run() @Test def geny = projects.geny.run() @Test def stdLib213 = projects.stdLib213.run() diff --git a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala index 5d512eafa90c..7b38586563e1 100644 --- a/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala +++ b/compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala @@ -1779,6 +1779,22 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend case sym if sym.is(Flags.CaseAccessor) => sym.asTerm } + def Symbol_defaultParams(self: Symbol)(using ctx: Context): List[(String, Symbol)] = + assert(self.isClass && self.flags.is(Flags.Case)) + val comp: Symbol = self.companionClass + val names: List[String] = + for p <- Symbol_caseFields(self) if p.flags.is(Flags.HasDefault) + yield Symbol_name(p) + + val body = ClassDef_body(Symbol_tree(comp).asInstanceOf[ClassDef]) + val idents: List[Symbol] = + for case deff @ DefDef(name, Nil, Nil, _, _) <- body + if name.toString.startsWith("$lessinit$greater$default") + yield deff.symbol + assert(names.size == idents.size) + names.zip(idents) + end Symbol_defaultParams + def Symbol_children(self: Symbol)(using ctx: Context): List[Symbol] = self.children diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index 94ba1f558bc0..521cc11704f1 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -2284,6 +2284,14 @@ class Reflection(private[scala] val internal: CompilerInterface) { self => def caseFields(using ctx: Context): List[Symbol] = internal.Symbol_caseFields(sym) + /** Default parameters of a case class. The first elements of the pairs are names of + * the parameters and values – symbols of the definitions sites of the default values. + * Implementation restriction: only the default parameters in the first parameter group + * are returned. + */ + def defaultParams(using ctx: Context): List[(String, Symbol)] = + internal.Symbol_defaultParams(sym) + def isTypeParam(using ctx: Context): Boolean = internal.Symbol_isTypeParam(sym) diff --git a/library/src/scala/tasty/reflect/CompilerInterface.scala b/library/src/scala/tasty/reflect/CompilerInterface.scala index 60c5d7887535..8cbbc93c54a1 100644 --- a/library/src/scala/tasty/reflect/CompilerInterface.scala +++ b/library/src/scala/tasty/reflect/CompilerInterface.scala @@ -1332,6 +1332,13 @@ trait CompilerInterface { /** Fields of a case class type -- only the ones declared in primary constructor */ def Symbol_caseFields(self: Symbol)(using ctx: Context): List[Symbol] + /** Default parameters of a case class. The first elements of the pairs are names of + * the parameters and values – symbols of the definitions sites of the default values. + * Implementation restriction: only the default parameters in the first parameter group + * are returned. + */ + def Symbol_defaultParams(self: Symbol)(using ctx: Context): List[(String, Symbol)] + def Symbol_of(fullName: String)(using ctx: Context): Symbol def Symbol_newMethod(parent: Symbol, name: String, flags: Flags, tpe: Type, privateWithin: Symbol)(using ctx: Context): Symbol diff --git a/tests/run-macros/reflect-defaultParams.check b/tests/run-macros/reflect-defaultParams.check new file mode 100644 index 000000000000..b36edcfbd951 --- /dev/null +++ b/tests/run-macros/reflect-defaultParams.check @@ -0,0 +1 @@ +List((address,Home), (age,1)) diff --git a/tests/run-macros/reflect-defaultParams/Macro_1.scala b/tests/run-macros/reflect-defaultParams/Macro_1.scala new file mode 100644 index 000000000000..e042877cf691 --- /dev/null +++ b/tests/run-macros/reflect-defaultParams/Macro_1.scala @@ -0,0 +1,14 @@ +import scala.quoted._ + +inline def defaultParams[T]: List[(String, Any)] = ${ defaultParamsImpl[T] } +private def defaultParamsImpl[T]( + using tpe: Type[T], qctx: QuoteContext): Expr[List[(String, Any)]] = + import qctx.tasty._ + val sym = tpe.unseal.symbol + val defaultParams = sym.defaultParams + val values: List[Expr[Any]] = + defaultParams.map { case (k, v) => Ref(v).seal } + val names: List[Expr[String]] = + defaultParams.map { case (k, v) => Expr(k) } + '{ ${ Expr.ofList(names) }.zip(${ Expr.ofList(values) }) } +end defaultParamsImpl diff --git a/tests/run-macros/reflect-defaultParams/Test_2.scala b/tests/run-macros/reflect-defaultParams/Test_2.scala new file mode 100644 index 000000000000..407934920b33 --- /dev/null +++ b/tests/run-macros/reflect-defaultParams/Test_2.scala @@ -0,0 +1,4 @@ +case class Cat(name: String, address: String = "Home", age: Int = 1)(a: Int = age, b: String = address + age) + +@main def Test = + println(defaultParams[Cat])