@@ -62,6 +62,30 @@ import dotty.tools.dotc.core.quoted._
6262 * )
6363 * ```
6464 * and then performs the same transformation on `'{ ... x1$1.unary_~ ... x2$1.unary_~ ...}`.
65+ *
66+ *
67+ * For inline macro definitions we assume that we have a single ~ directly as the RHS.
68+ * We will transform the definition from
69+ * ```
70+ * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Z = ~{ ... T1 ... x ... '(y) ... }
71+ * ```
72+ * to
73+ * ```
74+ * inline def foo[T1, ...](inline x1: X, ..., y1: Y, ....): Seq[Any] => Object = { (args: Seq[Any]) => {
75+ * val T1$1 = args(0).asInstanceOf[Type[T1]]
76+ * ...
77+ * val x1$1 = args(0).asInstanceOf[X]
78+ * ...
79+ * val y1$1 = args(1).asInstanceOf[Expr[Y]]
80+ * ...
81+ * { ... T1$1.unary_~ ... x ... '(y1$1.unary_~) ... }
82+ * }
83+ * ```
84+ * Note: the parameters of `foo` are kept for simple overloading resolution but they are not used in the body of `foo`.
85+ *
86+ * At inline site we will call reflectively the static method `foo` with dummy parameters, which will return a
87+ * precompiled version of the function that will evaluate the `Expr[Z]` that `foo` produces. The lambda is then called
88+ * at the inline site with the lifted arguments of the inlined call.
6589 */
6690class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
6791 import ast .tpd ._
@@ -444,13 +468,8 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
444468 val captured = mutable.LinkedHashMap .empty[Symbol , Tree ]
445469 val captured2 = capturer(captured)
446470 outer.enteredSyms.foreach(s => capturers.put(s, captured2))
447- if (ctx.owner.owner.is(Macro )) {
448- outer.enteredSyms.reverse.foreach(s => {
449- assert(s.is(Param ))
450- assert(s.owner == ctx.owner.owner)
451- captured2(ref(s))
452- })
453- }
471+ if (ctx.owner.owner.is(Macro ))
472+ outer.enteredSyms.reverse.foreach(s => captured2(ref(s)))
454473 val tree2 = transform(tree)
455474 capturers --= outer.enteredSyms
456475 seq(captured.result().valuesIterator.toList, tree2)
@@ -524,15 +543,31 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
524543 case _ : Import =>
525544 tree
526545 case tree : DefDef if tree.symbol.is(Macro ) && level == 0 =>
527- if (! tree.symbol.isStatic)
528- ctx.error(" Inline macro method must be a static method." , tree.pos)
529- markDef(tree)
530- val reifier = nested(isQuote = true )
531- reifier.transform(tree) // Ignore output, we only need the its embedding
532- assert(reifier.embedded.size == 1 )
533- val macroLambda = reifier.embedded.head
534- // replace macro code by lambda used to evaluate the macro expansion
535- cpy.DefDef (tree)(tpt = TypeTree (defn.ObjectType ), rhs = macroLambda)
546+ tree.rhs match {
547+ case InlineSplice (_) =>
548+ if (! tree.symbol.isStatic)
549+ ctx.error(" Inline macro method must be a static method." , tree.pos)
550+ markDef(tree)
551+ val reifier = nested(isQuote = true )
552+ reifier.transform(tree) // Ignore output, we only need the its embedding
553+ assert(reifier.embedded.size == 1 )
554+ val lambda = reifier.embedded.head
555+ // replace macro code by lambda used to evaluate the macro expansion
556+ cpy.DefDef (tree)(tpt = TypeTree (macroReturnType), rhs = lambda)
557+ case _ =>
558+ ctx.error(
559+ """ Malformed inline macro.
560+ |
561+ |Expected the ~ to be at the top of the RHS:
562+ | inline def foo(...): Int = ~impl(...)
563+ |or
564+ | inline def foo(...): Int = ~{
565+ | val x = 1
566+ | impl(... x ...)
567+ | }
568+ """ .stripMargin, tree.rhs.pos)
569+ EmptyTree
570+ }
536571 case _ =>
537572 markDef(tree)
538573 checkLevel(mapOverTree(enteredSyms))
@@ -561,21 +596,25 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
561596 }
562597
563598 def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type = {
564- /** Transforms the return type
599+ /** Transforms the return type of
565600 * inline def foo(...): X = ~(...)
566601 * to
567- * inline def foo(...): Seq[Any] => Object = (args: Seq[Any]) => ...
602+ * inline def foo(...): Seq[Any] => Expr[Any] = (args: Seq[Any]) => ...
568603 */
569604 def transform (tp : Type ): Type = tp match {
570- case tp : PolyType => PolyType (tp.paramNames, tp.paramInfos, transform(tp.resType))
571605 case tp : MethodType => MethodType (tp.paramNames, tp.paramInfos, transform(tp.resType))
606+ case tp : PolyType => PolyType (tp.paramNames, tp.paramInfos, transform(tp.resType))
572607 case tp : ExprType => ExprType (transform(tp.resType))
573- case _ => defn. FunctionType ( 1 ).appliedTo(defn. SeqType .appliedTo(defn. AnyType ), defn. ObjectType )
608+ case _ => macroReturnType
574609 }
575610 transform(tp)
576611 }
577612
578- override protected def mayChange (sym : Symbol )(implicit ctx : Context ) = sym.is(Macro )
613+ override protected def mayChange (sym : Symbol )(implicit ctx : Context ): Boolean = sym.is(Macro )
614+
615+ /** Returns the type of the compiled macro as a lambda: Seq[Any] => Object */
616+ private def macroReturnType (implicit ctx : Context ): Type =
617+ defn.FunctionType (1 ).appliedTo(defn.SeqType .appliedTo(defn.AnyType ), defn.ObjectType )
579618}
580619
581620object ReifyQuotes {
0 commit comments