http4s/rho

Circe auto generic derivation causes diverging implicit expansion of `HlistToFunc`

zarthross opened this issue · 4 comments

I'll try and put in an example next week, but it appears the fix for #216 does break using circe's fully automatic derivation. In the mean time, the work around is just using the semiauto derivation instead.

The fix I currently have (which is of course unacceptable) :

  import authContext._
  import swaggerSyntax._
  import io.circe.generic.auto._
  import org.http4s.circe._
  import org.http4s.rho.bits._

Importing in that order enables circe macros to work

Ok, actually I just got rid of all the errors by just extending CirceInstances at package level so I can now remove all these imports and just keep

import authContext._
import swaggerSyntax._

I see the same error (or a very similar one) when using semiauto derivation with circe-derivation:

// build.sbt
scalaVersion := "2.12.8"

scalacOptions += "-Ypartial-unification"

libraryDependencies := Seq(
  "io.circe" %% "circe-core" % "0.11.1",
  "io.circe" %% "circe-derivation" % "0.11.0-M1",
  "org.http4s" %% "http4s-circe" % "0.20.0-M6",
  "org.http4s" %% "http4s-dsl" % "0.20.0-M6",
  "org.http4s" %% "rho-swagger" % "0.19.0-M6",
  "org.typelevel" %% "cats-effect" % "1.2.0"
)
// src/main/scala/Example.scala
import cats.effect.IO
import io.circe.Encoder
import io.circe.derivation.deriveEncoder
import org.http4s.circe.CirceEntityEncoder
import org.http4s.rho.RhoRoutes

object Example extends CirceEntityEncoder {

  case class Response(a: String)
  object Response {
    implicit val encoder: Encoder[Response] = deriveEncoder
  }

  val routes = new RhoRoutes[IO] {
    GET / "example" |>> { () =>
      if (true) {
        Ok(Response("foo"))
      } else {
        InternalServerError(Response("bar"))
      }
    }
  }
}

As mentioned in #216 (comment), turning off partial unification gets things to compile, but that's not feasible in my full project. The two other workarounds I've found are:

  1. Explicitly call .asJson on each response. This fixes compilation, but leaves the model's info out of the eventually-generated Swagger documentation.
  2. Copy-paste the derivation rule provided by CirceEntityEncoder, but with pinned type parameters:
    // This works
    import cats.effect.IO
    import io.circe.Encoder
    import io.circe.derivation.deriveEncoder
    import org.http4s.EntityEncoder
    import org.http4s.circe.CirceInstances
    import org.http4s.rho.RhoRoutes
    
    object Example extends CirceInstances {
    
      case class Response(a: String)
      object Response {
        implicit val encoder: Encoder[Response] = deriveEncoder
      }
    
      val routes = new RhoRoutes[IO] {
        GET / "example" |>> { () =>
          implicit val e: EntityEncoder[IO, Response] =
            jsonEncoderOf[IO, Response]
    
          if (true) {
            Ok(Response("foo"))
          } else {
            InternalServerError(Response("bar"))
          }
        }
      }
    }

Currently I'm using solution 2. provided by @danxmoran and model is generating properly