@@ -2,10 +2,15 @@ package dotty.tools.dotc
2
2
package transform
3
3
4
4
import core ._
5
- import Decorators ._ , Flags ._ , Types ._ , Contexts ._ , Symbols ._ , Constants ._
5
+ import Decorators ._
6
+ import Flags ._
7
+ import Types ._
8
+ import Contexts ._
9
+ import Symbols ._
10
+ import Constants ._
6
11
import Flags ._
7
12
import ast .Trees ._
8
- import ast .{TreeTypeMap , untpd }
13
+ import ast .{TreeTypeMap , tpd , untpd }
9
14
import util .Positions ._
10
15
import tasty .TreePickler .Hole
11
16
import SymUtils ._
@@ -16,6 +21,7 @@ import typer.Implicits.SearchFailureType
16
21
import scala .collection .mutable
17
22
import dotty .tools .dotc .core .StdNames ._
18
23
import dotty .tools .dotc .core .quoted ._
24
+ import dotty .tools .dotc .util .SourcePosition
19
25
20
26
21
27
/** Translates quoted terms and types to `unpickle` method calls.
@@ -78,7 +84,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
78
84
if (ctx.compilationUnit.containsQuotesOrSplices) super .run
79
85
80
86
protected def newTransformer (implicit ctx : Context ): Transformer =
81
- new Reifier (inQuote = false , null , 0 , new LevelInfo , new mutable.ListBuffer [Tree ])
87
+ new Reifier (inQuote = false , null , 0 , new LevelInfo , new mutable.ListBuffer [Tree ], null )
82
88
83
89
private class LevelInfo {
84
90
/** A map from locally defined symbols to the staging levels of their definitions */
@@ -108,16 +114,22 @@ class ReifyQuotes extends MacroTransformWithImplicits {
108
114
* and `l == -1` is code inside a top level splice (in an inline method).
109
115
* @param levels a stacked map from symbols to the levels in which they were defined
110
116
* @param embedded a list of embedded quotes (if `inSplice = true`) or splices (if `inQuote = true`
117
+ * @param inlinedAtPos if non null, the reifier is inside an inlined call with position `inlinedAtPos`
111
118
*/
112
119
private class Reifier (inQuote : Boolean , val outer : Reifier , val level : Int , levels : LevelInfo ,
113
- val embedded : mutable.ListBuffer [Tree ]) extends ImplicitsTransformer {
120
+ val embedded : mutable.ListBuffer [Tree ], inlinedAtPos : SourcePosition ) extends ImplicitsTransformer {
114
121
import levels ._
115
122
assert(level >= - 1 )
116
123
117
124
/** A nested reifier for a quote (if `isQuote = true`) or a splice (if not) */
118
125
def nested (isQuote : Boolean ): Reifier = {
119
126
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)
127
+ new Reifier (isQuote, this , if (isQuote) level + 1 else level - 1 , levels, nestedEmbedded, inlinedAtPos)
128
+ }
129
+
130
+ def inlined (inlinedAt : SourcePosition ): Reifier = {
131
+ assert(level == 0 )
132
+ new Reifier (true , this , 0 , levels, embedded, inlinedAt)
121
133
}
122
134
123
135
/** We are in a `~(...)` context that is not shadowed by a nested `'(...)` */
@@ -126,6 +138,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
126
138
/** We are not in a `~(...)` or a `'(...)` */
127
139
def isRoot : Boolean = outer == null
128
140
141
+ def isInlined : Boolean = inlinedAtPos != null
142
+
129
143
/** A map from type ref T to expressions of type `quoted.Type[T]`".
130
144
* These will be turned into splices using `addTags` and represent type variables
131
145
* that can be possibly healed.
@@ -418,14 +432,34 @@ class ReifyQuotes extends MacroTransformWithImplicits {
418
432
val body1 = nested(isQuote = false ).transform(splice.qualifier)
419
433
body1.select(splice.name)
420
434
}
421
- else if (! inQuote && level == 0 && ! ctx.owner.is(Inline )) {
422
- spliceOutsideQuotes(splice.pos)
423
- splice
424
- }
425
- else {
435
+ else if (level == 1 ) {
426
436
val (body1, quotes) = nested(isQuote = false ).split(splice.qualifier)
427
437
makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
428
438
}
439
+ else if (level == - 1 ) {
440
+ // TODO add test
441
+ ctx.error(" Cannot splice inside a top-level splice" , splice.pos)
442
+ splice
443
+ }
444
+ else if (isInlined) { // level 0 in an inline call
445
+ val evaluatedSplice = Splicer .splice(splice.qualifier, inlinedAtPos, macroClassLoader).withPos(splice.pos)
446
+ if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
447
+ } else if (ctx.owner.is(Inline )) { // level 0 in an inline definition
448
+ if (! Splicer .canBeSpliced(splice.qualifier))
449
+ ctx.error( // TODO adapt error message
450
+ """ Malformed inline macro.
451
+ |
452
+ |Expected the ~ to be at the top of the RHS:
453
+ | inline def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y))
454
+ |
455
+ |The contents of the splice must call a static method. Arguments must be quoted or inlined.
456
+ """ .stripMargin, splice.pos)
457
+ splice
458
+ }
459
+ else { // level 0
460
+ spliceOutsideQuotes(splice.pos)
461
+ splice
462
+ }
429
463
}
430
464
431
465
/** Transforms the contents of a nested splice
@@ -550,37 +584,10 @@ class ReifyQuotes extends MacroTransformWithImplicits {
550
584
val last = enteredSyms
551
585
stats.foreach(markDef)
552
586
mapOverTree(last)
553
- case Inlined (call, bindings, InlineSplice (spliced)) =>
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
587
+ case tree : Inlined if ! isInlined && level == 0 =>
588
+ inlined(tree.pos).transform(tree)
565
589
case _ : Import =>
566
590
tree
567
- case tree : DefDef if tree.symbol.is(Macro ) && level == 0 =>
568
- markDef(tree)
569
- tree.rhs match {
570
- case InlineSplice (_) =>
571
- mapOverTree(enteredSyms) // Ignore output, only check PCP
572
- cpy.DefDef (tree)(rhs = defaultValue(tree.rhs.tpe))
573
- case _ =>
574
- ctx.error(
575
- """ Malformed inline macro.
576
- |
577
- |Expected the ~ to be at the top of the RHS:
578
- | inline def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y))
579
- |
580
- |The contents of the splice must call a static method. Arguments must be quoted or inlined.
581
- """ .stripMargin, tree.rhs.pos)
582
- EmptyTree
583
- }
584
591
case _ =>
585
592
markDef(tree)
586
593
checkLevel(mapOverTree(enteredSyms))
@@ -614,18 +621,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
614
621
acc.select(" ::" .toTermName).appliedToType(tpe).appliedTo(x)
615
622
}
616
623
}
617
-
618
- /** InlineSplice is used to detect cases where the expansion
619
- * consists of a (possibly multiple & nested) block or a sole expression.
620
- */
621
- object InlineSplice {
622
- def unapply (tree : Tree )(implicit ctx : Context ): Option [Tree ] = tree match {
623
- case Select (qual, _) if tree.symbol.isSplice && Splicer .canBeSpliced(qual) => Some (qual)
624
- case Block (List (stat), Literal (Constant (()))) => unapply(stat)
625
- case Block (Nil , expr) => unapply(expr)
626
- case _ => None
627
- }
628
- }
629
624
}
630
625
}
631
626
0 commit comments