I have a simpler solution, which also leverages ambiguity,
trait =!=[A, B]
implicit def neq[A, B] : A =!= B = null
// This pair excludes the A =:= B case
implicit def neqAmbig1[A] : A =!= A = null
implicit def neqAmbig2[A] : A =!= A = null
The original use case,
case class Foo[A,B](a : A, b : B)(implicit ev: A =!= B)
new Foo(1, "1")
new Foo("foo", Some("foo"))
// These don't compile
// new Foo(1, 1)
// new Foo("foo", "foo")
// new Foo(Some("foo"), Some("foo"))
Update
We can relate this to my "magical typesystem tricks" (thanks @jpp ;-) as follows,
type ?[T] = T => Nothing
implicit def neg[T, U](t : T)(implicit ev : T =!= U) : ?[U] = null
def notString[T <% ?[String]](t : T) = t
Sample REPL session,
scala> val ns1 = notString(1)
ns1: Int = 1
scala> val ns2 = notString(1.0)
ns2: Double = 1.0
scala> val ns3 = notString(Some("foo"))
ns3: Some[java.lang.String] = Some(foo)
scala> val ns4 = notString("foo")
<console>:14: error: No implicit view available from
java.lang.String => (String) => Nothing.
val ns4 = notString2("foo")
^
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…