Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code spliced for handling default parameters mentions companion object, potentially doesn't have to? #113

Open
neko-kai opened this issue Sep 16, 2019 · 2 comments

Comments

@neko-kai
Copy link
Contributor

Derivation in this code:

final case class RandomPayload(field1: String, randomArray: Set[Int] = List.fill(10)(Random.nextInt(10)).toSet)

object RandomPayload extends WithCirce[RandomPayload]

Will produce the following error:

super constructor cannot be passed a self reference unless parameter is declared by-name
[error]   object RandomPayload extends WithCirce[RandomPayload]
[error]                                ^

Where WithCirce is defined as:

import io.circe.{Decoder, Encoder, derivation}

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

/**
 * Provides circe codecs for case classes and sealed traits
 * {{{
 *   final case class Abc(a: String, b: String, c: String)
 *
 *   object Abc extends WithCirce[Abc]
 * }}}
 */
abstract class WithCirce[A](implicit encoder: DerivationDerivedEncoder[A], decoder: DerivationDerivedDecoder[A]) {
  implicit val enc: Encoder.AsObject[A] = encoder.value
  implicit val dec: Decoder[A] = decoder.value
}

final class MaterializeDerivationMacros(override val c: blackbox.Context) extends derivation.DerivationMacros(c) {
  import c.universe._

  def materializeEncoderImpl[A: c.WeakTypeTag]: c.Expr[DerivationDerivedEncoder[A]] =
    c.Expr[DerivationDerivedEncoder[A]] {
      q"{ ${symbolOf[DerivationDerivedEncoder.type].asClass.module}.apply(${materializeEncoder[A]}) }"
    }

  def materializeDecoderImpl[A: c.WeakTypeTag]: c.Expr[DerivationDerivedDecoder[A]] =
    c.Expr[DerivationDerivedDecoder[A]] {
      q"{ ${symbolOf[DerivationDerivedDecoder.type].asClass.module}.apply(${materializeDecoder[A]}) }"
    }
}

final case class DerivationDerivedEncoder[A](value: Encoder.AsObject[A])
object DerivationDerivedEncoder {
  implicit def materialize[A]: DerivationDerivedEncoder[A] = macro MaterializeDerivationMacros.materializeEncoderImpl[A]
}

final case class DerivationDerivedDecoder[A](value: Decoder[A])
object DerivationDerivedDecoder {
  implicit def materialize[A]: DerivationDerivedDecoder[A] = macro MaterializeDerivationMacros.materializeDecoderImpl[A]
}

If the default parameter is removed, the error disappears:

final case class RandomPayload(field1: String, randomArray: Set[Int])
object RandomPayload extends WithCirce[RandomPayload]

This didn't happen in older versions of circe-derivation and indicates that the code for default value management is splicing additional references to the companion object – which I'm not sure are necessary for the use case, although I may be wrong.

/cc @aparo

@travisbrown
Copy link
Member

Thanks for catching this. I'll try to take a look this weekend.

@voidconductor
Copy link

Derivation also fails if there's default parameters in companion object's apply method,
it could be related

case class Test(field1: Option[String], field2: Int, field3: Boolean)

object Test {
  def apply(value: List[String], bool: Boolean = false): Test = 
    Test(value.headOption, value.length, bool)
}

io.circe.derivation.deriveDecoder[Test]
cmd7.sc:1: type mismatch;
 found   : Boolean
 required: Int
val res7 = io.circe.derivation.deriveDecoder[Test]
                                            ^
Compilation Failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants