@@ -7,13 +7,10 @@ import Flags._
7
7
import ast .Trees ._
8
8
import ast .{TreeTypeMap , untpd }
9
9
import util .Positions ._
10
- import StdNames ._
11
10
import tasty .TreePickler .Hole
12
- import MegaPhase .MiniPhase
13
11
import SymUtils ._
14
12
import NameKinds ._
15
13
import dotty .tools .dotc .ast .tpd .Tree
16
- import dotty .tools .dotc .core .DenotTransformers .InfoTransformer
17
14
import typer .Implicits .SearchFailureType
18
15
19
16
import scala .collection .mutable
@@ -60,33 +57,9 @@ import dotty.tools.dotc.core.quoted._
60
57
*
61
58
*
62
59
* 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.
88
61
*/
89
- class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
62
+ class ReifyQuotes extends MacroTransformWithImplicits {
90
63
import ast .tpd ._
91
64
92
65
/** Classloader used for loading macros */
@@ -255,7 +228,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
255
228
! sym.is(Param ) || levelOK(sym.owner)
256
229
}
257
230
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 an inline method */
259
232
def spliceOutsideQuotes (pos : Position )(implicit ctx : Context ): Unit =
260
233
ctx.error(i " splice outside quotes " , pos)
261
234
@@ -267,7 +240,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
267
240
def tryHeal (tp : Type , pos : Position )(implicit ctx : Context ): Option [String ] = tp match {
268
241
case tp : TypeRef =>
269
242
if (level == 0 ) {
270
- assert(ctx.owner.ownersIterator.exists(_.is(Macro )))
243
+ assert(ctx.owner.ownersIterator.exists(_.is(Transparent )))
271
244
None
272
245
} else {
273
246
val reqType = defn.QuotedTypeType .appliedTo(tp)
@@ -298,7 +271,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
298
271
else i " ${sym.name}.this "
299
272
if (! isThis && sym.maybeOwner.isType && ! sym.is(Param ))
300
273
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)
302
275
importedTags(sym.typeRef) = capturers(sym)(ref(sym))
303
276
else if (sym.exists && ! sym.isStaticOwner && ! levelOK(sym))
304
277
for (errMsg <- tryHeal(tp, pos))
@@ -510,18 +483,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
510
483
val captured = mutable.LinkedHashMap .empty[Symbol , Tree ]
511
484
val captured2 = capturer(captured)
512
485
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))
525
487
526
488
val tree2 = transform(tree)
527
489
capturers --= outer.enteredSyms
@@ -582,16 +544,12 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
582
544
val last = enteredSyms
583
545
stats.foreach(markDef)
584
546
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 =>
587
548
val tree2 =
588
549
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)
593
551
if (ctx.reporter.hasErrors) EmptyTree
594
- else transform(cpy.Inlined (tree)(call2 , bindings, spliced ))
552
+ else transform(cpy.Inlined (tree)(call , bindings, evaluatedSplice ))
595
553
}
596
554
else super .transform(tree)
597
555
@@ -607,22 +565,16 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
607
565
ctx.error(" Transparent macro method must be a static method." , tree.pos)
608
566
markDef(tree)
609
567
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))
615
570
case _ =>
616
571
ctx.error(
617
572
""" Malformed transparent macro.
618
573
|
619
574
|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.
626
578
""" .stripMargin, tree.rhs.pos)
627
579
EmptyTree
628
580
}
@@ -651,7 +603,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
651
603
}
652
604
653
605
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)) ||
655
607
sym == defn.TastyTopLevelSplice_tastyContext // intrinsic value at stage 0
656
608
657
609
private def liftList (list : List [Tree ], tpe : Type )(implicit ctx : Context ): Tree = {
@@ -664,38 +616,14 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
664
616
* consists of a (possibly multiple & nested) block or a sole expression.
665
617
*/
666
618
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
674
624
}
675
625
}
676
626
}
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 )
699
627
}
700
628
701
629
object ReifyQuotes {
0 commit comments