@@ -7,13 +7,10 @@ import Flags._
77import ast .Trees ._
88import ast .{TreeTypeMap , untpd }
99import util .Positions ._
10- import StdNames ._
1110import tasty .TreePickler .Hole
12- import MegaPhase .MiniPhase
1311import SymUtils ._
1412import NameKinds ._
1513import dotty .tools .dotc .ast .tpd .Tree
16- import dotty .tools .dotc .core .DenotTransformers .InfoTransformer
1714import typer .Implicits .SearchFailureType
1815
1916import scala .collection .mutable
@@ -60,33 +57,9 @@ import dotty.tools.dotc.core.quoted._
6057 *
6158 *
6259 * For transparent macro definitions we assume that we have a single ~ directly as the RHS.
63- * We will transform the definition from
64- * ```
65- * transparent def foo[T1, ...] (transparent x1: X, ..., y1: Y, ....): Z = ~{ ... T1 ... x ... '(y) ... }
66- * ```
67- * to
68- * ```
69- * transparent def foo[T1, ...] (transparent 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- * { ... x1$1 .... '{ ... T1$1.unary_~ ... x1$1.toExpr.unary_~ ... y1$1.unary_~ ... } ... }
77- * }
78- * ```
79- * Where `transparent` parameters with type Boolean, Byte, Short, Int, Long, Float, Double, Char and String are
80- * passed as their actual runtime value. See `isStage0Value`. Other `transparent` arguments such as functions are handled
81- * like `y1: Y`.
82- *
83- * Note: the parameters of `foo` are kept for simple overloading resolution but they are not used in the body of `foo`.
84- *
85- * At inline site we will call reflectively the static method `foo` with dummy parameters, which will return a
86- * precompiled version of the function that will evaluate the `Expr[Z]` that `foo` produces. The lambda is then called
87- * at the inline site with the lifted arguments of the inlined call.
60+ * The Splicer is used to check that the RHS will be interpretable (with the `Splicer`) once inlined.
8861 */
89- class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
62+ class ReifyQuotes extends MacroTransformWithImplicits {
9063 import ast .tpd ._
9164
9265 /** Classloader used for loading macros */
@@ -255,7 +228,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
255228 ! sym.is(Param ) || levelOK(sym.owner)
256229 }
257230
258- /** Issue a "splice outside quote" error unless we ar in the body of a transparent method */
231+ /** Issue a "splice outside quote" error unless we are in the body of a transparent method */
259232 def spliceOutsideQuotes (pos : Position )(implicit ctx : Context ): Unit =
260233 ctx.error(i " splice outside quotes " , pos)
261234
@@ -267,7 +240,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
267240 def tryHeal (tp : Type , pos : Position )(implicit ctx : Context ): Option [String ] = tp match {
268241 case tp : TypeRef =>
269242 if (level == 0 ) {
270- assert(ctx.owner.ownersIterator.exists(_.is(Macro )))
243+ assert(ctx.owner.ownersIterator.exists(_.is(Transparent )))
271244 None
272245 } else {
273246 val reqType = defn.QuotedTypeType .appliedTo(tp)
@@ -298,7 +271,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
298271 else i " ${sym.name}.this "
299272 if (! isThis && sym.maybeOwner.isType && ! sym.is(Param ))
300273 check(sym.owner, sym.owner.thisType, pos)
301- else if (level == 1 && sym.isType && sym.is(Param ) && sym.owner.is(Macro ) && ! outer.isRoot)
274+ else if (level == 1 && sym.isType && sym.is(Param ) && sym.owner.is(Transparent ) && ! outer.isRoot)
302275 importedTags(sym.typeRef) = capturers(sym)(ref(sym))
303276 else if (sym.exists && ! sym.isStaticOwner && ! levelOK(sym))
304277 for (errMsg <- tryHeal(tp, pos))
@@ -510,18 +483,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
510483 val captured = mutable.LinkedHashMap .empty[Symbol , Tree ]
511484 val captured2 = capturer(captured)
512485
513- def registerCapturer (sym : Symbol ): Unit = capturers.put(sym, captured2)
514- def forceCapture (sym : Symbol ): Unit = captured2(ref(sym))
515-
516- outer.enteredSyms.foreach(registerCapturer)
517-
518- if (ctx.owner.owner.is(Macro )) {
519- registerCapturer(defn.TastyTopLevelSplice_tastyContext )
520- // Force a macro to have the context in first position
521- forceCapture(defn.TastyTopLevelSplice_tastyContext )
522- // Force all parameters of the macro to be created in the definition order
523- outer.enteredSyms.reverse.foreach(forceCapture)
524- }
486+ outer.enteredSyms.foreach(sym => capturers.put(sym, captured2))
525487
526488 val tree2 = transform(tree)
527489 capturers --= outer.enteredSyms
@@ -582,16 +544,12 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
582544 val last = enteredSyms
583545 stats.foreach(markDef)
584546 mapOverTree(last)
585- case Inlined (call, bindings, InlineSplice (expansion @ Select (body, name))) if ! call.isEmpty =>
586- assert(call.symbol.is(Macro ))
547+ case Inlined (call, bindings, InlineSplice (spliced)) if ! call.isEmpty =>
587548 val tree2 =
588549 if (level == 0 ) {
589- // Simplification of the call done in PostTyper for non-macros can also be performed now
590- // see PostTyper `case Inlined(...) =>` for description of the simplification
591- val call2 = Ident (call.symbol.topLevelClass.typeRef).withPos(call.pos)
592- val spliced = Splicer .splice(body, call, bindings, tree.pos, macroClassLoader).withPos(tree.pos)
550+ val evaluatedSplice = Splicer .splice(spliced, tree.pos, macroClassLoader).withPos(tree.pos)
593551 if (ctx.reporter.hasErrors) EmptyTree
594- else transform(cpy.Inlined (tree)(call2 , bindings, spliced ))
552+ else transform(cpy.Inlined (tree)(call , bindings, evaluatedSplice ))
595553 }
596554 else super .transform(tree)
597555
@@ -607,22 +565,16 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
607565 ctx.error(" Transparent macro method must be a static method." , tree.pos)
608566 markDef(tree)
609567 val reifier = nested(isQuote = true )
610- reifier.transform(tree) // Ignore output, we only need the its embedding
611- assert(reifier.embedded.size == 1 )
612- val lambda = reifier.embedded.head
613- // replace macro code by lambda used to evaluate the macro expansion
614- cpy.DefDef (tree)(tpt = TypeTree (macroReturnType), rhs = lambda)
568+ reifier.transform(tree) // Ignore output, only check PCP
569+ cpy.DefDef (tree)(rhs = defaultValue(tree.rhs.tpe))
615570 case _ =>
616571 ctx.error(
617572 """ Malformed transparent macro.
618573 |
619574 |Expected the ~ to be at the top of the RHS:
620- | transparent def foo(...): Int = ~impl(...)
621- |or
622- | transparent def foo(...): Int = ~{
623- | val x = 1
624- | impl(... x ...)
625- | }
575+ | transparent def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y))
576+ |
577+ |The contents of the splice must call a static method. Arguments must be quoted or inlined.
626578 """ .stripMargin, tree.rhs.pos)
627579 EmptyTree
628580 }
@@ -651,7 +603,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
651603 }
652604
653605 private def isStage0Value (sym : Symbol )(implicit ctx : Context ): Boolean =
654- (sym.is(Transparent ) && sym.owner.is(Macro ) && ! defn.isFunctionType(sym.info)) ||
606+ (sym.is(Transparent ) && sym.owner.is(Transparent ) && ! defn.isFunctionType(sym.info)) ||
655607 sym == defn.TastyTopLevelSplice_tastyContext // intrinsic value at stage 0
656608
657609 private def liftList (list : List [Tree ], tpe : Type )(implicit ctx : Context ): Tree = {
@@ -664,38 +616,14 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
664616 * consists of a (possibly multiple & nested) block or a sole expression.
665617 */
666618 object InlineSplice {
667- def unapply (tree : Tree )(implicit ctx : Context ): Option [Select ] = {
668- tree match {
669- case expansion : Select if expansion.symbol.isSplice => Some (expansion)
670- case Block (List (stat), Literal (Constant (()))) => unapply(stat)
671- case Block (Nil , expr) => unapply(expr)
672- case _ => None
673- }
619+ def unapply (tree : Tree )(implicit ctx : Context ): Option [Tree ] = tree match {
620+ case Select (qual, _) if tree.symbol.isSplice && Splicer .canBeSpliced(qual) => Some (qual)
621+ case Block (List (stat), Literal (Constant (()))) => unapply(stat)
622+ case Block (Nil , expr) => unapply(expr)
623+ case _ => None
674624 }
675625 }
676626 }
677-
678- def transformInfo (tp : Type , sym : Symbol )(implicit ctx : Context ): Type = {
679- /** Transforms the return type of
680- * transparent def foo(...): X = ~(...)
681- * to
682- * transparent def foo(...): Seq[Any] => Expr[Any] = (args: Seq[Any]) => ...
683- */
684- def transform (tp : Type ): Type = tp match {
685- case tp : MethodType => MethodType (tp.paramNames, tp.paramInfos, transform(tp.resType))
686- case tp : PolyType => PolyType (tp.paramNames, tp.paramInfos, transform(tp.resType))
687- case tp : ExprType => ExprType (transform(tp.resType))
688- case _ => macroReturnType
689- }
690- transform(tp)
691- }
692-
693- override protected def mayChange (sym : Symbol )(implicit ctx : Context ): Boolean =
694- ctx.compilationUnit.containsQuotesOrSplices && sym.isTerm && sym.is(Macro )
695-
696- /** Returns the type of the compiled macro as a lambda: Seq[Any] => Object */
697- private def macroReturnType (implicit ctx : Context ): Type =
698- defn.FunctionType (1 ).appliedTo(defn.SeqType .appliedTo(defn.AnyType ), defn.ObjectType )
699627}
700628
701629object ReifyQuotes {
0 commit comments