@@ -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.
@@ -230,10 +231,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
230231 ! sym.is(Param ) || levelOK(sym.owner)
231232 }
232233
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-
237234 /** Try to heal phase-inconsistent reference to type `T` using a local type definition.
238235 * @return None if successful
239236 * @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
@@ -292,7 +289,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
292289 outer.checkType(pos).foldOver(acc, tp)
293290 }
294291 else {
295- if (tp.isTerm) spliceOutsideQuotes( pos)
292+ if (tp.isTerm) ctx.error( i " splice outside quotes " , pos)
296293 tp
297294 }
298295 case tp : NamedType =>
@@ -418,14 +415,28 @@ class ReifyQuotes extends MacroTransformWithImplicits {
418415 val body1 = nested(isQuote = false ).transform(splice.qualifier)
419416 body1.select(splice.name)
420417 }
421- else if (! inQuote && level == 0 && ! ctx.owner.is(Transparent )) {
422- spliceOutsideQuotes(splice.pos)
423- splice
424- }
425- else {
418+ else if (level == 1 ) {
426419 val (body1, quotes) = nested(isQuote = false ).split(splice.qualifier)
427420 makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
428421 }
422+ else if (enclosingInlineds.nonEmpty) { // level 0 in an inline call
423+ val spliceCtx = ctx.outer // drop the last `inlineContext`
424+ val pos : SourcePosition = Decorators .sourcePos(enclosingInlineds.head.pos)(spliceCtx)
425+ val evaluatedSplice = Splicer .splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withPos(splice.pos)
426+ if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
427+ }
428+ else if (! ctx.owner.ownersIterator.exists(_.is(Transparent ))) { // level 0 outside a transparent definition
429+ ctx.error(i " splice outside quotes or transparent method " , splice.pos)
430+ splice
431+ }
432+ else if (Splicer .canBeSpliced(splice.qualifier)) { // level 0 inside a transparent definition
433+ nested(isQuote = false ).split(splice.qualifier) // Just check PCP
434+ splice
435+ }
436+ else { // level 0 inside a transparent definition
437+ ctx.error(" Malformed macro call. The contents of the ~ must call a static method and arguments must be quoted or transparent." .stripMargin, splice.pos)
438+ splice
439+ }
429440 }
430441
431442 /** Transforms the contents of a nested splice
@@ -550,39 +561,10 @@ class ReifyQuotes extends MacroTransformWithImplicits {
550561 val last = enteredSyms
551562 stats.foreach(markDef)
552563 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
565564 case _ : Import =>
566565 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- }
566+ case tree : DefDef if tree.symbol.is(Macro ) && level == 0 && enclosingInlineds.nonEmpty =>
567+ EmptyTree // Already checked at definition site and already inlined
586568 case _ =>
587569 markDef(tree)
588570 checkLevel(mapOverTree(enteredSyms))
@@ -616,18 +598,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
616598 acc.select(" ::" .toTermName).appliedToType(tpe).appliedTo(x)
617599 }
618600 }
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- }
631601 }
632602}
633603
0 commit comments