From 6b80d7782b450c8fb0506d8566ddfd14ecaee391 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 17 Sep 2020 10:42:15 +0200 Subject: [PATCH 1/3] Fix #9812: Do not widen types during quote reification --- compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala | 2 +- tests/pos-macros/i9812.scala | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 tests/pos-macros/i9812.scala diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 5ce5832dfd06..83b47be33ae3 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -168,7 +168,7 @@ class ReifyQuotes extends MacroTransform { else val tpe = if originalTp =:= defn.NilModule.termRef then originalTp // Workaround #4987 - else originalTp.widen.dealias + else originalTp.dealias ref(defn.Unpickler_unpickleExpr).appliedToType(tpe) val pickledQuoteStrings = liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType) val splicesList = liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), defn.AnyType)) diff --git a/tests/pos-macros/i9812.scala b/tests/pos-macros/i9812.scala new file mode 100644 index 000000000000..25218802ff31 --- /dev/null +++ b/tests/pos-macros/i9812.scala @@ -0,0 +1,8 @@ +// compile with -Ycheck:reifyQuotes -Ystop-after:reifyQuotes +import quoted._ + +sealed abstract class SomeEnum +object SomeEnum: + final val Foo = new SomeEnum {} + +def quoteFoo: QuoteContext ?=> Expr[SomeEnum.Foo.type] = '{SomeEnum.Foo} From 69c6f84c991d5baa220f2f546e6a2cfad713830c Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 17 Sep 2020 10:52:07 +0200 Subject: [PATCH 2/3] Simplify pickleAsTasty logic --- .../src/dotty/tools/dotc/transform/ReifyQuotes.scala | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 83b47be33ae3..7ba7130d62cf 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -163,16 +163,10 @@ class ReifyQuotes extends MacroTransform { } def pickleAsTasty() = { - val meth = - if (isType) ref(defn.Unpickler_unpickleType).appliedToType(originalTp) - else - val tpe = - if originalTp =:= defn.NilModule.termRef then originalTp // Workaround #4987 - else originalTp.dealias - ref(defn.Unpickler_unpickleExpr).appliedToType(tpe) + val meth = if isType then defn.Unpickler_unpickleType else defn.Unpickler_unpickleExpr val pickledQuoteStrings = liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType) val splicesList = liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), defn.AnyType)) - meth.appliedTo(pickledQuoteStrings, splicesList) + ref(meth).appliedToType(originalTp).appliedTo(pickledQuoteStrings, splicesList) } def taggedType(sym: Symbol) = ref(defn.InternalQuotedTypeModule).select(sym.name.toTermName) From c335a36198a796c4e52904ec797665cd64523fa3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 17 Sep 2020 13:29:29 +0200 Subject: [PATCH 3/3] Add test --- tests/run-macros/i9812b/Macro_1.scala | 51 +++++++++++++++++++++++++++ tests/run-macros/i9812b/Test_2.scala | 2 ++ 2 files changed, 53 insertions(+) create mode 100644 tests/run-macros/i9812b/Macro_1.scala create mode 100644 tests/run-macros/i9812b/Test_2.scala diff --git a/tests/run-macros/i9812b/Macro_1.scala b/tests/run-macros/i9812b/Macro_1.scala new file mode 100644 index 000000000000..808d82fadd4b --- /dev/null +++ b/tests/run-macros/i9812b/Macro_1.scala @@ -0,0 +1,51 @@ +import quoted._ +import SomeEnum._ + +trait Liftable[T] { + /** Lift a value into an expression containing the construction of that value */ + def toExpr(x: T): QuoteContext ?=> Expr[T] +} + +object Lift: + def apply[T: Liftable](t: T)(using qctx: QuoteContext, ev: Liftable[T]): Expr[T] = ev.toExpr(t) + +sealed abstract class SomeEnum +object SomeEnum: + final val Foo = new SomeEnum {} + final case class Bar[S <: SomeEnum](s: S) extends SomeEnum + object Bar: + def apply[S <: SomeEnum](s: S): SomeEnum = new Bar(s) + +given LiftFoo as Liftable[Foo.type]: + def toExpr(x: Foo.type): QuoteContext ?=> Expr[Foo.type] = '{Foo} + +given LiftBar[S <: SomeEnum: Type: Liftable] as Liftable[Bar[S]]: + def toExpr(x: Bar[S]): QuoteContext ?=> Expr[Bar[S]] = '{new Bar(${Lift(x.s)})} + +sealed abstract class Lst[+T] +final case class CONS[+T](head: T, tail: Lst[T]) extends Lst[T] +case object NIL extends Lst[Nothing] + +given IntLiftable[T <: Int] as Liftable[T]: + def toExpr(x: T): QuoteContext ?=> Expr[T] = qctx ?=> { + import qctx.tasty._ + Literal(Constant(x)).seal.asInstanceOf[Expr[T]] + } + +given LiftLst[T: Type: Liftable](using ev1: => Liftable[CONS[T]], ev2: => Liftable[NIL.type]) as Liftable[Lst[T]]: + def toExpr(xs: Lst[T]): QuoteContext ?=> Expr[Lst[T]] = xs match + case NIL => ev2.toExpr(NIL) + case cons @ CONS(_, _) => ev1.toExpr(cons) + +given LiftCONS[T: Type: Liftable](using Liftable[Lst[T]]) as Liftable[CONS[T]]: + def toExpr(x: CONS[T]): QuoteContext ?=> Expr[CONS[T]] = '{CONS(${Lift(x.head)}, ${Lift(x.tail)})} + +given LiftNIL as Liftable[NIL.type]: + def toExpr(x: NIL.type): QuoteContext ?=> Expr[NIL.type] = '{NIL} + +def mkLst[T](ts: T*) = ts.foldRight(NIL: Lst[T])(CONS(_,_)) + +def quote123: QuoteContext ?=> Expr[Lst[Int]] = Lift(mkLst(1,2,3)) + +inline def get123: Lst[Int] = ${ quote123 } + diff --git a/tests/run-macros/i9812b/Test_2.scala b/tests/run-macros/i9812b/Test_2.scala new file mode 100644 index 000000000000..5d62b72570d9 --- /dev/null +++ b/tests/run-macros/i9812b/Test_2.scala @@ -0,0 +1,2 @@ +@main def Test: Unit = println(get123) +