Skip to content

Commit b5d0fdf

Browse files
committed
Avoid cuadratic behaviour when lifting references
1 parent a6e19d4 commit b5d0fdf

File tree

1 file changed

+23
-30
lines changed

1 file changed

+23
-30
lines changed

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

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,21 @@ class ReifyQuotes extends MacroTransformWithImplicits {
7070
private class LevelInfo {
7171
/** A map from locally defined symbols to the staging levels of their definitions */
7272
val levelOf = new mutable.HashMap[Symbol, Int]
73+
74+
/** Register a reference defined in a quote but used in another quote nested in a splice.
75+
* Returns a lifted version of the reference that needs to be used in its place.
76+
* '{
77+
* val x = ???
78+
* { ... '{ ... x ... } ... }.unary_~
79+
* }
80+
* Lifting the `x` in `{ ... '{ ... x ... } ... }.unary_~` will return a `x$1.unary_~` for which the `x$1`
81+
* be created by some outer reifier.
82+
*
83+
* This transformation is only applied to definitions at staging level 1.
84+
*
85+
* See `needsLifting`
86+
*/
87+
val lifters = new mutable.HashMap[Symbol, RefTree => Tree]
7388
}
7489

7590
/** The main transformer class
@@ -354,44 +369,21 @@ class ReifyQuotes extends MacroTransformWithImplicits {
354369
Closure(meth, tss => body(tss.head.head)(ctx.withOwner(meth)).changeOwner(ctx.owner, meth))
355370
}
356371

357-
/** Register a reference defined in a quote but used in another quote nested in a splice.
358-
* Returns a lifted version of the reference that needs to be used in its place.
359-
* '{
360-
* val x = ???
361-
* { ... '{ ... x ... } ... }.unary_~
362-
* }
363-
* Lifting the `x` in `{ ... '{ ... x ... } ... }.unary_~` will return a `x$1.unary_~` for which the `x$1`
364-
* be created by some outer reifier.
365-
*
366-
* This transformation is only applied to definitions at staging level 1.
367-
*
368-
* See `needsLifting`
369-
*/
370-
def lift(tree: RefTree)(implicit ctx: Context): Select =
371-
if (!(level == 0 && outer.enteredSyms.contains(tree.symbol))) outer.lift(tree)
372-
else lifter(tree).select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~)
373-
private[this] var lifter: RefTree => Tree = null
374-
375372
private def transformWithLifter(tree: Tree)(
376373
lifter: mutable.ListBuffer[Tree] => RefTree => Tree)(implicit ctx: Context): Tree = {
377374
val lifted = new mutable.ListBuffer[Tree]
378-
this.lifter = lifter(lifted)
375+
val lifter2 = lifter(lifted)
376+
outer.enteredSyms.foreach(s => lifters.put(s, lifter2))
379377
val tree2 = transform(tree)
380-
this.lifter = null
378+
lifters --= outer.enteredSyms
381379
seq(lifted.result(), tree2)
382380
}
383381

384382
/** Returns true if this tree will be lifted by `makeLambda` */
385383
private def needsLifting(tree: RefTree)(implicit ctx: Context): Boolean = {
386-
def isInLiftedTree(reifier: Reifier): Boolean =
387-
if (reifier.level == 0) true
388-
else if (reifier.level == 1 && reifier.enteredSyms.contains(tree.symbol)) false
389-
else isInLiftedTree(reifier.outer)
390-
level == 1 &&
391-
!tree.symbol.is(Inline) &&
392-
levelOf.get(tree.symbol).contains(1) &&
393-
!enteredSyms.contains(tree.symbol) &&
394-
isInLiftedTree(outer)
384+
// Check phase consistency and presence of lifter
385+
level == 1 && !tree.symbol.is(Inline) && levelOf.get(tree.symbol).contains(1) &&
386+
lifters.contains(tree.symbol)
395387
}
396388

397389
/** Transform `tree` and return the resulting tree and all `embedded` quotes
@@ -426,7 +418,8 @@ class ReifyQuotes extends MacroTransformWithImplicits {
426418
case tree: Select if tree.symbol.isSplice =>
427419
splice(tree)
428420
case tree: RefTree if needsLifting(tree) =>
429-
splice(outer.lift(tree))
421+
val lift = lifters(tree.symbol)
422+
splice(lift(tree).select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~))
430423
case Block(stats, _) =>
431424
val last = enteredSyms
432425
stats.foreach(markDef)

0 commit comments

Comments
 (0)