Skip to content

Instantly share code, notes, and snippets.

@japgolly
Created December 16, 2014 08:35
Show Gist options
  • Save japgolly/fc0466d0d1690dc334af to your computer and use it in GitHub Desktop.
Save japgolly/fc0466d0d1690dc334af to your computer and use it in GitHub Desktop.
Quick script to decipher long Scala type errors
import scala.language._
import scala.annotation.tailrec
object Blah {
val errmsg = """
[error] found : blah.webapp.client.lib.ui.Editor[(blah.webapp.base.data.Validators.blar.scala.S, (String, String, blah.webapp.base.data.ImplicationRequired)),blah.webapp.client.app.ui.CfgBlars.fields.FieldValue,scalaz.effect.IO,blah.webapp.client.app.ui.CfgBlars.storesAndState.S,blah.webapp.client.app.ui.CfgBlars.fields.Field,scalaz.effect.IO[Unit],(japgolly.scalajs.react.vdom.ReactVDom.Tag, japgolly.scalajs.react.vdom.ReactVDom.Tag, japgolly.scalajs.react.vdom.prefix_<^.Tag)]
[error] (which expands to) blah.webapp.client.lib.ui.Editor[((Stream[blah.webapp.base.data.CustomBlar], Option[blah.webapp.base.data.CustomBlar.Id]), (String, String, blah.webapp.base.data.ImplicationRequired)),blah.webapp.client.app.ui.CfgBlars.fields.FieldValue,scalaz.effect.IO,blah.webapp.client.app.ui.CfgBlars.storesAndState.State,blah.webapp.client.app.ui.CfgBlars.fields.Field,scalaz.effect.IO[Unit],(japgolly.scalajs.react.vdom.ReactVDom.TypedTag[japgolly.scalajs.react.ReactElement], japgolly.scalajs.react.vdom.ReactVDom.TypedTag[japgolly.scalajs.react.ReactElement], japgolly.scalajs.react.vdom.ReactVDom.TypedTag[japgolly.scalajs.react.ReactElement])]
[error] required: blah.webapp.client.lib.ui.Editor[?,?,scalaz.effect.IO,Bleh.this.thing.sas.S,?,scalaz.effect.IO[Unit],?]
[error] (which expands to) blah.webapp.client.lib.ui.Editor[?,?,scalaz.effect.IO,Bleh.this.thing.sas.State,?,scalaz.effect.IO[Unit],?]
""".trim
def main(args: Array[String]): Unit = {
println()
case class Row[V](lvl: Int, v: V) {
def map[A](f: V => A): Row[A] = copy[A](v = f(v))
def indent = " " * lvl
override lazy val toString = s"$indent$v"
}
type R = List[Row[List[Char]]]
type R2 = List[Row[String]]
object Beg {
def unapply(c: Char): Option[Char] = if (c == '[' || c == '(') Some(c) else None
}
object End {
def unapply(c: Char): Option[Char] = if (c == ']' || c == ')') Some(c) else None
}
@tailrec def go(cs: List[Char], lvl: Int, cur: List[Char], r: R): R = {
@inline def add = if (cur.isEmpty) r else Row(lvl, cur) :: r
@inline def addc(c: Char) = Row(lvl, c :: cur) :: r
@inline def addl(c: Char) = if (cur.isEmpty && r.nonEmpty) r.head.map(c :: _) :: r.tail else addc(c)
cs match {
case Nil => add
case Beg(c) :: t => go(t, lvl+1, Nil , addc(c))
case End(c) :: t => go(t, lvl-1, Nil , addl(c))
case ',' :: t => go(t, lvl , Nil , addl(','))
case h :: t => go(t, lvl , h :: cur, r)
}
}
def parseIntoLines(input: String): R2 =
go(input.toCharArray.toList, 0, Nil, Nil)
.foldLeft[R2](Nil)((q,r) => r.map(_.reverse.mkString.trim) :: q)
val errmsgs = errmsg.split("\n")
.filter(_ contains "expands to")
.map(_.replaceFirst("^.+?expands to.\\s*", ""))
val i = errmsgs(0)
val il = parseIntoLines(i)
val j = errmsgs(1)
val jl = parseIntoLines(j)
def sbs1(found: R2, req: R2): List[String] = {
val lenf = found.foldLeft(0)(_ max _.toString.length)
val lenr = req .foldLeft(0)(_ max _.toString.length)
val fmt = s"%-${lenf}s |%s| %s"
val qm = {
val p = """^\s*\?[,\]]*$""".r.pattern
(s: String) => p.matcher(s).matches
}
@tailrec def sbs(al: R2, bl: R2, o: List[String]): List[String] = {
@inline def p(a: String, b: String) =
String.format(fmt, a,
if (a.isEmpty || b.isEmpty || a==b) " " else if (qm(a) || qm(b)) "?" else "≠",
b) :: o
@inline implicit def auto(a: Row[String]): String = a.toString
(al,bl) match {
case (Nil , Nil ) => o
case (a :: x, Nil ) => sbs(x, Nil, p(a, ""))
case (Nil , b :: y) => sbs(Nil, y, p("", b))
case (a :: x, b :: y) =>
if (a.lvl == b.lvl)
sbs(x, y, p(a,b))
else if (a.lvl > b.lvl)
sbs(x, bl, p(a, ""))
else
sbs(al, y, p("", b))
}
}
val hd = String.format(fmt, "Found", " ", "Required")
val hr = s"${"-"*lenf}-+-+-${"-"*lenr}"
val rr = hd :: hr :: sbs(found, req, Nil).reverse
hr :: rr ::: hr :: Nil
}
sbs1(jl, il) foreach println
println()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment