Maximal number of successive inlines (32) exceeded, Maybe this is caused by a recursive inline method?
0bon opened this issue · comments
I am using deriveCodec
to translate to and from json to ADTs. However, when I started adding Lists to my ADT the compiler did not like it and started throwing errors. See code and error below. I am using Scala 3.2.2.
Trying to set -Xmax-inlines
in the sbt build file gives me [warn] bad option '-Xmax-inlines 50' was ignored
libraryDependencies ++= Seq(
"io.circe" %% "circe-core",
"io.circe" %% "circe-generic",
"io.circe" %% "circe-parser"
).map(_ % "0.14.5")
import io.circe.generic.semiauto.{deriveCodec, deriveDecoder}
import io.circe.{Decoder, Encoder, parser}
import io.circe.syntax.*
case class Property(address1: String, address2: String, address3: String, postcode: String)
case class AccountForm(name: String, property: List[Property], postcode: String)
object CreateAccount {
implicit val decoder: Decoder[AccountForm] = deriveCodec[AccountForm]
implicit val decoder2: Decoder[Property] = deriveCodec[Property]
def fromJson(json: String): AccountForm = {
parser.decode[AccountForm](json).toOption.get
}
}
[error] -- Error: /AccountForm.scala:30:50
[error] 30 | implicit val decoder: Decoder[AccountForm] = deriveCodec[AccountForm]
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] | Maximal number of successive inlines (32) exceeded,
[error] | Maybe this is caused by a recursive inline method?
[error] | You can use -Xmax-inlines to change the limit.
[error] |---------------------------------------------------------------------------
[error] |Inline stack trace
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from AccountForm.scala:30
[error] --------------
Trying to set
-Xmax-inlines
in the sbt build file gives me[warn] bad option '-Xmax-inlines 50' was ignored
You need to pass it as two separate arguments
scalacOptions ++= Seq("-Xmax-inlines", "50")
Same here, and setting a higher max-inlines parameter didn't fix the issue
Likely would be helped by a solution to #2126 since there would be fewer inline calls overall
The example actually has two problems:
a) deriveCodec
does not use a proper given Codec
instance for List
and instead tries to derive a codec for List
b) derivation for recursive structures suffers from bugs (see #2101)
With the pending fix for b) (#2187 ), the code compiles, however:
import io.circe.generic.semiauto.deriveCodec
import io.circe.*
import io.circe.syntax.*
case class Property(address1: String, address2: String, address3: String, postcode: String)
case class AccountForm(name: String, property: List[Property], postcode: String)
implicit val accountFormDecoder: Decoder[AccountForm] = deriveCodec[AccountForm]
object Main:
def main(args: Array[String]) =
println(parser.decode[AccountForm]("""{"name":"x","property":[],"postcode":"y"}"""))
// Left(DecodingFailure at .property: Got value '[]' with wrong type, expecting object)
println(parser.decode[AccountForm]("""{"name":"x","property":{"Nil$":{}},"postcode":"y"}"""))
// Right(AccountForm(x,List(),y))
Looks like for all three typeclasses (Codec, Encoder, Decoder), the behavior is:
If a product-member is a List[T]
and there is a an instance of the typeclass for T
, then derivation will pick up the appropriated instance for List
that converts to/from Json-Array:
// with the fix from #2187
case class Ints(ints: List[Int]) derives Encoder.AsObject
println(Ints(List.empty).asJson.noSpaces)
// {"ints":[]}
If a product-member is a List[T]
and there is no instance of the typeclass for T
, then derivation will not pick up the appropriated instance for List
and instead derive one that converts to/from Json-Objects:
// with the fix from #2187
case class Foos(foos: List[Foo.type]) derives Encoder.AsObject
println(foos(List.empty).asJson.noSpaces)
// {"foos":{"Nil$":{}}}
Note that I'm not sure 100% if such "transitive derivation" is even expected to work (?). If not, then the original example is just not using the library correctly (because it tries to derive a Codec[AccountForm]
without having a given/implicitCodec[Property]
in scope) - nevertheless, in that case, the error message is still less than ideal.
@0bon @caenrique As a workaround you can use jsoniter-scala's JsonCodecMaker.makeCirceLike
macro to auto-derive safe an efficient JSON codecs (with clear compilation errors for unsupported types like Java classes and collections).