propensive / wisteria

Easy, fast, transparent generic derivation of typeclass instances in Scala
https://soundness.dev/wisteria/
Apache License 2.0
19 stars 1 forks source link

Cryptic compiler error message #13

Open NPCRUS opened 1 month ago

NPCRUS commented 1 month ago

Assuming I want to only implement type class for Products, therefore I deliberately leave split method unimplemented. When trying to derive type class for Sum type - I get extremely cryptic message:

[error] 200 |  val parserForSum = summon[Parser[ParserTestSum]]
[error]     |                                                  ^
[error]     |cannot reduce inline match with
[error]     | scrutinee:  x$1$proxy74 : (x$1$proxy74 :
[error]     |  scala.deriving.Mirror.Sum{
[error]     |    type MirroredMonoType = wisteria.ParserTestSum;
[error]     |      type MirroredType = wisteria.ParserTestSum;
[error]     |      type MirroredLabel = ("ParserTestSum" : String);
[error]     |      type MirroredElemTypes = (
[error]     |        (wisteria.ParserTestSum.FirstVariant : wisteria.ParserTestSum),
[error]     |        wisteria.ParserTestSum.SecondVariant);
[error]     |      type MirroredElemLabels = (("FirstVariant" : String),
[error]     |        ("SecondVariant" : String))
[error]     |  }
[error]     |)
[error]     | patterns :  case reflection @ _:wisteria.ProductReflection[derivationType @ _]
[error]     |---------------------------------------------------------------------------
[error]     |Inline stack trace
[error]     |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]     |This location contains code that was inlined from wisteria.ProductDerivation.scala:28
[error]  28 |    inline summon[Reflection[DerivationType]] match
[error]     |           ^
[error]  29 |      case reflection: ProductReflection[derivationType] =>
[error]  30 |        join[derivationType](using reflection).asMatchable match
[error]  31 |          case typeclass: TypeclassType[DerivationType] => typeclass
[error]      ---------------------------------------------------------------------------

I wonder if it can be improved somehow how to reproduce:

trait Parser[ValueType] {
  def parse(s: String): Option[ValueType]
}

object Parser extends ProductDerivation[Parser] {
  given Parser[Int] with
    def parse(s: String): Option[Int] = s.toIntOption

  given Parser[Boolean] with
    def parse(s: String): Option[Boolean] = s.toBooleanOption

  inline def join[DerivationType <: Product: ProductReflection]: Parser[DerivationType] = inputStr =>
    IArray.from(inputStr.split(',')).pipe: inputArr =>
      constructWithV2[DerivationType, Option](
        [T] => Some(_),
        [FieldType] => context =>
          if index < inputArr.length then 
            context.parse(inputArr(index)) match
              case None => None
              case Some(value) => specify(value)
          else 
            None
      )
}

enum ParserTestSum:
  case FirstVariant
  case SecondVariant(intValue: Int)

val parserForSum = summon[Parser[ParserTestSum]]
propensive commented 1 month ago

This is somewhat typical for an error message when a derivation fails. I haven't spent a lot of time investigating solutions yet, but one option may be to implement derivation with a macro which calls into the existing code, but identifies the case where derivation fails (for any reason, including the above) and then goes through some steps to try to diagnose it, replacing the long inline error message with something more useful.