Created
April 27, 2015 08:22
-
-
Save alexandru/39381aefb07e9248c178 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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