Skip to content

Instantly share code, notes, and snippets.

@propensive
Last active August 29, 2015 14:15
Show Gist options
  • Save propensive/6a47575a4bce3b17c5dc to your computer and use it in GitHub Desktop.
Save propensive/6a47575a4bce3b17c5dc to your computer and use it in GitHub Desktop.
Providing custom type mismatch errors in Scala
import language.experimental.macros
import language.implicitConversions
import scala.reflect.macros._
// We are going to provide a custom error message for when users use the wrong variant of some
// type, `Foo`. Note that `Foo` needs to be invariant or contravariant in its type parameter!
case class Foo[T]()
object Foo {
implicit def reportError[T, U](value: Foo[T]): Foo[U] = macro Macros.reportErrorMacro[T, U]
}
object Macros {
def reportErrorMacro[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context)(value: c.Expr[Foo[T]]): c.Expr[Foo[U]] = {
import c.universe._
val (t, u) = (weakTypeOf[T], weakTypeOf[U])
c.abort(c.enclosingPosition, s"You tried to use a Foo of type $t, when you should have used a $u!")
}
}
// We have created an implicit which will convert from any specific type of `Foo` to any other
// type of `Foo`, then we've implemented that with a macro which will always fail (at compile
// time) with our custom error.
// Let's demonstrate it in the REPL by providing a `Foo[String]` where a `Foo[Int]` is expected:
scala> def foo[T](f: Foo[T]) = ()
foo: [T](f: Foo[T])Unit
scala> foo[String](Foo[Int]())
<console>:18: error: You tried to use a Foo of type Int, when you should have used a String!
foo[String](Foo[Int]())
^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment