Skip to content

Commit 9c5383c

Browse files
committed
Fix #4455: Lift inlined values when quoted
This is part of the transformation that allows compiling the contents of the inline macro. The alternative would be to pass each inline parameter twice, once as a value and once as it's tree.
1 parent 48a2f4b commit 9c5383c

File tree

5 files changed

+53
-5
lines changed

5 files changed

+53
-5
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,9 @@ class Definitions {
660660
lazy val QuotedType_applyR = QuotedTypeModule.requiredMethodRef(nme.apply)
661661
def QuotedType_apply(implicit ctx: Context) = QuotedType_applyR.symbol
662662

663+
lazy val QuotedLiftableType = ctx.requiredClassRef("scala.quoted.Liftable")
664+
def QuotedLiftableClass(implicit ctx: Context) = QuotedLiftableType.symbol.asClass
665+
663666
def Unpickler_unpickleExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr")
664667
def Unpickler_liftedExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr")
665668
def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,15 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
375375
}
376376
else body match {
377377
case body: RefTree if isCaptured(body, level + 1) =>
378-
// Optimization: avoid the full conversion when capturing `x`
379-
// in '{ x } to '{ x$1.unary_~ } and go directly to `x$1`
380-
capturers(body.symbol)(body)
378+
if (body.symbol.is(Inline)) {
379+
// Optimization: avoid the full conversion when capturing inlined `x`
380+
// in '{ x } to '{ x$1.toExpr.unary_~ } and go directly to `x$1.toExpr`
381+
liftValue(capturers(body.symbol)(body))
382+
} else {
383+
// Optimization: avoid the full conversion when capturing `x`
384+
// in '{ x } to '{ x$1.unary_~ } and go directly to `x$1`
385+
capturers(body.symbol)(body)
386+
}
381387
case _=>
382388
val (body1, splices) = nested(isQuote = true).split(body)
383389
pickledQuote(body1, splices, isType).withPos(quote.pos)
@@ -546,8 +552,11 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
546552
splice(tree)
547553
case tree: RefTree if isCaptured(tree, level) =>
548554
val capturer = capturers(tree.symbol)
549-
if (tree.symbol.is(Inline)) capturer(tree)
550-
else splice(capturer(tree).select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~))
555+
def captureAndSplice(t: Tree) =
556+
splice(t.select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~))
557+
if (tree.symbol.is(Inline) && level == 0) capturer(tree)
558+
else if (tree.symbol.is(Inline)) captureAndSplice(liftValue(capturer(tree)))
559+
else captureAndSplice(capturer(tree))
551560
case Block(stats, _) =>
552561
val last = enteredSyms
553562
stats.foreach(markDef)
@@ -601,6 +610,21 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer {
601610
}
602611
}
603612

613+
private def liftValue(tree: Tree)(implicit ctx: Context): Tree = {
614+
val reqType = defn.QuotedLiftableType.appliedTo(tree.tpe.widen)
615+
val liftable = ctx.typer.inferImplicitArg(reqType, tree.pos)
616+
liftable.tpe match {
617+
case fail: SearchFailureType =>
618+
ctx.error(i"""
619+
|
620+
| The access would be accepted with the right Liftable, but
621+
| ${ctx.typer.missingArgMsg(liftable, reqType, "")}""")
622+
EmptyTree
623+
case _ =>
624+
liftable.select("toExpr".toTermName).appliedTo(tree)
625+
}
626+
}
627+
604628
private def liftList(list: List[Tree], tpe: Type)(implicit ctx: Context): Tree = {
605629
list.foldRight[Tree](ref(defn.NilModule)) { (x, acc) =>
606630
acc.select("::".toTermName).appliedToType(tpe).appliedTo(x)

tests/run/i4455.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
1
2+
3
3+
3
4+
5

tests/run/i4455/Macro_1.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted._
2+
object Macros {
3+
inline def foo(inline i: Int): Int = ~bar('(i))
4+
def bar(x: Expr[Int]): Expr[Int] = x
5+
6+
inline def foo2(inline i: Int): Int = ~bar('(i + 1))
7+
def bar2(x: Expr[Int]): Expr[Int] = x
8+
}

tests/run/i4455/Test_2.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Macros._
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
println(foo(1))
5+
println(foo(3))
6+
println(foo2(2))
7+
println(foo2(4))
8+
}
9+
}

0 commit comments

Comments
 (0)