Skip to content

Instantly share code, notes, and snippets.

@xeno-by
Created September 8, 2014 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xeno-by/9f04c2bf931150c546fa to your computer and use it in GitHub Desktop.
Save xeno-by/9f04c2bf931150c546fa to your computer and use it in GitHub Desktop.
14:58 ~/Projects/211x/sandbox (2.11.x)$ cat Macros.scala
import scala.reflect.macros.whitebox._
import scala.language.experimental.macros
object Macros {
def macroImpl[T: c.WeakTypeTag](c: Context) = {
import c.universe._
val tpe = weakTypeTag[T].tpe
implicit class RichType(tpe: Type) {
def pre: Type = tpe match {
case SingleType(pre, _) => pre
case TypeRef(pre, _, _) => pre // this doesn't dealias!
case PolyType(_, underlying) => underlying.pre
case ExistentialType(_, underlying) => underlying.pre
case AnnotatedType(_, underlying) => underlying.pre
case _ => c.abort(c.enclosingPosition, s"unexpected type $tpe: ${showRaw(tpe)}")
}
}
val companionRef = c.internal.gen.mkAttributedRef(tpe.pre, tpe.typeSymbol.companion)
q"$companionRef"
}
def myMacro[T]: Any = macro macroImpl[T]
}
14:58 ~/Projects/211x/sandbox (2.11.x)$ cat Test.scala
trait Trt3{
case class Cls(i: Int)
}
trait Trt2{
object Obj2 extends Trt3
}
trait Trt1{
object Obj1 extends Trt2
}
object Obj extends Trt1
object Test extends App {
println(Macros.myMacro[Obj.Obj1.Obj2.Cls])
}
14:58 ~/Projects/211x/sandbox (2.11.x)$ scalac Macros.scala && scalac Test.scala && scala Test
Cls
14:59 ~/Projects/211x/sandbox (2.11.x)$
@retronym
Copy link

In 2.10

// ==> sandbox/Macro.scala <==
import scala.reflect.macros.Context
import scala.language.experimental.macros

object Macros {
  def macroImpl[T: c.WeakTypeTag](c: Context): c.Expr[Any] = {
    import c.universe._
    val tpe = weakTypeTag[T].tpe
    val symTab = c.universe.asInstanceOf[reflect.internal.SymbolTable]
    val pre = tpe.asInstanceOf[symTab.Type].prefix.asInstanceOf[Type]
    val companionRef = c.universe.treeBuild.mkAttributedRef(pre, tpe.typeSymbol.companionSymbol)
    c.Expr(companionRef)
  }

  def myMacro[T]: Any = macro macroImpl[T]
}

// ==> sandbox/Test.scala <==
trait Trt3{
  case class Cls(i: Int)
}
trait Trt2{
  object Obj2 extends Trt3
}
trait Trt1{
  object Obj1 extends Trt2
}
object Obj extends Trt1

object Test extends App {
  println(Macros.myMacro[Obj.Obj1.Obj2.Cls])

  class C {
    class D
    object D
  }
  val c = new C
  println(Macros.myMacro[c.D])
}
% (export V=v2.10.4; scalac-hash $V sandbox/Macro.scala && scalac-hash $V sandbox/Test.scala && scala-hash $V Test)
Cls
Test$C$D$@b4c966a

Note: the switch to downcasting to access Type#prefix, rather than the copy/pasted impl above isn't necessary.

Testing with prefixes like c above (which is not a "static" prefix) is important for this sort of thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment