@@ -13,6 +13,7 @@ import MegaPhase.MiniPhase
1313import SymUtils ._
1414import NameKinds ._
1515import dotty .tools .dotc .ast .tpd .Tree
16+ import dotty .tools .dotc .core .DenotTransformers .InfoTransformer
1617import typer .Implicits .SearchFailureType
1718
1819import scala .collection .mutable
@@ -56,8 +57,32 @@ import dotty.tools.dotc.core.quoted._
5657 * )
5758 * ```
5859 * and then performs the same transformation on `'{ ... x1$1.unary_~ ... x2$1.unary_~ ...}`.
60+ *
61+ *
62+ * For inline macro definitions we assume that we have a single ~ directly as the RHS.
63+ * We will transform the definition from
64+ * ```
65+ * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Z = ~{ ... T1 ... x ... '(y) ... }
66+ * ```
67+ * to
68+ * ```
69+ * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Seq[Any] => Object = { (args: Seq[Any]) => {
70+ * val T1$1 = args(0).asInstanceOf[Type[T1]]
71+ * ...
72+ * val x1$1 = args(0).asInstanceOf[X]
73+ * ...
74+ * val y1$1 = args(1).asInstanceOf[Expr[Y]]
75+ * ...
76+ * { ... T1$1.unary_~ ... x ... '(y1$1.unary_~) ... }
77+ * }
78+ * ```
79+ * Note: the parameters of `foo` are kept for simple overloading resolution but they are not used in the body of `foo`.
80+ *
81+ * At inline site we will call reflectively the static method `foo` with dummy parameters, which will return a
82+ * precompiled version of the function that will evaluate the `Expr[Z]` that `foo` produces. The lambda is then called
83+ * at the inline site with the lifted arguments of the inlined call.
5984 */
60- class ReifyQuotes extends MacroTransformWithImplicits {
85+ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
6186 import ast .tpd ._
6287
6388 override def phaseName : String = " reifyQuotes"
@@ -408,13 +433,15 @@ class ReifyQuotes extends MacroTransformWithImplicits {
408433 var i = 0
409434 transformWithCapturer(tree)(
410435 (captured : mutable.Map [Symbol , Tree ]) => {
411- (tree : RefTree ) => {
436+ (tree : Tree ) => {
412437 def newCapture = {
438+ val tpw = tree.tpe.widen
413439 val argTpe =
414- if (tree.isTerm) defn.QuotedExprType .appliedTo(tree.tpe.widen)
415- else defn.QuotedTypeType .appliedTo(defn.AnyType )
440+ if (tree.isType) defn.QuotedTypeType .appliedTo(tpw)
441+ else if (tree.symbol.is(Inline )) tpw // inlined term
442+ else defn.QuotedExprType .appliedTo(tpw)
416443 val selectArg = arg.select(nme.apply).appliedTo(Literal (Constant (i))).asInstance(argTpe)
417- val capturedArg = SyntheticValDef (UniqueName .fresh(tree.name.toTermName).toTermName, selectArg)
444+ val capturedArg = SyntheticValDef (UniqueName .fresh(tree.symbol. name.toTermName).toTermName, selectArg)
418445 i += 1
419446 embedded += tree
420447 captured.put(tree.symbol, capturedArg)
@@ -432,11 +459,12 @@ class ReifyQuotes extends MacroTransformWithImplicits {
432459 Closure (meth, tss => body(tss.head.head)(ctx.withOwner(meth)).changeOwner(ctx.owner, meth))
433460 }
434461
435- private def transformWithCapturer (tree : Tree )(
436- capturer : mutable.Map [Symbol , Tree ] => RefTree => Tree )(implicit ctx : Context ): Tree = {
462+ private def transformWithCapturer (tree : Tree )(capturer : mutable.Map [Symbol , Tree ] => Tree => Tree )(implicit ctx : Context ): Tree = {
437463 val captured = mutable.LinkedHashMap .empty[Symbol , Tree ]
438464 val captured2 = capturer(captured)
439465 outer.enteredSyms.foreach(s => capturers.put(s, captured2))
466+ if (ctx.owner.owner.is(Macro ))
467+ outer.enteredSyms.reverse.foreach(s => captured2(ref(s)))
440468 val tree2 = transform(tree)
441469 capturers --= outer.enteredSyms
442470 seq(captured.result().valuesIterator.toList, tree2)
@@ -445,8 +473,9 @@ class ReifyQuotes extends MacroTransformWithImplicits {
445473 /** Returns true if this tree will be captured by `makeLambda` */
446474 private def isCaptured (tree : RefTree , level : Int )(implicit ctx : Context ): Boolean = {
447475 // Check phase consistency and presence of capturer
448- level == 1 && ! tree.symbol.is(Inline ) && levelOf.get(tree.symbol).contains(1 ) &&
449- capturers.contains(tree.symbol)
476+ ( (level == 1 && levelOf.get(tree.symbol).contains(1 )) ||
477+ (level == 0 && tree.symbol.is(Inline ))
478+ ) && capturers.contains(tree.symbol)
450479 }
451480
452481 /** Transform `tree` and return the resulting tree and all `embedded` quotes
@@ -485,7 +514,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
485514 splice(tree)
486515 case tree : RefTree if isCaptured(tree, level) =>
487516 val capturer = capturers(tree.symbol)
488- splice(capturer(tree).select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~ ))
517+ if (tree.symbol.is(Inline )) capturer(tree)
518+ else splice(capturer(tree).select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~ ))
489519 case Block (stats, _) =>
490520 val last = enteredSyms
491521 stats.foreach(markDef)
@@ -498,7 +528,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
498528 }
499529
500530 val tree1 =
501- if (level == 0 ) cpy.Inlined (tree)(call, stagedBindings, Splicer .splice(seq( splicedBindings, body ).withPos(tree.pos) ))
531+ if (level == 0 ) cpy.Inlined (tree)(call, stagedBindings, Splicer .splice(body, call, splicedBindings, tree.pos ).withPos(tree.pos))
502532 else seq(stagedBindings, cpy.Select (expansion)(cpy.Inlined (tree)(call, splicedBindings, body), name))
503533 val tree2 = transform(tree1)
504534
@@ -513,9 +543,12 @@ class ReifyQuotes extends MacroTransformWithImplicits {
513543 if (! tree.symbol.isStatic)
514544 ctx.error(" Inline macro method must be a static method." , tree.pos)
515545 markDef(tree)
516- nested(isQuote = true ).transform(tree)
517- // check macro code as it if appeared in a quoted context
518- cpy.DefDef (tree)(rhs = EmptyTree )
546+ val reifier = nested(isQuote = true )
547+ reifier.transform(tree) // Ignore output, we only need the its embedding
548+ assert(reifier.embedded.size == 1 )
549+ val lambda = reifier.embedded.head
550+ // replace macro code by lambda used to evaluate the macro expansion
551+ cpy.DefDef (tree)(tpt = TypeTree (macroReturnType), rhs = lambda)
519552 case _ =>
520553 ctx.error(
521554 """ Malformed inline macro.
@@ -556,6 +589,27 @@ class ReifyQuotes extends MacroTransformWithImplicits {
556589 }
557590 }
558591 }
592+
593+ def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type = {
594+ /** Transforms the return type of
595+ * inline def foo(...): X = ~(...)
596+ * to
597+ * inline def foo(...): Seq[Any] => Expr[Any] = (args: Seq[Any]) => ...
598+ */
599+ def transform (tp : Type ): Type = tp match {
600+ case tp : MethodType => MethodType (tp.paramNames, tp.paramInfos, transform(tp.resType))
601+ case tp : PolyType => PolyType (tp.paramNames, tp.paramInfos, transform(tp.resType))
602+ case tp : ExprType => ExprType (transform(tp.resType))
603+ case _ => macroReturnType
604+ }
605+ transform(tp)
606+ }
607+
608+ override protected def mayChange (sym : Symbol )(implicit ctx : Context ): Boolean = sym.is(Macro )
609+
610+ /** Returns the type of the compiled macro as a lambda: Seq[Any] => Object */
611+ private def macroReturnType (implicit ctx : Context ): Type =
612+ defn.FunctionType (1 ).appliedTo(defn.SeqType .appliedTo(defn.AnyType ), defn.ObjectType )
559613}
560614
561615object ReifyQuotes {
0 commit comments