Detecting macro annotated type inside macro body

I want to use macro commands (macro-paradise, Scala 2.11) to generate synthetic features inside an object of annotated attribute objects. For example, given some abstraction of STM:

trait Var[Tx, A] {
  def apply()         (implicit tx: Tx): A
  def update(value: A)(implicit tx: Tx): Unit
}

I want to define a macro txnso that:

@txn trait Cell[A] {
  val value: A
  var next: Option[Cell[A]]
}

Will be re-synthesized in:

object Cell {
  trait Txn[-Tx, A] {
    def value: A
    def next: Var[Option[Cell.Txn[Tx, A]]] // !
  }
}
trait Cell[A] {
  val value: A
  var next: Option[Cell[A]]
}

I got to the object of a companion, an internal attribute and a member value. But obviously, in order for the member to nexthave an extended type (instead Option[Cell[A]], I need Option[Cell.Txn[Tx, A]]), I need to map the template to the type tree and rewrite it.

For example, let's say that the definition of a nextvalue in the original trait is Cellas follows:

case v @ ValDef(vMods, vName, tpt, rhs) =>

tpt, X[...], @txn X.Txn[Tx, ...]? , , X ? Cell , ?


, :

val tpt1 = tpt match {
  case tq"$ident" => $ident  // obviously don't change this?
  case ??? => ???
}
+4
1

, Scala. typecheck tpt , , X[A] X.Txn[Tx, A] X, TxnMarker, .

, ( ) ( typechecker) , ( Scala macros: (aka typechecked) ), .

, 2.10, 2.11 , , (, Var Var[...] - , , , , , Var). , , , .

import scala.reflect.macros.whitebox._
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation

trait Var[T]
trait TxnMarker

object txnMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    // NOTE: this pattern is only going to work with simple traits
    // for a full pattern that captures all traits, refer to Denys quasiquote guide:
    // http://den.sh/quasiquotes.html#defns-summary
    val q"$mods trait $name[..$targs] extends ..$parents { ..$stats }" = annottees.head.tree
    def rewire(tpt: Tree): Tree = {
      object RewireTransformer extends Transformer {
        override def transform(tree: Tree): Tree = tree match {
          case AppliedTypeTree(x @ RefTree(xqual, xname), a :: Nil) =>
            val dummyType = q"type SomeUniqueName[T] = $x[T]"
            val dummyTrait = q"$mods trait $name[..$targs] extends ..$parents { ..${stats :+ dummyType} }"
            val dummyTrait1 = c.typecheck(dummyTrait)
            val q"$_ trait $_[..$_] extends ..$_ { ..${_ :+ dummyType1} }" = dummyTrait1
            def refersToSelf = dummyTrait1.symbol == dummyType1.symbol.info.typeSymbol
            def refersToSubtypeOfTxnMarker = dummyType1.symbol.info.baseClasses.contains(symbolOf[TxnMarker])
            if (refersToSelf || refersToSubtypeOfTxnMarker) transform(tq"${RefTree(xqual, xname.toTermName)}.Txn[Tx, $a]")
            else super.transform(tree)
          case _ =>
            super.transform(tree)
        }
      }
      RewireTransformer.transform(tpt)
    }
    val stats1 = stats map {
      // this is a simplification, probably you'll also want to do recursive rewiring and whatnot
      // but I'm omitting that here to focus on the question at hand
      case q"$mods val $name: $tpt = $_" => q"$mods def $name: $tpt"
      case q"$mods var $name: $tpt = $_" => q"$mods def $name: Var[${rewire(tpt)}]"
      case stat => stat
    }
    val annottee1 = q"$mods trait $name[..$targs] extends ..${parents :+ tq"TxnMarker"} { ..$stats }"
    val companion = q"""
      object ${name.toTermName} {
        trait Txn[Tx, A] { ..$stats1 }
      }
    """
    c.Expr[Any](Block(List(annottee1, companion), Literal(Constant(()))))
  }
}

class txn extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro txnMacro.impl
}

, , , @txn - . info.baseClasses.contains(symbolOf[TxnMarker]) /, info, . SOE , - scalac .

, . , . , , , !

object Cell {
  trait Txn[-Tx, A] {
    def value: A
    def next: Var[Option[Cell.Txn[Tx, A]]]
  }
}
trait Cell[A] {
  val value: A
  var next: Option[Cell[A]]
}

:

object Cell {
  trait Txn[-Tx, A] {
    def value: A
    def next[U](implicit ev: TxnTypeMapper[Option[Cell[A]], U]): U
  }
}
trait Cell[A] {
  val value: A
  var next: Option[Cell[A]]
}

TxnTypeMapper[T, U] fundage materializer, Type => Type, Type.map, , , ( typer), . , , !!

+9

Source: https://habr.com/ru/post/1530779/


All Articles