@@ -62,6 +62,30 @@ import dotty.tools.dotc.core.quoted._
62
62
* )
63
63
* ```
64
64
* 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.
65
89
*/
66
90
class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
67
91
import ast .tpd ._
@@ -444,13 +468,8 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
444
468
val captured = mutable.LinkedHashMap .empty[Symbol , Tree ]
445
469
val captured2 = capturer(captured)
446
470
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)))
454
473
val tree2 = transform(tree)
455
474
capturers --= outer.enteredSyms
456
475
seq(captured.result().valuesIterator.toList, tree2)
@@ -524,15 +543,31 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
524
543
case _ : Import =>
525
544
tree
526
545
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
+ }
536
571
case _ =>
537
572
markDef(tree)
538
573
checkLevel(mapOverTree(enteredSyms))
@@ -561,21 +596,25 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
561
596
}
562
597
563
598
def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type = {
564
- /** Transforms the return type
599
+ /** Transforms the return type of
565
600
* inline def foo(...): X = ~(...)
566
601
* to
567
- * inline def foo(...): Seq[Any] => Object = (args: Seq[Any]) => ...
602
+ * inline def foo(...): Seq[Any] => Expr[Any] = (args: Seq[Any]) => ...
568
603
*/
569
604
def transform (tp : Type ): Type = tp match {
570
- case tp : PolyType => PolyType (tp.paramNames, tp.paramInfos, transform(tp.resType))
571
605
case tp : MethodType => MethodType (tp.paramNames, tp.paramInfos, transform(tp.resType))
606
+ case tp : PolyType => PolyType (tp.paramNames, tp.paramInfos, transform(tp.resType))
572
607
case tp : ExprType => ExprType (transform(tp.resType))
573
- case _ => defn. FunctionType ( 1 ).appliedTo(defn. SeqType .appliedTo(defn. AnyType ), defn. ObjectType )
608
+ case _ => macroReturnType
574
609
}
575
610
transform(tp)
576
611
}
577
612
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 )
579
618
}
580
619
581
620
object ReifyQuotes {
0 commit comments