circe / circe

Yet another JSON library for Scala

Home Page:https://circe.github.io/circe/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Bug] configured derivation withDefaults fails on class with type parameters and defaults

kailuowang opened this issue · comments

The following code fails

    given Configuration = Configuration.default.withDefaults

    case class FooWithDefaultSeq[A](a: Seq[A] = Nil) 

    object FooWithDefaultSeq:
       given Codec[FooWithDefaultSeq[Int]] = Codec.AsObject.derivedConfigured

Error

[error] 237 |      given Codec[FooWithDefaultSeq[Int]] = Codec.AsObject.derivedConfigured
[error]     |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]     |Exception occurred while executing macro expansion.
[error]     |java.lang.Exception: Expected an expression. This is a partially applied Term. Try eta-expanding the term first.
[error]     |	at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExpr(QuotesImpl.scala:110)
[error]     |	at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExpr(QuotesImpl.scala:106)
[error]     |	at io.circe.derivation.Default$.$anonfun$1$$anonfun$1(Default.scala:43)
[error]     |	at io.circe.derivation.Default$.$anonfun$1$$anonfun$adapted$1(Default.scala:43)
[error]     |	at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:109)
[error]     |	at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1446)
[error]     |	at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:134)
[error]     |	at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1507)
[error]     |	at scala.collection.immutable.List.mapConserve(List.scala:472)
[error]     |	at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1507)
[error]     |	at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1412)
[error]     |	at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:134)
[error]     |	at dotty.tools.dotc.quoted.PickledQuotes$.spliceTerms(PickledQuotes.scala:151)
[error]     |	at dotty.tools.dotc.quoted.PickledQuotes$.unpickleTerm(PickledQuotes.scala:87)
[error]     |	at scala.quoted.runtime.impl.QuotesImpl.unpickleExprV2(QuotesImpl.scala:3044)
[error]     |	at io.circe.derivation.Default$.$anonfun$1(Default.scala:43)
[error]     |	at io.circe.derivation.Default$.$anonfun$adapted$1(Default.scala:43)
[error]     |	at scala.collection.StrictOptimizedSeqFactory.tabulate(Factory.scala:341)
[error]     |	at scala.collection.StrictOptimizedSeqFactory.tabulate$(Factory.scala:336)
[error]     |	at scala.collection.immutable.List$.tabulate(List.scala:681)
[error]     |	at io.circe.derivation.Default$.getDefaultsImpl(Default.scala:43)

The code compiles if you remove the default value for the parameter, i.e.

    case class FooWithDefaultSeq[A](a: Seq[A]) 

Sorry I am not familiar with scala 3 derivation enough to help debug this error.

cc @Lasering

Configuration.withDefaults uses a macro to fetch the defaults of the class. The error is coming from the macro. Here is a more detailed explanation of the problem https://stackoverflow.com/questions/73024281/how-to-get-the-list-of-default-fields-values-for-typed-case-class

I'm looking into a solution, but I'm really not good with macros, if someone with more experience can lend a hand it would be greatly appreciated.

Some more context: lampepfl/dotty-feature-requests#162

When the class is generic this line:

companion.declaredMethod(s"$$lessinit$$greater$$default$$${i + 1}").headOption.map(Select(Ref(companion), _))

should be

companion.declaredMethod(s"$$lessinit$$greater$$default$$${i + 1}").headOption.map(s => Ref(companion).select(s).appliedToTypes(TypeRepr.of[T].typeArgs))

I just need to find a way to distinguish between a generic class and a non generic class.