@@ -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.
@@ -230,10 +244,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
230
244
! sym.is(Param ) || levelOK(sym.owner)
231
245
}
232
246
233
- /** Issue a "splice outside quote" error unless we are in the body of an inline method */
234
- def spliceOutsideQuotes (pos : Position )(implicit ctx : Context ): Unit =
235
- ctx.error(i " splice outside quotes " , pos)
236
-
237
247
/** Try to heal phase-inconsistent reference to type `T` using a local type definition.
238
248
* @return None if successful
239
249
* @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
@@ -292,7 +302,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
292
302
outer.checkType(pos).foldOver(acc, tp)
293
303
}
294
304
else {
295
- if (tp.isTerm) spliceOutsideQuotes( pos)
305
+ if (tp.isTerm) ctx.error( i " splice outside quotes " , pos)
296
306
tp
297
307
}
298
308
case tp : NamedType =>
@@ -418,14 +428,34 @@ class ReifyQuotes extends MacroTransformWithImplicits {
418
428
val body1 = nested(isQuote = false ).transform(splice.qualifier)
419
429
body1.select(splice.name)
420
430
}
421
- else if (! inQuote && level == 0 && ! ctx.owner.is(Inline )) {
422
- spliceOutsideQuotes(splice.pos)
423
- splice
424
- }
425
- else {
431
+ else if (level == 1 ) {
426
432
val (body1, quotes) = nested(isQuote = false ).split(splice.qualifier)
427
433
makeHole(body1, quotes, splice.tpe).withPos(splice.pos)
428
434
}
435
+ else if (level == - 1 ) {
436
+ // TODO add test
437
+ ctx.error(" Cannot splice inside a top-level splice" , splice.pos)
438
+ splice
439
+ }
440
+ else if (isInlined) { // level 0 in an inline call
441
+ val evaluatedSplice = Splicer .splice(splice.qualifier, inlinedAtPos, macroClassLoader).withPos(splice.pos)
442
+ if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
443
+ } else if (ctx.owner.is(Inline )) { // level 0 in an inline definition
444
+ if (! Splicer .canBeSpliced(splice.qualifier))
445
+ ctx.error( // TODO adapt error message
446
+ """ Malformed inline macro.
447
+ |
448
+ |Expected the ~ to be at the top of the RHS:
449
+ | inline def foo(x: X, ..., y: Y): Int = ~impl(x, ... '(y))
450
+ |
451
+ |The contents of the splice must call a static method. Arguments must be quoted or inlined.
452
+ """ .stripMargin, splice.pos)
453
+ splice
454
+ }
455
+ else { // level 0
456
+ ctx.error(i " splice outside quotes or inline method " , splice.pos)
457
+ splice
458
+ }
429
459
}
430
460
431
461
/** Transforms the contents of a nested splice
@@ -550,37 +580,10 @@ class ReifyQuotes extends MacroTransformWithImplicits {
550
580
val last = enteredSyms
551
581
stats.foreach(markDef)
552
582
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
583
+ case tree : Inlined if ! isInlined && level == 0 =>
584
+ inlined(tree.pos).transform(tree)
565
585
case _ : Import =>
566
586
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
587
case _ =>
585
588
markDef(tree)
586
589
checkLevel(mapOverTree(enteredSyms))
@@ -614,18 +617,6 @@ class ReifyQuotes extends MacroTransformWithImplicits {
614
617
acc.select(" ::" .toTermName).appliedToType(tpe).appliedTo(x)
615
618
}
616
619
}
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
620
}
630
621
}
631
622
0 commit comments