From 5adfd3a2966c382efa2c1ff93ba92e0ba1507ed1 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 23 Nov 2020 14:57:15 +0100 Subject: [PATCH] Remove reflect refinement form nested quotes This refinement is unsound as the nested `reflect` is not the same as the outer one. In theory we could make it work by using the refinement ``` type Nested = Quotes { type Tree >: self.reflect.Tree ... } ``` This refinement is unfortunately too large for the compiler to handle. Removing the refinement forces us to transform trees into `Expr` before using them in a splice. This is in general a better practice anyway. --- library/src/scala/quoted/Quotes.scala | 18 ++---------------- tests/neg-macros/i8045.scala | 5 +++++ tests/neg-macros/i8045b.scala | 8 ++++++++ tests/pos-macros/i8045.scala | 2 +- tests/pos-macros/i8045b.scala | 2 +- .../tasty-macro-positions/quoted_1.scala | 8 ++++---- tests/run-staging/multi-staging.check | 2 +- tests/run-staging/quote-nested-2.check | 2 +- tests/run-staging/quote-nested-5.check | 2 +- 9 files changed, 24 insertions(+), 25 deletions(-) create mode 100644 tests/neg-macros/i8045.scala create mode 100644 tests/neg-macros/i8045b.scala diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index a72d4ffedca5..cb06c663d289 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3697,21 +3697,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => } - /** Type of a Quotes provided by a splice within a quote that took this context. - * It is only required if working with the reflection API. - * - * Usually it is infered by the quotes an splices typing. But sometimes it is necessary - * to explicitly state that a context is nested as in the following example: - * - * ```scala - * def run(using Quotes)(tree: qctx.reflect.Tree): Unit = - * def nested()(using qctx.Nested): Expr[Int] = '{ ${ makeExpr(tree) } + 1 } - * '{ ${ nested() } + 2 } - * def makeExpr(using Quotes)(tree: qctx.reflect.Tree): Expr[Int] = ??? - * ``` - */ - type Nested = Quotes { - val reflect: self.reflect.type - } + /** Type of a `Quotes` provided by a splice within a quote that took this context. */ + type Nested = Quotes } diff --git a/tests/neg-macros/i8045.scala b/tests/neg-macros/i8045.scala new file mode 100644 index 000000000000..66f16d57849d --- /dev/null +++ b/tests/neg-macros/i8045.scala @@ -0,0 +1,5 @@ +import scala.quoted._ +object Test + def run(using Quotes)(tree: quotes.reflect.Tree): Unit = + '{ ${ makeExpr(tree) } + 1 } // error + def makeExpr(using Quotes)(tree: quotes.reflect.Tree): Expr[Int] = ??? diff --git a/tests/neg-macros/i8045b.scala b/tests/neg-macros/i8045b.scala new file mode 100644 index 000000000000..dd03479788a2 --- /dev/null +++ b/tests/neg-macros/i8045b.scala @@ -0,0 +1,8 @@ +import scala.quoted._ +object Test + def run(using q: Quotes)(tree: q.reflect.Tree): Unit = + def nested()(using q.Nested): Expr[Int] = + '{ ${ makeExpr(tree) } + 1 } // error + '{ ${ nested() } + 2 } + + def makeExpr(using q: Quotes)(tree: q.reflect.Tree): Expr[Int] = ??? diff --git a/tests/pos-macros/i8045.scala b/tests/pos-macros/i8045.scala index e501d8668b09..3cc2db538fba 100644 --- a/tests/pos-macros/i8045.scala +++ b/tests/pos-macros/i8045.scala @@ -1,5 +1,5 @@ import scala.quoted._ object Test def run(using Quotes)(tree: quotes.reflect.Tree): Unit = + def makeExpr(tree: quotes.reflect.Tree): Expr[Int] = ??? '{ ${ makeExpr(tree) } + 1 } - def makeExpr(using Quotes)(tree: quotes.reflect.Tree): Expr[Int] = ??? diff --git a/tests/pos-macros/i8045b.scala b/tests/pos-macros/i8045b.scala index d9fd435bf331..71a0086de286 100644 --- a/tests/pos-macros/i8045b.scala +++ b/tests/pos-macros/i8045b.scala @@ -1,8 +1,8 @@ import scala.quoted._ object Test def run(using q: Quotes)(tree: q.reflect.Tree): Unit = + def makeExpr(tree: q.reflect.Tree): Expr[Int] = ??? def nested()(using q.Nested): Expr[Int] = '{ ${ makeExpr(tree) } + 1 } '{ ${ nested() } + 2 } - def makeExpr(using q: Quotes)(tree: q.reflect.Tree): Expr[Int] = ??? diff --git a/tests/run-macros/tasty-macro-positions/quoted_1.scala b/tests/run-macros/tasty-macro-positions/quoted_1.scala index ea9c0e7ea836..9e20acbbf1c9 100644 --- a/tests/run-macros/tasty-macro-positions/quoted_1.scala +++ b/tests/run-macros/tasty-macro-positions/quoted_1.scala @@ -10,20 +10,20 @@ object Macros { def impl(x: Expr[Any])(using Quotes) : Expr[Unit] = { import quotes.reflect._ - val pos = Term.of(x).underlyingArgument.pos + val pos = posStr(Term.of(x).underlyingArgument.pos) val code = Term.of(x).underlyingArgument.show '{ - println(${posStr(pos)}) + println($pos) println(${Expr(code)}) } } def impl2[T](using x: Type[T])(using Quotes) : Expr[Unit] = { import quotes.reflect._ - val pos = TypeTree.of[T].pos + val pos = posStr(TypeTree.of[T].pos) val code = TypeTree.of[T].show '{ - println(${posStr(pos)}) + println($pos) println(${Expr(code)}) } } diff --git a/tests/run-staging/multi-staging.check b/tests/run-staging/multi-staging.check index fcdab8891c45..027f6b4b6189 100644 --- a/tests/run-staging/multi-staging.check +++ b/tests/run-staging/multi-staging.check @@ -1,5 +1,5 @@ stage1 code: ((q1: scala.quoted.Quotes) ?=> { val x1: scala.Int = 2 - scala.quoted.runtime.Expr.quote[scala.Int](1.+(scala.quoted.runtime.Expr.nestedSplice[scala.Int](q1)(((evidence$5: q1.Nested) ?=> scala.quoted.Expr.apply[scala.Int](x1)(scala.quoted.Liftable.IntLiftable[scala.Int])(evidence$5))))).apply(using q1) + scala.quoted.runtime.Expr.quote[scala.Int](1.+(scala.quoted.runtime.Expr.nestedSplice[scala.Int](q1)(((evidence$5: scala.quoted.Quotes) ?=> scala.quoted.Expr.apply[scala.Int](x1)(scala.quoted.Liftable.IntLiftable[scala.Int])(evidence$5))))).apply(using q1) }) 3 diff --git a/tests/run-staging/quote-nested-2.check b/tests/run-staging/quote-nested-2.check index ee2c5eccf702..b0af638da1a8 100644 --- a/tests/run-staging/quote-nested-2.check +++ b/tests/run-staging/quote-nested-2.check @@ -1,4 +1,4 @@ ((q: scala.quoted.Quotes) ?=> { val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q) - ((evidence$2: q.Nested) ?=> a).asInstanceOf[scala.ContextFunction1[scala.quoted.Quotes, scala.quoted.Expr[scala.Int]]].apply(using q) + ((evidence$2: scala.quoted.Quotes) ?=> a).asInstanceOf[scala.ContextFunction1[scala.quoted.Quotes, scala.quoted.Expr[scala.Int]]].apply(using q) }) diff --git a/tests/run-staging/quote-nested-5.check b/tests/run-staging/quote-nested-5.check index 72d31bfb23cc..f29acb3b347a 100644 --- a/tests/run-staging/quote-nested-5.check +++ b/tests/run-staging/quote-nested-5.check @@ -1,4 +1,4 @@ ((q: scala.quoted.Quotes) ?=> { val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q) - ((q2: scala.quoted.Quotes) ?=> ((evidence$3: q2.Nested) ?=> a).asInstanceOf[scala.ContextFunction1[scala.quoted.Quotes, scala.quoted.Expr[scala.Int]]].apply(using q2)).apply(using q) + ((q2: scala.quoted.Quotes) ?=> ((evidence$3: scala.quoted.Quotes) ?=> a).asInstanceOf[scala.ContextFunction1[scala.quoted.Quotes, scala.quoted.Expr[scala.Int]]].apply(using q2)).apply(using q) })