Skip to content

Commit 8efbbf4

Browse files
committed
Shift level of top-level splice
Now all levels are relative to the definition site. 0 is the level of all non-staged definitions, -1 is the level of the contents of a top level splice (in an inline method) and positive levels are (as before) staging levels.
1 parent 7ea2810 commit 8efbbf4

File tree

1 file changed

+20
-15
lines changed

1 file changed

+20
-15
lines changed

compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,16 @@ class ReifyQuotes extends MacroTransformWithImplicits {
103103
/** The main transformer class
104104
* @param inQuote we are within a `'(...)` context that is not shadowed by a nested `~(...)`
105105
* @param outer the next outer reifier, null is this is the topmost transformer
106-
* @param level the current level, where quotes add one and splices subtract one level
106+
* @param level the current level, where quotes add one and splices subtract one level.
107+
* The initial level is 0, a level `l` where `l > 0` implies code has been quotes `l` times
108+
* and `l == -1` is code inside a top level splice (in an transparent method).
107109
* @param levels a stacked map from symbols to the levels in which they were defined
108110
* @param embedded a list of embedded quotes (if `inSplice = true`) or splices (if `inQuote = true`
109111
*/
110112
private class Reifier(inQuote: Boolean, val outer: Reifier, val level: Int, levels: LevelInfo,
111113
val embedded: mutable.ListBuffer[Tree]) extends ImplicitsTransformer {
112114
import levels._
113-
assert(level >= 0)
115+
assert(level >= -1)
114116

115117
/** A nested reifier for a quote (if `isQuote = true`) or a splice (if not) */
116118
def nested(isQuote: Boolean): Reifier = {
@@ -205,7 +207,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
205207
}
206208

207209
/** Enter staging level of symbol defined by `tree`, if applicable. */
208-
def markDef(tree: Tree)(implicit ctx: Context) = tree match {
210+
def markDef(tree: Tree)(implicit ctx: Context): Unit = tree match {
209211
case tree: DefTree =>
210212
val sym = tree.symbol
211213
if ((sym.isClass || !sym.maybeOwner.isType) && !levelOf.contains(sym)) {
@@ -223,7 +225,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
223225
def levelOK(sym: Symbol)(implicit ctx: Context): Boolean = levelOf.get(sym) match {
224226
case Some(l) =>
225227
l == level ||
226-
l == 1 && level == 0 && isStage0Value(sym)
228+
l == 0 && level == -1 && isStageNegOneValue(sym)
227229
case None =>
228230
!sym.is(Param) || levelOK(sym.owner)
229231
}
@@ -239,7 +241,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
239241
*/
240242
def tryHeal(tp: Type, pos: Position)(implicit ctx: Context): Option[String] = tp match {
241243
case tp: TypeRef =>
242-
if (level == 0) {
244+
if (level == -1) {
243245
assert(ctx.owner.ownersIterator.exists(_.is(Transparent)))
244246
None
245247
} else {
@@ -357,7 +359,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
357359
}
358360
else body match {
359361
case body: RefTree if isCaptured(body.symbol, level + 1) =>
360-
if (isStage0Value(body.symbol)) {
362+
if (isStageNegOneValue(body.symbol)) {
361363
// Optimization: avoid the full conversion when capturing inlined `x`
362364
// in '{ x } to '{ x$1.toExpr.unary_~ } and go directly to `x$1.toExpr`
363365
liftInlineParamValue(capturers(body.symbol)(body))
@@ -368,7 +370,11 @@ class ReifyQuotes extends MacroTransformWithImplicits {
368370
}
369371
case _=>
370372
val (body1, splices) = nested(isQuote = true).split(body)
371-
pickledQuote(body1, splices, body.tpe, isType).withPos(quote.pos)
373+
if (level >= 0) pickledQuote(body1, splices, body.tpe, isType).withPos(quote.pos)
374+
else {
375+
// In top-level splice in an transparent def. Keep the tree as it is, it will be transformed at inline site.
376+
body
377+
}
372378
}
373379
}
374380

@@ -412,7 +418,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
412418
val body1 = nested(isQuote = false).transform(splice.qualifier)
413419
body1.select(splice.name)
414420
}
415-
else if (!inQuote && level == 0) {
421+
else if (!inQuote && level == 0 && !ctx.owner.is(Transparent)) {
416422
spliceOutsideQuotes(splice.pos)
417423
splice
418424
}
@@ -458,7 +464,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
458464
val tpw = tree.tpe.widen
459465
val argTpe =
460466
if (tree.isType) defn.QuotedTypeType.appliedTo(tpw)
461-
else if (isStage0Value(tree.symbol)) tpw
467+
else if (isStageNegOneValue(tree.symbol)) tpw
462468
else defn.QuotedExprType.appliedTo(tpw)
463469
val selectArg = arg.select(nme.apply).appliedTo(Literal(Constant(i))).asInstance(argTpe)
464470
val capturedArg = SyntheticValDef(UniqueName.fresh(tree.symbol.name.toTermName).toTermName, selectArg)
@@ -495,7 +501,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
495501
private def isCaptured(sym: Symbol, level: Int)(implicit ctx: Context): Boolean = {
496502
// Check phase consistency and presence of capturer
497503
( (level == 1 && levelOf.get(sym).contains(1)) ||
498-
(level == 0 && isStage0Value(sym))
504+
(level == 0 && isStageNegOneValue(sym))
499505
) && capturers.contains(sym)
500506
}
501507

@@ -537,7 +543,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
537543
val capturer = capturers(tree.symbol)
538544
def captureAndSplice(t: Tree) =
539545
splice(t.select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~))
540-
if (!isStage0Value(tree.symbol)) captureAndSplice(capturer(tree))
546+
if (!isStageNegOneValue(tree.symbol)) captureAndSplice(capturer(tree))
541547
else if (level == 0) capturer(tree)
542548
else captureAndSplice(liftInlineParamValue(capturer(tree)))
543549
case Block(stats, _) =>
@@ -559,13 +565,12 @@ class ReifyQuotes extends MacroTransformWithImplicits {
559565
case _: Import =>
560566
tree
561567
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>
568+
markDef(tree)
562569
tree.rhs match {
563570
case InlineSplice(_) =>
564571
if (!tree.symbol.isStatic)
565572
ctx.error("Transparent macro method must be a static method.", tree.pos)
566-
markDef(tree)
567-
val reifier = nested(isQuote = true)
568-
reifier.transform(tree) // Ignore output, only check PCP
573+
mapOverTree(enteredSyms) // Ignore output, only check PCP
569574
cpy.DefDef(tree)(rhs = defaultValue(tree.rhs.tpe))
570575
case _ =>
571576
ctx.error(
@@ -602,7 +607,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
602607
ref(lifter).select("toExpr".toTermName).appliedTo(tree)
603608
}
604609

605-
private def isStage0Value(sym: Symbol)(implicit ctx: Context): Boolean =
610+
private def isStageNegOneValue(sym: Symbol)(implicit ctx: Context): Boolean =
606611
(sym.is(Transparent) && sym.owner.is(Transparent) && !defn.isFunctionType(sym.info)) ||
607612
sym == defn.TastyTopLevelSplice_tastyContext // intrinsic value at stage 0
608613

0 commit comments

Comments
 (0)