scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.79k stars 1.04k forks source link

Typeclass derivation fails with no useful information #18166

Open pmeheut opened 1 year ago

pmeheut commented 1 year ago

With caliban 2.0.0, the code compiles and works. With 2.2.0, it fails and the recursive error message is not helpful at all.

Compiler version

3.3.0

Minimized example

import caliban.client.*
import sttp.client3.*
import sttp.client3.circe.*
import sttp.model.*
import io.circe.*
import io.circe.parser.*
import io.circe.syntax.*
import io.circe.generic.auto.*
import io.circe.parser.decode

class Foo {
    val foo = implicitly[BodySerializer[GraphQLRequest]]
}

build.sbt

ThisBuild / scalaVersion := "3.3.0"

lazy val root = (project in file("."))
  .settings(
    name := "scala_bug_2",
    libraryDependencies ++= Seq("com.github.ghostdogpr" %% "caliban-client" % "2.2.0",
      "com.softwaremill.sttp.client3" %% "core" % "3.8.3",
      "com.softwaremill.sttp.client3" %% "circe" % "3.8.3",
      "com.softwaremill.sttp.client3" %% "zio" % "3.8.3",
      "io.circe" %% "circe-generic" % "0.14.3",
      "io.circe" %% "circe-parser" % "0.14.3")
  )

``
## Output

```scala
[error] 12 |    val foo = implicitly[BodySerializer[GraphQLRequest]]
[error]    |                                                        ^
[error]    |             method derived is declared as `inline`, but was not inlined
[error]    |
[error]    |             Try increasing `-Xmax-inlines` above 32
[error]    |----------------------------------------------------------------------------
[error]    |Inline stack trace
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]    |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]    |This location contains code that was inlined from Derivation.scala:16
[error]     ----------------------------------------------------------------------------
[error] one error found

Expectation

At least an usable error message pointed out the source of the problem in the code because increasing -Xmax-inlines has no effect.

WojciechMazur commented 1 year ago

Open CB failures of zio/zio-config might be related to that. It fails with same error in 3.3.1-RC3: https://github.com/VirtusLab/community-build3/actions/runs/5480083582/jobs/9985438703 However, it compiles in 3.3.2-RC1 Nightly, but fails with different error https://github.com/VirtusLab/community-build3/actions/runs/5426571795/jobs/9871306636

WojciechMazur commented 1 year ago

I think it might be rather a regression in one of used libraries, if I need to guess, then I'd bet on import io.circe.generic.auto.* which might generate a new typeclass for each found usage of given type

And if fact it matches a source code for that version: https://github.com/circe/circe/blob/505fa69c73306ce98b67f4d224799774a5ba3e67/modules/core/shared/src/main/scala-3/io/circe/Derivation.scala#L16-L17

What's interesting this Derivation is deprecated since 0.14.4, so they're probably aware of this kind of issues, however the given snippet would still fail to compile even when using latest versions of libraries. There no version of Scala 3 in which it would successfully compile

smarter commented 1 year ago

I believe the relevant circe issue is https://github.com/circe/circe/issues/2126, I'm not sure if there's actually something we can do differently in the compiler since we don't know what the inline def is trying to achieve in general so it's hard for us to give more precise error messages. perhaps we could let the authors of the inline def customize the error that is reported in cases like this, but full auto derivation is just the wrong default in circe.

pmeheut commented 1 year ago

Thanks. Now I understand. Because Caliban 2.2.0 moved from Circe to jsoniter, GraphQLRequest and other classes do not provide the implicit Circe encoders/decoders anymore. So the compiler tries full auto-derivation and fails.

This is not obvious.

odersky commented 1 year ago

It's not the compiler that tries that, it's the type class derivation macro library that circe uses (kitten, maybe?). Once we move to Scala 3 built in typeclass derivation, it will be up the the compiler. And hopefully that will be more predictable..

smarter commented 1 year ago

, it's the type class derivation macro library that circe uses (kitten, maybe?).

circe implements typeclass derivation for scala 3 by itself via inline defs: https://github.com/circe/circe/blob/series/0.14.x/modules/core/shared/src/main/scala-3/io/circe/derivation/package.scala

Once we move to Scala 3 built in typeclass derivation, it will be up the the compiler.

Is this referring to an upcoming feature?

odersky commented 1 year ago

Ah indeed. Not sure why it tried to call itself in a cycle then.

bishabosha commented 1 year ago

What is the definition ofGraphQLRequest ? - edit: I found it and i dont that is relevant to this issue

bishabosha commented 1 year ago

You can also try -Xprint:inlining to try and see the trees that get inlined