Skip to content

Instantly share code, notes, and snippets.

@neontorrent
Last active August 7, 2019 19:10
Show Gist options
  • Save neontorrent/ec379039db9c5098b2cf77b3b0bc45c5 to your computer and use it in GitHub Desktop.
Save neontorrent/ec379039db9c5098b2cf77b3b0bc45c5 to your computer and use it in GitHub Desktop.
/* Ambiguous
def compare[T1, T2](a: T1, b: T2)(implicit ev: T1 => T2) = compareImpl[T2](ev(a), b)
def compare[T1, T2](a: T1, b: T2)(implicit ev: T2 => T1) = compareImpl[T1](a, ev(b))
def compareImpl[T](a: T, b: T) = a == b
*/
import scala.reflect.runtime.universe._
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
import scala.language.implicitConversions
def compare[T1, T2](a: T1, b: T2): Boolean = macro compareImpl[T1,T2]
def compareImpl[T1: c.WeakTypeTag, T2: c.WeakTypeTag](c: Context)(a: c.Expr[T1], b: c.Expr[T2]): c.Expr[Boolean] = {
import c.universe._
val f1 = c.inferImplicitValue(c.weakTypeOf[T1 => T2])
if (f1.isEmpty) {
val f2 = c.inferImplicitValue(c.weakTypeOf[T2 => T1])
if(f2.isEmpty) {
c.abort(c.enclosingPosition, s"Cannot find ${weakTypeOf[T1]}=> ${weakTypeOf[T2]}")
}
else {
c.Expr(q"$f2.apply($b) == $a")
}
}
else {
c.Expr(q"$f1.apply($a) == $b")
}
}
case class Foo(s: String)
case class Bar(s: String)
implicit def foo2bar(f: Foo): Bar = Bar(f.s)
println(compare(Foo("hello"), Bar("hello")))
println(compare(Bar("hello"), Foo("hello")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment