Skip to content

Instantly share code, notes, and snippets.

@xeno-by
Created December 12, 2015 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xeno-by/90daa4b8227034acce36 to your computer and use it in GitHub Desktop.
Save xeno-by/90daa4b8227034acce36 to your computer and use it in GitHub Desktop.
import scala.language.experimental.macros
trait Foo[T]
object Foo {
implicit def materialize[T]: Foo[T] = macro Macros.impl[T]
}
@scala.annotation.implicitNotFound("boom")
trait Typeclass[T]
object Main extends App {
def foo[T: Foo](x: T) = ???
foo(42)
}
// We'd like to have Macros.impl look up an implicit instance of Typeclass
// And then propagate the implicitNotFound error message if that instance is not found
// c.abort only works if your macro is blackbox
// If you're whitebox, read on
import scala.reflect.macros.whitebox._ // if this was blackbox, everything would've worked without any hacks
import scala.language.experimental.macros
object Macros {
def impl[T: c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
import c.internal._
import decorators._
val Foo = c.mirror.staticClass("Foo")
val Typeclass = c.mirror.staticClass("Typeclass")
Typeclass.initialize // necessary to get @implicitNotFound loaded
val TypeclassOfT = appliedType(Typeclass.toType, c.weakTypeOf[T])
val result = c.inferImplicitValue(TypeclassOfT, silent = true)
if (result.isEmpty) {
val infAnn = TypeclassOfT.typeSymbol.annotations.find(_.tpe =:= typeOf[_root_.scala.annotation.implicitNotFound]).get
Foo.setAnnotations(infAnn) // propagate the @implicitNotFound message
c.abort(c.enclosingPosition, "") // the "" can be anything - it doesn't matter to the compiler anyway
} else {
q"null"
}
}
}
13:32 ~/Projects/BetterErrors/sandbox (topic/better)$ ks
Test.scala:13: error: boom
foo(42)
^
one error found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment