From c8fcd1e2d08ce42d14ab28f18e6e0a3515e415d6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Sat, 7 Jul 2018 18:34:02 +0200 Subject: [PATCH 1/2] Fix inline parameters lifted for 0 to 1 In theory the inline parameters are available in level 1, but we can access it "unlifted" as a value in level 0. To only pass the parameter once it is passed as a value and lifted using the standard lifter for the values. Unsing lifter is just an implementation detail and should not be observable by the user. The issue was that the lifter used could be replaced or unimported which yield unexpected error messages. --- .../dotty/tools/dotc/core/Definitions.scala | 13 ++++++++ .../tools/dotc/transform/ReifyQuotes.scala | 33 ++++++++++--------- tests/pos/quote-lift-inline-params-b.scala | 7 ++++ .../pos/quote-lift-inline-params/App_2.scala | 4 +++ .../quote-lift-inline-params/Macro_1.scala | 7 ++++ 5 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 tests/pos/quote-lift-inline-params-b.scala create mode 100644 tests/pos/quote-lift-inline-params/App_2.scala create mode 100644 tests/pos/quote-lift-inline-params/Macro_1.scala diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 3e4d470babdc..94fef2f76c5c 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -654,6 +654,19 @@ class Definitions { lazy val QuotedType_applyR = QuotedTypeModule.requiredMethodRef(nme.apply) def QuotedType_apply(implicit ctx: Context) = QuotedType_applyR.symbol + lazy val QuotedLiftableModule = ctx.requiredModule("scala.quoted.Liftable") + def QuotedLiftableModuleClass(implicit ctx: Context) = QuotedLiftableModule.asClass + + def QuotedLiftable_BooleanIsLiftable = QuotedLiftableModule.requiredMethodRef("BooleanIsLiftable") + def QuotedLiftable_ByteLiftable = QuotedLiftableModule.requiredMethodRef("ByteLiftable") + def QuotedLiftable_CharIsLiftable = QuotedLiftableModule.requiredMethodRef("CharIsLiftable") + def QuotedLiftable_ShortIsLiftable = QuotedLiftableModule.requiredMethodRef("ShortIsLiftable") + def QuotedLiftable_IntIsLiftable = QuotedLiftableModule.requiredMethodRef("IntIsLiftable") + def QuotedLiftable_LongIsLiftable = QuotedLiftableModule.requiredMethodRef("LongIsLiftable") + def QuotedLiftable_FloatIsLiftable = QuotedLiftableModule.requiredMethodRef("FloatIsLiftable") + def QuotedLiftable_DoubleIsLiftable = QuotedLiftableModule.requiredMethodRef("DoubleIsLiftable") + def QuotedLiftable_StringIsLiftable = QuotedLiftableModule.requiredMethodRef("StringIsLiftable") + lazy val QuotedLiftableType = ctx.requiredClassRef("scala.quoted.Liftable") def QuotedLiftableClass(implicit ctx: Context) = QuotedLiftableType.symbol.asClass diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 9cc37d3716bd..bfb64c78a541 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -387,7 +387,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { if (isStage0Value(body.symbol)) { // 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)) + liftInlineParamValue(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` @@ -577,7 +577,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { splice(t.select(if (tree.isTerm) nme.UNARY_~ else tpnme.UNARY_~)) if (!isStage0Value(tree.symbol)) captureAndSplice(capturer(tree)) else if (level == 0) capturer(tree) - else captureAndSplice(liftValue(capturer(tree))) + else captureAndSplice(liftInlineParamValue(capturer(tree))) case Block(stats, _) => val last = enteredSyms stats.foreach(markDef) @@ -632,19 +632,22 @@ 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) - } + /** Takes a reference to an inline parameter `tree` and lifts it to an Expr */ + private def liftInlineParamValue(tree: Tree)(implicit ctx: Context): Tree = { + val tpSym = tree.tpe.widenDealias.classSymbol + + val lifter = + if (tpSym eq defn.BooleanClass) defn.QuotedLiftable_BooleanIsLiftable + else if (tpSym eq defn.ByteClass) defn.QuotedLiftable_ByteLiftable + else if (tpSym eq defn.CharClass) defn.QuotedLiftable_CharIsLiftable + else if (tpSym eq defn.ShortClass) defn.QuotedLiftable_ShortIsLiftable + else if (tpSym eq defn.IntClass) defn.QuotedLiftable_IntIsLiftable + else if (tpSym eq defn.LongClass) defn.QuotedLiftable_LongIsLiftable + else if (tpSym eq defn.FloatClass) defn.QuotedLiftable_FloatIsLiftable + else if (tpSym eq defn.DoubleClass) defn.QuotedLiftable_DoubleIsLiftable + else defn.QuotedLiftable_StringIsLiftable + + ref(lifter).select("toExpr".toTermName).appliedTo(tree) } private def isStage0Value(sym: Symbol)(implicit ctx: Context): Boolean = diff --git a/tests/pos/quote-lift-inline-params-b.scala b/tests/pos/quote-lift-inline-params-b.scala new file mode 100644 index 000000000000..a5e4d797c083 --- /dev/null +++ b/tests/pos/quote-lift-inline-params-b.scala @@ -0,0 +1,7 @@ +import scala.quoted.Expr +object Macro { + inline def foo(inline n: Int): Int = ~{ + import quoted.Liftable.{IntIsLiftable => _} + '(n) + } +} \ No newline at end of file diff --git a/tests/pos/quote-lift-inline-params/App_2.scala b/tests/pos/quote-lift-inline-params/App_2.scala new file mode 100644 index 000000000000..3cf1427a3955 --- /dev/null +++ b/tests/pos/quote-lift-inline-params/App_2.scala @@ -0,0 +1,4 @@ + +object App { + Macro.foo(3) +} \ No newline at end of file diff --git a/tests/pos/quote-lift-inline-params/Macro_1.scala b/tests/pos/quote-lift-inline-params/Macro_1.scala new file mode 100644 index 000000000000..a5e4d797c083 --- /dev/null +++ b/tests/pos/quote-lift-inline-params/Macro_1.scala @@ -0,0 +1,7 @@ +import scala.quoted.Expr +object Macro { + inline def foo(inline n: Int): Int = ~{ + import quoted.Liftable.{IntIsLiftable => _} + '(n) + } +} \ No newline at end of file From b3d38345078d9ecc22bb3c5d7d40e1c2b3244dc8 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 Jul 2018 11:34:15 +0200 Subject: [PATCH 2/2] Rename ByteLiftable to ByteIsLiftable --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 +- compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala | 2 +- library/src/scala/quoted/Liftable.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 94fef2f76c5c..03edce966792 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -658,7 +658,7 @@ class Definitions { def QuotedLiftableModuleClass(implicit ctx: Context) = QuotedLiftableModule.asClass def QuotedLiftable_BooleanIsLiftable = QuotedLiftableModule.requiredMethodRef("BooleanIsLiftable") - def QuotedLiftable_ByteLiftable = QuotedLiftableModule.requiredMethodRef("ByteLiftable") + def QuotedLiftable_ByteIsLiftable = QuotedLiftableModule.requiredMethodRef("ByteIsLiftable") def QuotedLiftable_CharIsLiftable = QuotedLiftableModule.requiredMethodRef("CharIsLiftable") def QuotedLiftable_ShortIsLiftable = QuotedLiftableModule.requiredMethodRef("ShortIsLiftable") def QuotedLiftable_IntIsLiftable = QuotedLiftableModule.requiredMethodRef("IntIsLiftable") diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index bfb64c78a541..63a0c59641ca 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -638,7 +638,7 @@ class ReifyQuotes extends MacroTransformWithImplicits with InfoTransformer { val lifter = if (tpSym eq defn.BooleanClass) defn.QuotedLiftable_BooleanIsLiftable - else if (tpSym eq defn.ByteClass) defn.QuotedLiftable_ByteLiftable + else if (tpSym eq defn.ByteClass) defn.QuotedLiftable_ByteIsLiftable else if (tpSym eq defn.CharClass) defn.QuotedLiftable_CharIsLiftable else if (tpSym eq defn.ShortClass) defn.QuotedLiftable_ShortIsLiftable else if (tpSym eq defn.IntClass) defn.QuotedLiftable_IntIsLiftable diff --git a/library/src/scala/quoted/Liftable.scala b/library/src/scala/quoted/Liftable.scala index ae494e17d33b..4bb43917a166 100644 --- a/library/src/scala/quoted/Liftable.scala +++ b/library/src/scala/quoted/Liftable.scala @@ -16,7 +16,7 @@ abstract class Liftable[T] { */ object Liftable { implicit def BooleanIsLiftable: Liftable[Boolean] = (x: Boolean) => liftedExpr(x) - implicit def ByteLiftable: Liftable[Byte] = (x: Byte) => liftedExpr(x) + implicit def ByteIsLiftable: Liftable[Byte] = (x: Byte) => liftedExpr(x) implicit def CharIsLiftable: Liftable[Char] = (x: Char) => liftedExpr(x) implicit def ShortIsLiftable: Liftable[Short] = (x: Short) => liftedExpr(x) implicit def IntIsLiftable: Liftable[Int] = (x: Int) => liftedExpr(x)