scala/bug

Implicit whitebox macros (fundep materialization) swallow fatal errors

joroKr21 opened this issue · 3 comments

Since whitebox macro expansion is forced here, when the typer is an implicit search all exceptions thrown by the macro implementation are caught and swallowed as "implicit not found", including fatal errors like out of memory or stack overflow.

This doesn't happen with blackbox macros, because they are delayed and expanded after the implicit search.

Example:

object Macros {
  trait BlackBox[A]
  object BlackBox {
    implicit def materialize[A]: BlackBox[A] = macro materializeImpl[A]
    def materializeImpl[A](c: blackbox.Context): c.Tree = throw new OutOfMemoryError
  }

  trait WhiteBox[A]
  object WhiteBox {
    implicit def materialize[A]: WhiteBox[A] = macro materializeImpl[A]
    def materializeImpl[A](c: whitebox.Context): c.Tree = throw new OutOfMemoryError
  }
}

object Test {
  import Macros._
  implicitly[BlackBox[Int]] // out of memory
  implicitly[WhiteBox[Int]] // implicit not found
}

This can cause spurious missing implicit errors (see. milessabin/shapeless#776).

Thanks for the minimal reproduction @joroKr21

The behavior for both blackbox and whitebox macros is unexpected for me.

java.lang.reflect.InvocationTargetException
so-test.scala:3: error: exception during macro expansion:
java.lang.OutOfMemoryError
	at Macros$BlackBox$.materializeImpl(so.scala:8)

  implicitly[BlackBox[Int]] // out of memory
            ^
java.lang.reflect.InvocationTargetException
so-test.scala:4: error: could not find implicit value for parameter e: Macros.WhiteBox[Int]
  implicitly[WhiteBox[Int]] // implicit not found
            ^
two errors found

The behavior for whitebox macros is arguably worse, but I would expect fatal errors to propagate instead of get reported. Is there a good reason to not use NonFatal where Throwable is caught?

I opened scala/scala#6220 changing the error handling to propagate fatal exceptions.

I have no idea how error handling works in the compiler. Does rethrowing the fatal error crash it? Does the stack trace then include the source location where the macro was called? In general it's a good idea to guard against poorly written macros, but "implicit not found" is just plain the incorrect error.