import scala.annotation.implicitNotFound
import scala.reflect.ClassTag
object Test {
import Phantom_=::=._
// import Normal_=::=._
def main(args: Array[String]): Unit = {
foo(1, 2)
foo2(Array(1), Array(1))
bar(Array(1))
bar2(1)
}
def foo[A, B](a: A, b: B)(implicit ev: =::=[A, B]): B = {
ev.apply(a)
SafeCast(a)
}
def foo2[A, B](a: Array[A], b: Array[B])(implicit ev: =::=[A, B]) = {
b(0) = ev(a.head)
b(0) = SafeCast(a.head)
}
def bar[C](a: Array[C])(implicit ev: =::=[C, Int]) = foo2(a, Array(2))
def bar2[C: ClassTag](a: C)(implicit ev: =::=[C, Int]) = foo2(Array(a), Array(2))
}
object Normal_=::= {
@implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.")
sealed abstract class =::=[From, To] extends (From => To) with Serializable
private[this] final val singleton_=::= = new =::=[Any, Any] { def apply(x: Any): Any = x }
object =::= {
implicit def tpEquals[A]: A =::= A = singleton_=::=.asInstanceOf[A =::= A]
}
}
object Phantom_=::= extends Phantom {
@implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.")
type =::=[A,B] <: this.Any
implicit inline def tpEquals[A]: A =::= A = assume
implicit class Cast[From, To](ev: From =::= To) { // Could be a AnyVal if we support them for Phantom
inline def apply(a: From): To = a.asInstanceOf[To] // safe cast, we have an evidence to prove it
}
object SafeCast { // 0 overhead on application side
inline def apply[From, To](a: From)(implicit ev: From =::= To): To = a.asInstanceOf[To]
}
}
Last active
July 14, 2017 10:51
-
-
Save nicolasstucki/02eddd8f67f2652b049b3500e20db475 to your computer and use it in GitHub Desktop.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment