Skip to content

Instantly share code, notes, and snippets.

@alexandru
Last active August 13, 2019 08:03
Show Gist options
  • Save alexandru/11375046 to your computer and use it in GitHub Desktop.
Save alexandru/11375046 to your computer and use it in GitHub Desktop.
// CONTEXT: https://groups.google.com/forum/#!topic/scala-user/8YpX1VkIkDs
import scala.annotation.implicitNotFound
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
/**
* Macro-driven type for proving that an implicit parameter does not exist
* in scope.
*/
@implicitNotFound("Cannot prove that Not[${T}] because an implicit for ${T} exists in scope")
sealed trait Not[T]
object Not {
/**
* Implicit instance for [[Not]], auto-generated via a macro.
*/
implicit def proof[T]: Not[T] = macro proofMacro[T]
def proofMacro[T : c.WeakTypeTag](c: whitebox.Context): c.Tree = {
import c.universe._
if (c.inferImplicitValue(weakTypeOf[T], silent=true) == EmptyTree)
reify(new Not[T] {}).tree
else
c.abort(c.macroApplication.pos, "Found an implicit, so can't find Not[T]")
}
}
// Example
scala> trait Foo
scala> trait Bar
scala> def something[T <: Foo](value: T)(implicit ev: Not[T <:< Bar]) = println("it works!")
//=> something: [T <: Foo](value: T)(implicit ev: experiments.NotMacro.Not[<:<[T,Bar]])Unit
scala> something(new Foo {})
//=> it works!
scala> something(new Foo with Bar {})
//=> <console>:12: error: cannot prove that Not[<:<[Foo with Bar,Bar]] because an implicit for <:<[Foo with Bar,Bar] exists in scope
//=> something(new Foo with Bar {})
//=> ^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment