@@ -5,7 +5,7 @@ import core._
55import Decorators ._ , Flags ._ , Types ._ , Contexts ._ , Symbols ._ , Constants ._
66import Flags ._
77import ast .Trees ._
8- import ast .{TreeTypeMap , untpd }
8+ import ast .{TreeTypeMap , tpd , untpd }
99import util .Positions ._
1010import tasty .TreePickler .Hole
1111import SymUtils ._
@@ -16,6 +16,7 @@ import typer.Implicits.SearchFailureType
1616import scala .collection .mutable
1717import dotty .tools .dotc .core .StdNames ._
1818import dotty .tools .dotc .core .quoted ._
19+ import dotty .tools .dotc .util .SourcePosition
1920
2021
2122/** Translates quoted terms and types to `unpickle` method calls.
@@ -78,7 +79,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
7879 if (ctx.compilationUnit.containsQuotesOrSplices) super .run
7980
8081 protected def newTransformer (implicit ctx : Context ): Transformer =
81- new Reifier (inQuote = false , null , 0 , new LevelInfo , new mutable.ListBuffer [Tree ])
82+ new Reifier (inQuote = false , null , 0 , new LevelInfo , new mutable.ListBuffer [Tree ], null )
8283
8384 private class LevelInfo {
8485 /** A map from locally defined symbols to the staging levels of their definitions */
@@ -108,16 +109,22 @@ class ReifyQuotes extends MacroTransformWithImplicits {
108109 * and `l == -1` is code inside a top level splice (in an transparent method).
109110 * @param levels a stacked map from symbols to the levels in which they were defined
110111 * @param embedded a list of embedded quotes (if `inSplice = true`) or splices (if `inQuote = true`
112+ * @param inlinedAtPos if non null, the reifier is inside an inlined call with position `inlinedAtPos`
111113 */
112114 private class Reifier (inQuote : Boolean , val outer : Reifier , val level : Int , levels : LevelInfo ,
113- val embedded : mutable.ListBuffer [Tree ]) extends ImplicitsTransformer {
115+ val embedded : mutable.ListBuffer [Tree ], inlinedAtPos : SourcePosition ) extends ImplicitsTransformer {
114116 import levels ._
115117 assert(level >= - 1 )
116118
117119 /** A nested reifier for a quote (if `isQuote = true`) or a splice (if not) */
118120 def nested (isQuote : Boolean ): Reifier = {
119121 val nestedEmbedded = if (level > 1 || (level == 1 && isQuote)) embedded else new mutable.ListBuffer [Tree ]
120- new Reifier (isQuote, this , if (isQuote) level + 1 else level - 1 , levels, nestedEmbedded)
122+ new Reifier (isQuote, this , if (isQuote) level + 1 else level - 1 , levels, nestedEmbedded, inlinedAtPos)
123+ }
124+
125+ def inlined (inlinedAt : SourcePosition ): Reifier = {
126+ assert(level == 0 )
127+ new Reifier (true , this , 0 , levels, embedded, inlinedAt)
121128 }
122129
123130 /** We are in a `~(...)` context that is not shadowed by a nested `'(...)` */
@@ -126,6 +133,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
126133 /** We are not in a `~(...)` or a `'(...)` */
127134 def isRoot : Boolean = outer == null
128135
136+ def isInlined : Boolean = inlinedAtPos != null
137+
129138 /** A map from type ref T to expressions of type `quoted.Type[T]`".
130139 * These will be turned into splices using `addTags` and represent type variables
131140 * that can be possibly healed.
@@ -230,10 +239,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
230239 ! sym.is(Param ) || levelOK(sym.owner)
231240 }
232241
233- /** Issue a "splice outside quote" error unless we are in the body of a transparent method */
234- def spliceOutsideQuotes (pos : Position )(implicit ctx : Context ): Unit =
235- ctx.error(i " splice outside quotes " , pos)
236-
237242 /** Try to heal phase-inconsistent reference to type `T` using a local type definition.
238243 * @return None if successful
239244 * @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
@@ -292,7 +297,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
292297 outer.checkType(pos).foldOver(acc, tp)
293298 }
294299 else {
295- if (tp.isTerm) spliceOutsideQuotes( pos)
300+ if (tp.isTerm) ctx.error( i " splice outside quotes " , pos)
296301 tp
297302 }
298303 case tp : NamedType =>
@@ -418,14 +423,34 @@ class ReifyQuotes extends MacroTransformWithImplicits {
418423 val body1 = nested(isQuote = false ).transform(splice.qualifier)
419424 body1.select(splice.name)
420425 }
421- else if (! inQuote && level == 0 && ! ctx.owner.is(Transparent )) {
422- spliceOutsideQuotes(splice.pos)
423- splice
424- }
425- else {
426+ else if (level == 1 ) {
426427 val (body1, quotes) = nested(isQuote = false ).split(splice.qualifier)
427428 makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
428429 }
430+ else if (level == - 1 ) {
431+ // TODO add test
432+ ctx.error(" Cannot splice inside a top-level splice" , splice.pos)
433+ splice
434+ }
435+ else if (isInlined) { // level 0 in an inline call
436+ val evaluatedSplice = Splicer .splice(splice.qualifier, inlinedAtPos, macroClassLoader).withPos(splice.pos)
437+ if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
438+ } else if (ctx.owner.is(Transparent )) { // level 0 in an inline definition
439+ if (! Splicer .canBeSpliced(splice.qualifier))
440+ ctx.error( // TODO adapt error message
441+ """ Malformed inline macro.
442+ |
443+ |Expected the ~ to be at the top of the RHS:
444+ | inline def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y))
445+ |
446+ |The contents of the splice must call a static method. Arguments must be quoted or inlined.
447+ """ .stripMargin, splice.pos)
448+ splice
449+ }
450+ else { // level 0
451+ ctx.error(i " splice outside quotes or inline method " , splice.pos)
452+ splice
453+ }
429454 }
430455
431456 /** Transforms the contents of a nested splice
@@ -550,39 +575,12 @@ class ReifyQuotes extends MacroTransformWithImplicits {
550575 val last = enteredSyms
551576 stats.foreach(markDef)
552577 mapOverTree(last)
553- case Inlined (call, bindings, InlineSplice (spliced)) if ! call.isEmpty =>
554- val tree2 =
555- if (level == 0 ) {
556- val evaluatedSplice = Splicer .splice(spliced, tree.pos, macroClassLoader).withPos(tree.pos)
557- if (ctx.reporter.hasErrors) EmptyTree
558- else transform(cpy.Inlined (tree)(call, bindings, evaluatedSplice))
559- }
560- else super .transform(tree)
561-
562- // due to value-discarding which converts an { e } into { e; () })
563- if (tree.tpe =:= defn.UnitType ) Block (tree2 :: Nil , Literal (Constant (())))
564- else tree2
578+ case tree : Inlined if ! isInlined && level == 0 =>
579+ inlined(tree.pos).transform(tree)
565580 case _ : Import =>
566581 tree
567- case tree : DefDef if tree.symbol.is(Macro ) && level == 0 =>
568- if (enclosingInlineds.nonEmpty)
569- return EmptyTree // Already checked at definition site and already inlined
570- markDef(tree)
571- tree.rhs match {
572- case InlineSplice (_) =>
573- mapOverTree(enteredSyms) // Ignore output, only check PCP
574- cpy.DefDef (tree)(rhs = defaultValue(tree.rhs.tpe))
575- case _ =>
576- ctx.error(
577- """ Malformed transparent macro.
578- |
579- |Expected the ~ to be at the top of the RHS:
580- | transparent def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y))
581- |
582- |The contents of the splice must call a static method. Arguments must be quoted or inlined.
583- """ .stripMargin, tree.rhs.pos)
584- EmptyTree
585- }
582+ case tree : DefDef if tree.symbol.is(Macro ) && level == 0 && enclosingInlineds.nonEmpty =>
583+ EmptyTree // Already checked at definition site and already inlined
586584 case _ =>
587585 markDef(tree)
588586 checkLevel(mapOverTree(enteredSyms))
@@ -616,18 +614,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
616614 acc.select(" ::" .toTermName).appliedToType(tpe).appliedTo(x)
617615 }
618616 }
619-
620- /** InlineSplice is used to detect cases where the expansion
621- * consists of a (possibly multiple & nested) block or a sole expression.
622- */
623- object InlineSplice {
624- def unapply (tree : Tree )(implicit ctx : Context ): Option [Tree ] = tree match {
625- case Select (qual, _) if tree.symbol.isSplice && Splicer .canBeSpliced(qual) => Some (qual)
626- case Block (List (stat), Literal (Constant (()))) => unapply(stat)
627- case Block (Nil , expr) => unapply(expr)
628- case _ => None
629- }
630- }
631617 }
632618}
633619
0 commit comments