Skip to content

Commit 1154889

Browse files
Merge pull request #10262 from dotty-staging/remove-pickled-quotes-from-library
Remove PickledQuote and TastyString from library
2 parents 4411811 + 8edf7d9 commit 1154889

File tree

8 files changed

+98
-82
lines changed

8 files changed

+98
-82
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -796,8 +796,10 @@ class Definitions {
796796

797797
@tu lazy val QuoteContextClass: ClassSymbol = requiredClass("scala.quoted.QuoteContext")
798798
@tu lazy val QuoteContextInternalClass: ClassSymbol = requiredClass("scala.internal.quoted.QuoteContextInternal")
799-
@tu lazy val QuoteContextInternalClass_ExprMatch: Symbol = QuoteContextInternalClass.requiredMethod("ExprMatch")
800-
@tu lazy val QuoteContextInternalClass_TypeMatch: Symbol = QuoteContextInternalClass.requiredMethod("TypeMatch")
799+
@tu lazy val QuoteContextInternal_unpickleExpr: Symbol = QuoteContextInternalClass.requiredMethod("unpickleExpr")
800+
@tu lazy val QuoteContextInternal_unpickleType: Symbol = QuoteContextInternalClass.requiredMethod("unpickleType")
801+
@tu lazy val QuoteContextInternal_ExprMatch: Symbol = QuoteContextInternalClass.requiredMethod("ExprMatch")
802+
@tu lazy val QuoteContextInternal_TypeMatch: Symbol = QuoteContextInternalClass.requiredMethod("TypeMatch")
801803

802804
@tu lazy val LiftableModule: Symbol = requiredModule("scala.quoted.Liftable")
803805
@tu lazy val LiftableModule_BooleanLiftable: Symbol = LiftableModule.requiredMethod("BooleanLiftable")
@@ -831,8 +833,6 @@ class Definitions {
831833

832834
@tu lazy val TastyReflectionClass: ClassSymbol = requiredClass("scala.tasty.Reflection")
833835

834-
@tu lazy val PickledQuote_make: Symbol = requiredMethod("scala.internal.quoted.PickledQuote.make")
835-
836836
@tu lazy val EqlClass: ClassSymbol = requiredClass("scala.Eql")
837837
def Eql_eqlAny(using Context): TermSymbol = EqlClass.companionModule.requiredMethod(nme.eqlAny)
838838

compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import dotty.tools.dotc.report
1919

2020
import scala.reflect.ClassTag
2121

22-
import scala.internal.quoted.PickledQuote
2322
import scala.quoted.QuoteContext
2423
import scala.collection.mutable
2524

@@ -34,7 +33,7 @@ object PickledQuotes {
3433
else {
3534
assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x`
3635
val pickled = pickle(tree)
37-
scala.internal.quoted.TastyString.pickle(pickled)
36+
TastyString.pickle(pickled)
3837
}
3938

4039
/** Transform the expression into its fully spliced Tree */
@@ -52,25 +51,23 @@ object PickledQuotes {
5251
}
5352

5453
/** Unpickle the tree contained in the TastyExpr */
55-
def unpickleTerm(pickledQuote: PickledQuote)(using Context): Tree = {
56-
val unpickled = withMode(Mode.ReadPositions)(
57-
unpickle(pickledQuote, isType = false))
54+
def unpickleTerm(pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.QuoteContext) => scala.quoted.Expr[?])(using Context): Tree = {
55+
val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = false))
5856
val Inlined(call, Nil, expnasion) = unpickled
5957
val inlineCtx = inlineContext(call)
60-
val expansion1 = spliceTypes(expnasion, pickledQuote)(using inlineCtx)
61-
val expansion2 = spliceTerms(expansion1, pickledQuote)(using inlineCtx)
58+
val expansion1 = spliceTypes(expnasion, typeHole, termHole)(using inlineCtx)
59+
val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx)
6260
cpy.Inlined(unpickled)(call, Nil, expansion2)
6361
}
6462

6563
/** Unpickle the tree contained in the TastyType */
66-
def unpickleTypeTree(pickledQuote: PickledQuote)(using Context): Tree = {
67-
val unpickled = withMode(Mode.ReadPositions)(
68-
unpickle(pickledQuote, isType = true))
69-
spliceTypes(unpickled, pickledQuote)
64+
def unpickleTypeTree(pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.QuoteContext) => scala.quoted.Expr[?])(using Context): Tree = {
65+
val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = true))
66+
spliceTypes(unpickled, typeHole, termHole)
7067
}
7168

7269
/** Replace all term holes with the spliced terms */
73-
private def spliceTerms(tree: Tree, pickledQuote: PickledQuote)(using Context): Tree = {
70+
private def spliceTerms(tree: Tree, typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.QuoteContext) => scala.quoted.Expr[?])(using Context): Tree = {
7471
val evaluateHoles = new TreeMap {
7572
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
7673
case Hole(isTerm, idx, args) =>
@@ -79,7 +76,7 @@ object PickledQuotes {
7976
else new scala.quoted.internal.Type(arg, QuoteContextImpl.scopeId)
8077
}
8178
if isTerm then
82-
val quotedExpr = pickledQuote.exprSplice(idx)(reifiedArgs)(dotty.tools.dotc.quoted.QuoteContextImpl())
79+
val quotedExpr = termHole(idx, reifiedArgs, dotty.tools.dotc.quoted.QuoteContextImpl())
8380
val filled = PickledQuotes.quotedExprToTree(quotedExpr)
8481

8582
// We need to make sure a hole is created with the source file of the surrounding context, even if
@@ -89,7 +86,7 @@ object PickledQuotes {
8986
else
9087
// Replaces type holes generated by PickleQuotes (non-spliced types).
9188
// These are types defined in a quote and used at the same level in a nested quote.
92-
val quotedType = pickledQuote.typeSplice(idx)(reifiedArgs)
89+
val quotedType = typeHole(idx, reifiedArgs)
9390
PickledQuotes.quotedTypeToTree(quotedType)
9491
case tree: Select =>
9592
// Retain selected members
@@ -124,15 +121,15 @@ object PickledQuotes {
124121
}
125122

126123
/** Replace all type holes generated with the spliced types */
127-
private def spliceTypes(tree: Tree, pickledQuote: PickledQuote)(using Context): Tree = {
124+
private def spliceTypes(tree: Tree, typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Int], scala.quoted.QuoteContext) => Any)(using Context): Tree = {
128125
tree match
129126
case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
130127
val typeSpliceMap = (stat :: rest).iterator.map {
131128
case tdef: TypeDef =>
132129
assert(tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot))
133130
val tree = tdef.rhs match
134131
case TypeBoundsTree(_, Hole(_, idx, args), _) =>
135-
val quotedType = pickledQuote.typeSplice(idx)(args)
132+
val quotedType = typeHole(idx, args)
136133
PickledQuotes.quotedTypeToTree(quotedType)
137134
case TypeBoundsTree(_, tpt, _) =>
138135
tpt
@@ -178,8 +175,11 @@ object PickledQuotes {
178175
}
179176

180177
/** Unpickle TASTY bytes into it's tree */
181-
private def unpickle(pickledQuote: PickledQuote, isType: Boolean)(using Context): Tree = {
182-
val bytes = pickledQuote.bytes()
178+
private def unpickle(pickled: String | List[String], isType: Boolean)(using Context): Tree = {
179+
val bytes = pickled match
180+
case pickled: String => TastyString.unpickle(pickled)
181+
case pickled: List[String] => TastyString.unpickle(pickled)
182+
183183
quotePickling.println(s"**** unpickling quote from TASTY\n${TastyPrinter.show(bytes)}")
184184

185185
val mode = if (isType) UnpickleMode.TypeTree else UnpickleMode.Term

compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import dotty.tools.dotc.core.Decorators._
1616
import scala.quoted.QuoteContext
1717
import dotty.tools.dotc.quoted.printers.{Extractors, SourceCode, SyntaxHighlight}
1818

19-
import scala.internal.quoted.PickledQuote
2019
import scala.tasty.reflect._
2120

2221
object QuoteContextImpl {
@@ -2622,12 +2621,12 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern
26222621

26232622
end reflect
26242623

2625-
def unpickleExpr[T](pickledQuote: PickledQuote): scala.quoted.Expr[T] =
2626-
val tree = PickledQuotes.unpickleTerm(pickledQuote)(using reflect.rootContext)
2624+
def unpickleExpr[T](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.QuoteContext) => scala.quoted.Expr[?]): scala.quoted.Expr[T] =
2625+
val tree = PickledQuotes.unpickleTerm(pickled, typeHole, termHole)(using reflect.rootContext)
26272626
new scala.quoted.internal.Expr(tree, hash).asInstanceOf[scala.quoted.Expr[T]]
26282627

2629-
def unpickleType[T <: AnyKind](pickledQuote: PickledQuote): scala.quoted.Type[T] =
2630-
val tree = PickledQuotes.unpickleTypeTree(pickledQuote)(using reflect.rootContext)
2628+
def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.QuoteContext) => scala.quoted.Expr[?]): scala.quoted.Type[T] =
2629+
val tree = PickledQuotes.unpickleTypeTree(pickled, typeHole, termHole)(using reflect.rootContext)
26312630
new scala.quoted.internal.Type(tree, hash).asInstanceOf[scala.quoted.Type[T]]
26322631

26332632
object ExprMatch extends ExprMatchModule:

library/src/scala/internal/quoted/TastyString.scala renamed to compiler/src/dotty/tools/dotc/quoted/TastyString.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package scala.internal.quoted
1+
package dotty.tools.dotc.quoted
22

33
import java.io._
44
import java.util.Base64
@@ -22,4 +22,9 @@ object TastyString {
2222
strings.foreach(string.append)
2323
Base64.getDecoder().decode(string.result().getBytes(UTF_8))
2424
}
25+
26+
/** Decode the Strings into TASTY bytes */
27+
def unpickle(string: String): Array[Byte] =
28+
Base64.getDecoder().decode(string.getBytes(UTF_8))
29+
2530
}

compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import dotty.tools.dotc.typer.Inliner
2828
import scala.annotation.constructorOnly
2929

3030

31-
/** Translates quoted terms and types to `unpickle` method calls.
31+
/** Translates quoted terms and types to `unpickleExpr` or `unpickleType` method calls.
3232
*
3333
* Transforms top level quote
3434
* ```
@@ -42,23 +42,27 @@ import scala.annotation.constructorOnly
4242
* ```
4343
* to
4444
* ```
45-
* unpickle(
46-
* [[ // PICKLED TASTY
45+
* unpickleExpr(
46+
* pickled = [[ // PICKLED TASTY
4747
* ...
4848
* val x1 = ???
4949
* val x2 = ???
5050
* ...
51-
* Hole(0 | x1, x2)
51+
* Hole(<i> | x1, x2)
5252
* ...
5353
* ]],
54-
* List(
55-
* (args: Seq[Any]) => {
54+
* typeHole = (idx: Int, args: List[Any]) => idx match {
55+
* case 0 => ...
56+
* },
57+
* termHole = (idx: Int, args: List[Any], qctx: QuoteContext) => idx match {
58+
* case 0 => ...
59+
* ...
60+
* case <i> =>
5661
* val x1$1 = args(0).asInstanceOf[Expr[T]]
5762
* val x2$1 = args(1).asInstanceOf[Expr[T]] // can be asInstanceOf[Type[T]]
58-
* ...
63+
* ...
5964
* { ... '{ ... ${x1$1} ... ${x2$1} ...} ... }
60-
* }
61-
* )
65+
* },
6266
* )
6367
* ```
6468
* and then performs the same transformation on `'{ ... ${x1$1} ... ${x2$1} ...}`.
@@ -194,23 +198,66 @@ class PickleQuotes extends MacroTransform {
194198
* Generate the code
195199
* ```scala
196200
* qctx => qctx.asInstanceOf[QuoteContextInternal].<unpickleExpr|unpickleType>[<type>](
197-
* <pickledQuote>
201+
* <pickledQuote>,
202+
* <typeHole>,
203+
* <termHole>,
198204
* )
199205
* ```
200206
* this closure is always applied directly to the actual context and the BetaReduce phase removes it.
201207
*/
202208
def pickleAsTasty() = {
203-
val pickledQuoteStrings = liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType)
204-
// TODO: generate an instance of PickledSplices directly instead of passing through a List
205-
val splicesList = liftList(splices, defn.FunctionType(1).appliedTo(defn.SeqType.appliedTo(defn.AnyType), defn.AnyType))
206-
val pickledQuote = ref(defn.PickledQuote_make).appliedTo(pickledQuoteStrings, splicesList)
209+
val pickleQuote = PickledQuotes.pickleQuote(body)
210+
val pickledQuoteStrings = pickleQuote match
211+
case x :: Nil => Literal(Constant(x))
212+
case xs => liftList(xs.map(x => Literal(Constant(x))), defn.StringType)
213+
214+
// TODO split holes earlier into types and terms. This all holes in each category can have consecutive indices
215+
val (typeSplices, termSplices) = splices.zipWithIndex.partition { case (splice, _) =>
216+
splice.tpe match
217+
case defn.FunctionOf(_, res, _, _) => res.typeSymbol == defn.QuotedTypeClass
218+
}
219+
220+
// This and all closures in typeSplices are removed by the BetaReduce phase
221+
val typeHoles =
222+
if typeSplices.isEmpty then Literal(Constant(null)) // keep pickled quote without splices as small as possible
223+
else
224+
Lambda(
225+
MethodType(
226+
List(defn.IntType, defn.SeqType.appliedTo(defn.AnyType)),
227+
defn.QuotedTypeClass.typeRef.appliedTo(WildcardType)),
228+
args => {
229+
val cases = typeSplices.map { case (splice, idx) =>
230+
CaseDef(Literal(Constant(idx)), EmptyTree, splice.select(nme.apply).appliedTo(args(1)))
231+
}
232+
Match(args(0).annotated(New(ref(defn.UncheckedAnnot.typeRef))), cases)
233+
}
234+
)
235+
236+
// This and all closures in termSplices are removed by the BetaReduce phase
237+
val termHoles =
238+
if termSplices.isEmpty then Literal(Constant(null)) // keep pickled quote without splices as small as possible
239+
else
240+
Lambda(
241+
MethodType(
242+
List(defn.IntType, defn.SeqType.appliedTo(defn.AnyType), defn.QuoteContextClass.typeRef),
243+
defn.QuotedExprClass.typeRef.appliedTo(defn.AnyType)),
244+
args => {
245+
val cases = termSplices.map { case (splice, idx) =>
246+
val defn.FunctionOf(_, defn.FunctionOf(qctxType :: _, _, _, _), _, _) = splice.tpe
247+
val rhs = splice.select(nme.apply).appliedTo(args(1)).select(nme.apply).appliedTo(args(2).asInstance(qctxType))
248+
CaseDef(Literal(Constant(idx)), EmptyTree, rhs)
249+
}
250+
Match(args(0).annotated(New(ref(defn.UncheckedAnnot.typeRef))), cases)
251+
}
252+
)
253+
207254
val quoteClass = if isType then defn.QuotedTypeClass else defn.QuotedExprClass
208255
val quotedType = quoteClass.typeRef.appliedTo(originalTp)
209256
val lambdaTpe = MethodType(defn.QuoteContextClass.typeRef :: Nil, quotedType)
210257
def callUnpickle(ts: List[Tree]) = {
211258
val qctx = ts.head.asInstance(defn.QuoteContextInternalClass.typeRef)
212-
val unpickleMethName = if isType then "unpickleType" else "unpickleExpr"
213-
qctx.select(unpickleMethName.toTermName).appliedToType(originalTp).appliedTo(pickledQuote)
259+
val unpickleMeth = if isType then defn.QuoteContextInternal_unpickleType else defn.QuoteContextInternal_unpickleExpr
260+
qctx.select(unpickleMeth).appliedToType(originalTp).appliedTo(pickledQuoteStrings, typeHoles, termHoles)
214261
}
215262
Lambda(lambdaTpe, callUnpickle).withSpan(body.span)
216263
}

compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ trait QuotesAndSplices {
463463
if (tree.quoted.isTerm) ref(defn.InternalQuoted_exprQuote.termRef).appliedToType(defn.AnyType).appliedTo(shape).select(nme.apply).appliedTo(qctx)
464464
else ref(defn.QuotedTypeModule_apply.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx)
465465

466-
val matchModule = if tree.quoted.isTerm then defn.QuoteContextInternalClass_ExprMatch else defn.QuoteContextInternalClass_TypeMatch
466+
val matchModule = if tree.quoted.isTerm then defn.QuoteContextInternal_ExprMatch else defn.QuoteContextInternal_TypeMatch
467467
val unapplyFun = qctx.asInstance(defn.QuoteContextInternalClass.typeRef).select(matchModule).select(nme.unapply)
468468

469469
UnApply(

library/src/scala/internal/quoted/PickledQuote.scala

Lines changed: 0 additions & 34 deletions
This file was deleted.

library/src/scala/internal/quoted/QuoteContextInternal.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@ package scala.internal.quoted
22

33
import scala.quoted.{QuoteContext, Expr, Type}
44
import scala.tasty.reflect._
5-
import scala.internal.quoted.PickledQuote
65

76
/** Part of the QuoteContext interface that needs to be implemented by the compiler but is not visible to users */
87
trait QuoteContextInternal { self: QuoteContext =>
98

109
/** Unpickle `repr` which represents a pickled `Expr` tree,
1110
* replacing splice nodes with `holes`
1211
*/
13-
def unpickleExpr[T](pickledQuote: PickledQuote): scala.quoted.Expr[T]
12+
def unpickleExpr[T](pickled: String | List[String], typeHole: (Int, Seq[Any]) => Type[?], termHole: (Int, Seq[Any], QuoteContext) => Expr[?]): scala.quoted.Expr[T]
1413

1514
/** Unpickle `repr` which represents a pickled `Type` tree,
1615
* replacing splice nodes with `holes`
1716
*/
18-
def unpickleType[T <: AnyKind](pickledQuote: PickledQuote): scala.quoted.Type[T]
17+
def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: (Int, Seq[Any]) => Type[?], termHole: (Int, Seq[Any], QuoteContext) => Expr[?]): scala.quoted.Type[T]
1918

2019
val ExprMatch: ExprMatchModule
2120

0 commit comments

Comments
 (0)