Skip to content

Instantly share code, notes, and snippets.

@alexandru
Created April 27, 2015 08:22
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 alexandru/39381aefb07e9248c178 to your computer and use it in GitHub Desktop.
Save alexandru/39381aefb07e9248c178 to your computer and use it in GitHub Desktop.
import language.experimental.macros
import scala.reflect.macros.Context
/**
* Provides type-safe equality and inequality operators, implemented with
* macros for efficiency reasons.
*/
implicit class TypeSafeEquals[T](val self: T) extends AnyVal {
def ===[U](other: U): Boolean = macro TypeSafeEquals.equalsImpl[T, U]
def ≟[U](other: U): Boolean = macro TypeSafeEquals.equalsImpl[T, U]
def !==[U](other: U): Boolean = macro TypeSafeEquals.notEqualsImpl[T, U]
def ≠[U](other: U): Boolean = macro TypeSafeEquals.notEqualsImpl[T, U]
}
object TypeSafeEquals {
def equalsImpl[T : c.WeakTypeTag, U : c.WeakTypeTag](c: Context)(other: c.Expr[T]): c.Expr[Boolean] = {
import c.universe._
def canProve[A : WeakTypeTag] =
c.inferImplicitValue(weakTypeOf[A], silent=true) != EmptyTree
val selfExpr = c.Expr[T](Select(c.prefix.tree, newTermName("self")))
if (canProve[T <:< U] || canProve[U <:< T])
reify(selfExpr.splice == other.splice)
else
c.abort(c.macroApplication.pos, s"Cannot compare unrelated types ${weakTypeOf[T]} and ${weakTypeOf[U]}")
}
def notEqualsImpl[T : c.WeakTypeTag, U : c.WeakTypeTag](c: Context)(other: c.Expr[T]): c.Expr[Boolean] = {
import c.universe._
val equality = equalsImpl[T, U](c)(other)
reify(!equality.splice)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment