From 8ed24870082d667cb788d5f63186c3aba524c33d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 Nov 2020 11:09:08 +0100 Subject: [PATCH 1/3] Encode quote unpickle quotes directly on QuoteContext --- .../dotty/tools/dotc/core/Definitions.scala | 3 +-- .../tools/dotc/transform/ReifyQuotes.scala | 21 +++++++++++++++++-- .../scala/internal/quoted/PickledQuote.scala | 6 ------ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 70d7c6106ea0..f88c88eabdfb 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -795,6 +795,7 @@ class Definitions { @tu lazy val QuotedExprModule: Symbol = QuotedExprClass.companionModule @tu lazy val QuoteContextClass: ClassSymbol = requiredClass("scala.quoted.QuoteContext") + @tu lazy val QuoteContextInternalClass: ClassSymbol = requiredClass("scala.internal.quoted.QuoteContextInternal") @tu lazy val LiftableModule: Symbol = requiredModule("scala.quoted.Liftable") @tu lazy val LiftableModule_BooleanLiftable: Symbol = LiftableModule.requiredMethod("BooleanLiftable") @@ -837,8 +838,6 @@ class Definitions { @tu lazy val TastyReflectionClass: ClassSymbol = requiredClass("scala.tasty.Reflection") @tu lazy val PickledQuote_make: Symbol = requiredMethod("scala.internal.quoted.PickledQuote.make") - @tu lazy val PickledQuote_unpickleExpr: Symbol = requiredMethod("scala.internal.quoted.PickledQuote.unpickleExpr") - @tu lazy val PickledQuote_unpickleType: Symbol = requiredMethod("scala.internal.quoted.PickledQuote.unpickleType") @tu lazy val EqlClass: ClassSymbol = requiredClass("scala.Eql") def Eql_eqlAny(using Context): TermSymbol = EqlClass.companionModule.requiredMethod(nme.eqlAny) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 58769748b420..6db9cd75cf2f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -190,13 +190,30 @@ class ReifyQuotes extends MacroTransform { } } + /** Encode quote using QuoteContextInternal.{unpickleExpr, unpickleType} + * + * Generate the code + * ```scala + * qctx => qctx.asInstanceOf[QuoteContextInternal].( + * + * ).asInstanceOf[scala.quoted.[]] + * ``` + * this closure is always applied directly to the actual context and the BetaReduce phase removes it. + */ def pickleAsTasty() = { - val unpickleMeth = if isType then defn.PickledQuote_unpickleType else defn.PickledQuote_unpickleExpr val pickledQuoteStrings = liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType) // TODO: generate an instance of PickledSplices directly instead of passing through a List val splicesList = liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), defn.AnyType)) val pickledQuote = ref(defn.PickledQuote_make).appliedTo(pickledQuoteStrings, splicesList) - ref(unpickleMeth).appliedToType(originalTp).appliedTo(pickledQuote) + val quoteClass = if isType then defn.QuotedTypeClass else defn.QuotedExprClass + val quotedType = quoteClass.typeRef.appliedTo(originalTp) + val lambdaTpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, quotedType) + def callUnpickle(ts: List[Tree]) = { + val qctx = ts.head.asInstance(defn.QuoteContextInternalClass.typeRef) + val unpickleMethName = if isType then "unpickleType" else "unpickleExpr" + qctx.select(unpickleMethName.toTermName).appliedTo(pickledQuote).asInstance(quotedType) + } + Lambda(lambdaTpe, callUnpickle).withSpan(body.span) } /** Encode quote using Reflection.TypeRepr.typeConstructorOf diff --git a/library/src/scala/internal/quoted/PickledQuote.scala b/library/src/scala/internal/quoted/PickledQuote.scala index 6c44109c41e7..53b45a7e62be 100644 --- a/library/src/scala/internal/quoted/PickledQuote.scala +++ b/library/src/scala/internal/quoted/PickledQuote.scala @@ -16,12 +16,6 @@ trait PickledQuote: object PickledQuote: - def unpickleExpr[T](pickledQuote: PickledQuote): QuoteContext ?=> Expr[T] = - qctx.asInstanceOf[QuoteContextInternal].unpickleExpr(pickledQuote).asInstanceOf[Expr[T]] - - def unpickleType[T](pickledQuote: PickledQuote): QuoteContext ?=> Type[T] = - qctx.asInstanceOf[QuoteContextInternal].unpickleType(pickledQuote).asInstanceOf[Type[T]] - /** Create an instance of PickledExpr from encoded tasty and sequence of labmdas to fill holes * * @param pickled: Bytes of tasty encoded using TastyString.pickle From 87411b56b23451b8a5f751c97adda6a6ed34bbd3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 Nov 2020 11:16:44 +0100 Subject: [PATCH 2/3] Add types to unpickle methods --- .../src/dotty/tools/dotc/quoted/QuoteContextImpl.scala | 8 ++++---- compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala | 6 +++--- .../src/scala/internal/quoted/QuoteContextInternal.scala | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 9875814ebaf2..ad9f1ce05056 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -2628,13 +2628,13 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern end reflect - def unpickleExpr(pickledQuote: PickledQuote): scala.quoted.Expr[Any] = + def unpickleExpr[T](pickledQuote: PickledQuote): scala.quoted.Expr[T] = val tree = PickledQuotes.unpickleTerm(pickledQuote)(using reflect.rootContext) - new scala.internal.quoted.Expr(tree, hash) + new scala.internal.quoted.Expr(tree, hash).asInstanceOf[scala.quoted.Expr[T]] - def unpickleType(pickledQuote: PickledQuote): scala.quoted.Type[?] = + def unpickleType[T <: AnyKind](pickledQuote: PickledQuote): scala.quoted.Type[T] = val tree = PickledQuotes.unpickleTypeTree(pickledQuote)(using reflect.rootContext) - new scala.internal.quoted.Type(tree, hash) + new scala.internal.quoted.Type(tree, hash).asInstanceOf[scala.quoted.Type[T]] def exprMatch(scrutinee: scala.quoted.Expr[Any], pattern: scala.quoted.Expr[Any]): Option[Tuple] = treeMatch(scrutinee.unseal(using this), pattern.unseal(using this)) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 6db9cd75cf2f..f3c9eb072031 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -194,9 +194,9 @@ class ReifyQuotes extends MacroTransform { * * Generate the code * ```scala - * qctx => qctx.asInstanceOf[QuoteContextInternal].( + * qctx => qctx.asInstanceOf[QuoteContextInternal].[]( * - * ).asInstanceOf[scala.quoted.[]] + * ) * ``` * this closure is always applied directly to the actual context and the BetaReduce phase removes it. */ @@ -211,7 +211,7 @@ class ReifyQuotes extends MacroTransform { def callUnpickle(ts: List[Tree]) = { val qctx = ts.head.asInstance(defn.QuoteContextInternalClass.typeRef) val unpickleMethName = if isType then "unpickleType" else "unpickleExpr" - qctx.select(unpickleMethName.toTermName).appliedTo(pickledQuote).asInstance(quotedType) + qctx.select(unpickleMethName.toTermName).appliedToType(originalTp).appliedTo(pickledQuote) } Lambda(lambdaTpe, callUnpickle).withSpan(body.span) } diff --git a/library/src/scala/internal/quoted/QuoteContextInternal.scala b/library/src/scala/internal/quoted/QuoteContextInternal.scala index 0efdbb9f5945..9d752fabb0bb 100644 --- a/library/src/scala/internal/quoted/QuoteContextInternal.scala +++ b/library/src/scala/internal/quoted/QuoteContextInternal.scala @@ -10,12 +10,12 @@ trait QuoteContextInternal { self: scala.quoted.QuoteContext => /** Unpickle `repr` which represents a pickled `Expr` tree, * replacing splice nodes with `holes` */ - def unpickleExpr(pickledQuote: PickledQuote): scala.quoted.Expr[Any] + def unpickleExpr[T](pickledQuote: PickledQuote): scala.quoted.Expr[T] /** Unpickle `repr` which represents a pickled `Type` tree, * replacing splice nodes with `holes` */ - def unpickleType(pickledQuote: PickledQuote): scala.quoted.Type[?] + def unpickleType[T <: AnyKind](pickledQuote: PickledQuote): scala.quoted.Type[T] /** Pattern matches the scrutinee against the pattern and returns a tuple * with the matched holes if successful. From d35a5d77a2ffc3ef1eea11cd92aaacfd671e6c29 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 Nov 2020 11:19:02 +0100 Subject: [PATCH 3/3] Use Lambda constuctor --- .../tools/dotc/transform/ReifyQuotes.scala | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index f3c9eb072031..5bc9dd0abbdd 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -155,10 +155,9 @@ class ReifyQuotes extends MacroTransform { */ def pickleAsLiteral(lit: Literal) = { val exprType = defn.QuotedExprClass.typeRef.appliedTo(body.tpe) - val tpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, exprType) - val meth = newSymbol(ctx.owner, UniqueName.fresh(nme.ANON_FUN), Synthetic | Method, tpe) - def mkConst(tss: List[List[Tree]]) = { - val reflect = tss.head.head.select("reflect".toTermName) + val lambdaTpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, exprType) + def mkConst(ts: List[Tree]) = { + val reflect = ts.head.select("reflect".toTermName) val typeName = body.tpe.typeSymbol.name val literalValue = if lit.const.tag == Constants.NullTag || lit.const.tag == Constants.UnitTag then Nil @@ -167,7 +166,7 @@ class ReifyQuotes extends MacroTransform { val literal = reflect.select("Literal".toTermName).select(nme.apply).appliedTo(constant) reflect.select("TreeMethods".toTermName).select("asExpr".toTermName).appliedTo(literal).asInstance(exprType) } - Closure(meth, mkConst).withSpan(body.span) + Lambda(lambdaTpe, mkConst).withSpan(body.span) } def pickleAsValue(lit: Literal) = { @@ -229,14 +228,13 @@ class ReifyQuotes extends MacroTransform { def taggedType() = val typeType = defn.QuotedTypeClass.typeRef.appliedTo(body.tpe) val classTree = TypeApply(ref(defn.Predef_classOf.termRef), body :: Nil) - val tpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, typeType) - val meth = newSymbol(ctx.owner, UniqueName.fresh(nme.ANON_FUN), Synthetic | Method, tpe) - def mkConst(tss: List[List[Tree]]) = { - val reflect = tss.head.head.select("reflect".toTermName) + val lambdaTpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, typeType) + def callTypeConstructorOf(ts: List[Tree]) = { + val reflect = ts.head.select("reflect".toTermName) val typeRepr = reflect.select("TypeRepr".toTermName).select("typeConstructorOf".toTermName).appliedTo(classTree) reflect.select("TypeReprMethods".toTermName).select("asType".toTermName).appliedTo(typeRepr).asInstance(typeType) } - Closure(meth, mkConst).withSpan(body.span) + Lambda(lambdaTpe, callTypeConstructorOf).withSpan(body.span) if (isType) { if (splices.isEmpty && body.symbol.isPrimitiveValueClass) taggedType()