Question

I'd like to use Sample#cap(String) in the following macro implementation for selectDynamic.

Is it possible?

// macro implementation
import scala.language.experimental.macros
import scala.reflect.macros._

object MyMacros {
  def selectDynamic(c: Context)(name: c.Expr[String]): c.Expr[String] = {
    // I expected `This` to refer a Sample instance, but actually it refers SampleSpec instance...
    c.Expr[String](Apply(TypeApply(Select(This(tpnme.EMPTY), newTermName("cap")), List(Ident(typeTag[String].tpe.typeSymbol))), List(name.tree)))
  }
}

// class which uses selectDynamic and macro
import scala.language.dynamics
class Sample extends Dynamic {
  def cap(name: String): String = name.toUpperCase
  def selectDynamic(name: String): String = macro MyMacros.selectDynamic
}

class SampleSpec extends FlatSpec with ShouldMatchers {
  it should "call dynamic" in {
    val sample = new Sample
    sample.foo should equal("FOO") // value cap is not a member of SampleSpec
  }
}
Was it helpful?

Solution

You can use c.prefix.tree instead of This.

// macro implementation
import scala.language.experimental.macros
import scala.reflect.macros.Context
import language.dynamics

object MyMacros {
  def selectDynamic(c: Context)(name: c.Expr[String]): c.Expr[String] = {
    import c.universe._
    // I expected `This` to refer a Sample instance, but actually it refers SampleSpec instance...
    c.Expr[String](Apply(Select(c.prefix.tree, newTermName("cap")), List(name.tree)))
  }
}

// class which uses selectDynamic and macro
class Sample extends Dynamic {
  def cap(name: String): String = name.toUpperCase
  def selectDynamic(name: String): String = macro MyMacros.selectDynamic
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top