sirthias / borer

Efficient CBOR and JSON (de)serialization in Scala
https://sirthias.github.io/borer/
Mozilla Public License 2.0
220 stars 13 forks source link

Issues with Scala 3 enums derived from a trait #695

Closed OndrejSpanel closed 2 months ago

OndrejSpanel commented 5 months ago

Following code gives error with borer 1.14.0 and Scala 3.3.3:

package com.github.ondrejspanel.borer

import io.bullet.borer._
import io.bullet.borer.derivation.MapBasedCodecs._

sealed trait EBase
case class EE() extends EBase

enum E extends EBase:
  case A
  case B

object E:
  given codec: Codec[E] = deriveCodec

object EBase:
  given codec: Codec[EBase] = deriveAllCodecs

@main
def main(): Unit = {
  val c: EBase = EE()
  println(Json.encode(c).toUtf8String)
}

Error is:

value E is not a member of object com.github.ondrejspanel.borer.EBase given codec: Codec[EBase] = deriveAllCodecs

When removing EE, a different error is shown:

Could not find any sub-types of EBase, likely because EBase is not a fully closed ADT. Do you maybe have a sealed trait somewhere, which has no subclasses?

sirthias commented 5 months ago

Ok, interesting, thank you @OndrejSpanel ! I'll look into this ASAP.

mrdziuban commented 2 months ago

I also just ran into the second error, ... is not a fully closed ADT. Would love to see support for enums!

sirthias commented 2 months ago

Ok, thank you, @mrdziuban ! The bug is confirmed but unfortunately not super easy to fix. Still, it needs to be corrected and will be done.

Note that Enums are supported already, the problem only arises of they extend another trait or class.

mrdziuban commented 2 months ago

Thanks @sirthias, I realized why it wasn't working for me, my issue is unrelated to extending another trait or class. It looks like using Encoder.All.derived or deriveAllEncoders doesn't work when the enum has only case object members -- https://scastie.scala-lang.org/EB8BVPG0QMGkeqCSg2Pjlg

Is this intentional? I would like to use Encoder.All.derived for all of my enums regardless of whether they're all case objects or some case classes are mixed in. sealed traits and sealed abstract classes do not have the same issue.

image
sirthias commented 2 months ago

@mrdziuban Ah, I see. The case that an enum doesn't define any actual sub-classes (but only simple cases) is already supported, but the error message you are seeing isn't good. I've just pushed a fix for that. In your case everything will work as expected with a simple derives Encoder or deriveEncoder call.

Background: Simple Enum cases do not actually define any new types or sub-classes. They simply designate instances of the enum type itself. Therefore a single Encoder, Decoder or Codec is enough to support all cases and you don't need the deriveAll macro at all.

sirthias commented 2 months ago

I just published release 1.14.1 containing the full fill for this issue. Thank you again for reporting!