diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index f10c7ae75ee7..ef5d0d1f7022 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -660,6 +660,9 @@ class Definitions { lazy val QuotedType_applyR = QuotedTypeModule.requiredMethodRef(nme.apply) def QuotedType_apply(implicit ctx: Context) = QuotedType_applyR.symbol + lazy val QuotedLiftableType = ctx.requiredClassRef("scala.quoted.Liftable") + def QuotedLiftableClass(implicit ctx: Context) = QuotedLiftableType.symbol.asClass + def Unpickler_unpickleExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr") def Unpickler_liftedExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr") def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType") diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index ae9d63c3c222..3751c1a4d4a7 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -73,7 +73,7 @@ import dotty.tools.dotc.core.quoted._ * ... * val y1$1 = args(1).asInstanceOf[Expr[Y]] * ... - * { ... T1$1.unary_~ ... x ... '(y1$1.unary_~) ... } + * { ... x1$1 .... '{ ... T1$1.unary_~ ... x1$1.toExpr.unary_~ ... y1$1.unary_~ ... } ... } * } * ``` * Note: the parameters of `foo` are kept for simple overloading resolution but they are not used in the body of `foo`. @@ -375,9 +375,15 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { } else body match { case body: RefTree if isCaptured(body, level + 1) => - // Optimization: avoid the full conversion when capturing `x` - // in '{ x } to '{ x$1.unary_~ } and go directly to `x$1` - capturers(body.symbol)(body) + if (body.symbol.is(Inline)) { + // Optimization: avoid the full conversion when capturing inlined `x` + // in '{ x } to '{ x$1.toExpr.unary_~ } and go directly to `x$1.toExpr` + liftValue(capturers(body.symbol)(body)) + } else { + // Optimization: avoid the full conversion when capturing `x` + // in '{ x } to '{ x$1.unary_~ } and go directly to `x$1` + capturers(body.symbol)(body) + } case _=> val (body1, splices) = nested(isQuote = true).split(body) pickledQuote(body1, splices, isType).withPos(quote.pos) @@ -546,8 +552,11 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { splice(tree) case tree: RefTree if isCaptured(tree, level) => val capturer = capturers(tree.symbol) - if (tree.symbol.is(Inline)) capturer(tree) - else splice(capturer(tree).select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~)) + def captureAndSplice(t: Tree) = + splice(t.select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~)) + if (tree.symbol.is(Inline) && level == 0) capturer(tree) + else if (tree.symbol.is(Inline)) captureAndSplice(liftValue(capturer(tree))) + else captureAndSplice(capturer(tree)) case Block(stats, _) => val last = enteredSyms stats.foreach(markDef) @@ -601,6 +610,21 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { } } + private def liftValue(tree: Tree)(implicit ctx: Context): Tree = { + val reqType = defn.QuotedLiftableType.appliedTo(tree.tpe.widen) + val liftable = ctx.typer.inferImplicitArg(reqType, tree.pos) + liftable.tpe match { + case fail: SearchFailureType => + ctx.error(i""" + | + | The access would be accepted with the right Liftable, but + | ${ctx.typer.missingArgMsg(liftable, reqType, "")}""") + EmptyTree + case _ => + liftable.select("toExpr".toTermName).appliedTo(tree) + } + } + private def liftList(list: List[Tree], tpe: Type)(implicit ctx: Context): Tree = { list.foldRight[Tree](ref(defn.NilModule)) { (x, acc) => acc.select("::".toTermName).appliedToType(tpe).appliedTo(x) diff --git a/tests/run/i4455.check b/tests/run/i4455.check new file mode 100644 index 000000000000..b22040ee9c71 --- /dev/null +++ b/tests/run/i4455.check @@ -0,0 +1,4 @@ +1 +3 +3 +5 diff --git a/tests/run/i4455/Macro_1.scala b/tests/run/i4455/Macro_1.scala new file mode 100644 index 000000000000..9ac3070ed986 --- /dev/null +++ b/tests/run/i4455/Macro_1.scala @@ -0,0 +1,8 @@ +import scala.quoted._ +object Macros { + inline def foo(inline i: Int): Int = ~bar('(i)) + + inline def foo2(inline i: Int): Int = ~bar('(i + 1)) + + def bar(x: Expr[Int]): Expr[Int] = x +} diff --git a/tests/run/i4455/Test_2.scala b/tests/run/i4455/Test_2.scala new file mode 100644 index 000000000000..18fc75a361c6 --- /dev/null +++ b/tests/run/i4455/Test_2.scala @@ -0,0 +1,9 @@ +import Macros._ +object Test { + def main(args: Array[String]): Unit = { + println(foo(1)) + println(foo(3)) + println(foo2(2)) + println(foo2(4)) + } +}