Skip to content

Instantly share code, notes, and snippets.

@Jasper-M
Last active November 2, 2022 02:18
Show Gist options
  • Save Jasper-M/1b6540fecfa3af9094dab1614038a1b5 to your computer and use it in GitHub Desktop.
Save Jasper-M/1b6540fecfa3af9094dab1614038a1b5 to your computer and use it in GitHub Desktop.
Typeclass that provides evidence that a type has a companion object, and access to the object.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
trait HasCompanion[A] {
type Type
def companion: Type
}
object HasCompanion {
type Aux[A,C] = HasCompanion[A] { type Type = C }
def apply[A](implicit hc: HasCompanion[A]): hc.type = hc
implicit def mkHasCompanion[A,C]: Aux[A,C] = macro MacroHasCompanion.hasCompanionMacro[A]
}
object MacroHasCompanion {
def hasCompanionMacro[A: c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
val aTpe = weakTypeOf[A]
val companionTpe = aTpe.companion
val companion = aTpe.typeSymbol.companion
val HasCompanion = weakTypeOf[HasCompanion[A]]
if (companionTpe =:= NoType)
c.abort(c.enclosingPosition, s"No companion found for type $aTpe.")
else if (!companion.isModule)
c.abort(c.enclosingPosition, s"$aTpe is the companion.")
else
q"new $HasCompanion { type Type = $companionTpe; def companion = $companion }"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment