Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 36707c7

Browse files
Merge pull request #6963 from dotty-staging/fix-#5376
Fix #5376, fix #5434: Unpickle quotes eagerly
2 parents 95ae77c + 8b8c66a commit 36707c7

File tree

22 files changed

+159
-92
lines changed

22 files changed

+159
-92
lines changed

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

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ import dotty.tools.dotc.tastyreflect.ReflectionImpl
1919
import scala.internal.quoted._
2020
import scala.reflect.ClassTag
2121

22+
import scala.runtime.quoted.Unpickler._
23+
2224
object PickledQuotes {
2325
import tpd._
2426

2527
/** Pickle the tree of the quote into strings */
26-
def pickleQuote(tree: Tree)(implicit ctx: Context): scala.runtime.quoted.Unpickler.Pickled = {
28+
def pickleQuote(tree: Tree)(implicit ctx: Context): PickledQuote = {
2729
if (ctx.reporter.hasErrors) Nil
2830
else {
2931
assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x`
@@ -33,33 +35,12 @@ object PickledQuotes {
3335
}
3436

3537
/** Transform the expression into its fully spliced Tree */
36-
def quotedExprToTree[T](expr: quoted.Expr[T])(implicit ctx: Context): Tree = expr match {
37-
case expr: TastyExpr[_] =>
38-
val unpickled = unpickleExpr(expr)
39-
/** Force unpickling of the tree, removes the spliced type `@quotedTypeTag type` definitions and dealiases references to `@quotedTypeTag type` */
40-
val forceAndCleanArtefacts = new TreeMap {
41-
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
42-
case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
43-
assert(rest.forall { case tdef: TypeDef => tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) })
44-
transform(expr1)
45-
case tree => super.transform(tree).withType(dealiasTypeTags(tree.tpe))
46-
}
47-
}
48-
forceAndCleanArtefacts.transform(unpickled)
49-
case expr: TastyTreeExpr[Tree] @unchecked => healOwner(expr.tree)
50-
}
38+
def quotedExprToTree[T](expr: quoted.Expr[T])(implicit ctx: Context): Tree =
39+
healOwner(expr.asInstanceOf[TastyTreeExpr[Tree]].tree)
5140

5241
/** Transform the expression into its fully spliced TypeTree */
53-
def quotedTypeToTree(expr: quoted.Type[_])(implicit ctx: Context): Tree = expr match {
54-
case expr: TastyType[_] =>
55-
unpickleType(expr) match {
56-
case Block(aliases, tpt) =>
57-
// `@quoteTypeTag type` aliasses are not required after unpickling
58-
tpt
59-
case tpt => tpt
60-
}
61-
case expr: TreeType[Tree] @unchecked => healOwner(expr.typeTree)
62-
}
42+
def quotedTypeToTree(expr: quoted.Type[_])(implicit ctx: Context): Tree =
43+
healOwner(expr.asInstanceOf[TreeType[Tree]].typeTree)
6344

6445
private def dealiasTypeTags(tp: Type)(implicit ctx: Context): Type = new TypeMap() {
6546
override def apply(tp: Type): Type = {
@@ -72,15 +53,31 @@ object PickledQuotes {
7253
}.apply(tp)
7354

7455
/** Unpickle the tree contained in the TastyExpr */
75-
private def unpickleExpr(expr: TastyExpr[_])(implicit ctx: Context): Tree = {
76-
val tastyBytes = TastyString.unpickle(expr.tasty)
77-
unpickle(tastyBytes, expr.args, isType = false)(ctx.addMode(Mode.ReadPositions))
56+
def unpickleExpr(tasty: PickledQuote, args: PickledExprArgs)(implicit ctx: Context): Tree = {
57+
val tastyBytes = TastyString.unpickle(tasty)
58+
val unpickled = unpickle(tastyBytes, args, isType = false)(ctx.addMode(Mode.ReadPositions))
59+
/** Force unpickling of the tree, removes the spliced type `@quotedTypeTag type` definitions and dealiases references to `@quotedTypeTag type` */
60+
val forceAndCleanArtefacts = new TreeMap {
61+
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
62+
case Block(stat :: rest, expr1) if stat.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
63+
assert(rest.forall { case tdef: TypeDef => tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) })
64+
transform(expr1)
65+
case tree => super.transform(tree).withType(dealiasTypeTags(tree.tpe))
66+
}
67+
}
68+
forceAndCleanArtefacts.transform(unpickled)
7869
}
7970

8071
/** Unpickle the tree contained in the TastyType */
81-
private def unpickleType(ttpe: TastyType[_])(implicit ctx: Context): Tree = {
82-
val tastyBytes = TastyString.unpickle(ttpe.tasty)
83-
unpickle(tastyBytes, ttpe.args, isType = true)(ctx.addMode(Mode.ReadPositions))
72+
def unpickleType(tasty: PickledQuote, args: PickledTypeArgs)(implicit ctx: Context): Tree = {
73+
val tastyBytes = TastyString.unpickle(tasty)
74+
val unpickled = unpickle(tastyBytes, args, isType = true)(ctx.addMode(Mode.ReadPositions))
75+
unpickled match {
76+
case Block(aliases, tpt) =>
77+
// `@quoteTypeTag type` aliasses are not required after unpickling
78+
tpt
79+
case tpt => tpt
80+
}
8481
}
8582

8683
// TASTY picklingtests/pos/quoteTest.scala

‎compiler/src/dotty/tools/dotc/core/tasty/TastyString.scala‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
package dotty.tools.dotc.core.tasty
22

3-
import scala.runtime.quoted.Unpickler.Pickled
4-
53
import java.io._
64
import java.util.Base64
75
import java.nio.charset.StandardCharsets.UTF_8
86

7+
import scala.runtime.quoted.Unpickler.PickledQuote
8+
99
/** Utils for String representation of TASTY */
1010
object TastyString {
1111

1212
// Max size of a string literal in the bytecode
1313
private final val maxStringSize = 65535
1414

15-
/** Encode TASTY bytes into an Seq of String */
16-
def pickle(bytes: Array[Byte]): Pickled = {
15+
/** Encode TASTY bytes into a List of String */
16+
def pickle(bytes: Array[Byte]): PickledQuote = {
1717
val str = new String(Base64.getEncoder().encode(bytes), UTF_8)
1818
str.sliding(maxStringSize, maxStringSize).toList
1919
}
2020

21-
/** Decode the TASTY String into TASTY bytes */
22-
def unpickle(strings: Pickled): Array[Byte] = {
21+
/** Decode the List of Strings into TASTY bytes */
22+
def unpickle(strings: PickledQuote): Array[Byte] = {
2323
val string = new StringBuilder
2424
strings.foreach(string.append)
2525
Base64.getDecoder().decode(string.result().getBytes(UTF_8))

‎compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1281,7 +1281,7 @@ class TreeUnpickler(reader: TastyReader,
12811281
PickledQuotes.quotedTypeToTree(quotedType)
12821282
} else {
12831283
val splice1 = splice.asInstanceOf[Seq[Any] => given scala.quoted.QuoteContext => quoted.Expr[_]]
1284-
val quotedExpr = splice1(reifiedArgs) given new scala.quoted.QuoteContext(tastyreflect.ReflectionImpl(ctx))
1284+
val quotedExpr = splice1(reifiedArgs) given dotty.tools.dotc.quoted.QuoteContext()
12851285
PickledQuotes.quotedExprToTree(quotedExpr)
12861286
}
12871287
// We need to make sure a hole is created with the source file of the surrounding context, even if

‎compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class QuoteCompiler extends Compiler {
6464
cls.enter(ctx.newDefaultConstructor(cls), EmptyScope)
6565
val meth = ctx.newSymbol(cls, nme.apply, Method, ExprType(defn.AnyType), coord = pos).entered
6666

67-
val quoted = PickledQuotes.quotedExprToTree(exprUnit.exprBuilder.apply(new QuoteContext(ReflectionImpl(ctx))))(ctx.withOwner(meth))
67+
val qctx = dotty.tools.dotc.quoted.QuoteContext()
68+
val quoted = PickledQuotes.quotedExprToTree(exprUnit.exprBuilder.apply(qctx))(ctx.withOwner(meth))
6869

6970
getLiteral(quoted) match {
7071
case Some(value) =>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.core.Contexts.Context
4+
import dotty.tools.dotc.tastyreflect.ReflectionImpl
5+
6+
object QuoteContext {
7+
8+
def apply() given Context: scala.quoted.QuoteContext =
9+
new scala.quoted.QuoteContext(ReflectionImpl(the[Context]))
10+
11+
}

‎compiler/src/dotty/tools/dotc/tastyreflect/ReflectionInternal.scala‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import dotty.tools.dotc.parsing.Parsers.Parser
1616
import dotty.tools.dotc.typer.Implicits.{AmbiguousImplicits, DivergingImplicit, NoMatchingImplicits, SearchFailure, SearchFailureType}
1717
import dotty.tools.dotc.util.{SourceFile, SourcePosition, Spans}
1818

19+
import scala.runtime.quoted.Unpickler
1920
import scala.tasty.reflect.CompilerInterface
2021

2122
class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extends CompilerInterface {
@@ -28,6 +29,16 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
2829
def rootPosition: util.SourcePosition =
2930
tastyreflect.MacroExpansion.position.getOrElse(SourcePosition(rootContext.source, Spans.NoSpan))
3031

32+
//
33+
// QUOTE UNPICKLING
34+
//
35+
36+
def unpickleExpr(repr: Unpickler.PickledQuote, args: Unpickler.PickledExprArgs): scala.quoted.Expr[_] =
37+
new scala.internal.quoted.TastyTreeExpr(PickledQuotes.unpickleExpr(repr, args))
38+
39+
def unpickleType(repr: Unpickler.PickledQuote, args: Unpickler.PickledTypeArgs): scala.quoted.Type[_] =
40+
new scala.internal.quoted.TreeType(PickledQuotes.unpickleType(repr, args))
41+
3142
//
3243
// CONTEXT
3344
//

‎compiler/src/dotty/tools/dotc/transform/Splicer.scala‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import dotty.tools.repl.AbstractFileClassLoader
2525

2626
import scala.reflect.ClassTag
2727

28+
import dotty.tools.dotc.quoted.QuoteContext
29+
2830
/** Utility class to splice quoted expressions */
2931
object Splicer {
3032
import tpd._
@@ -42,7 +44,7 @@ object Splicer {
4244
try {
4345
// Some parts of the macro are evaluated during the unpickling performed in quotedExprToTree
4446
val interpretedExpr = interpreter.interpret[scala.quoted.QuoteContext => scala.quoted.Expr[Any]](tree)
45-
interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(new scala.quoted.QuoteContext(ReflectionImpl(ctx)))))
47+
interpretedExpr.fold(tree)(macroClosure => PickledQuotes.quotedExprToTree(macroClosure(QuoteContext())))
4648
}
4749
catch {
4850
case ex: StopInterpretation =>
@@ -261,7 +263,7 @@ object Splicer {
261263
args.toSeq
262264

263265
private def interpretQuoteContext()(implicit env: Env): Object =
264-
new scala.quoted.QuoteContext(ReflectionImpl(ctx))
266+
QuoteContext()
265267

266268
private def interpretedStaticMethodCall(moduleClass: Symbol, fn: Symbol)(implicit env: Env): List[Object] => Object = {
267269
val (inst, clazz) =

‎library/src-bootstrapped/dotty/internal/StringContextMacro.scala‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ object StringContextMacro {
6666
}
6767
def splitParts(seq: Expr[Seq[String]]) = (seq, seq) match {
6868
case (ExprSeq(p1), ConstSeq(p2)) => Some((p1.toList, p2.toList))
69-
case _ => notStatic
69+
case (_, _) => notStatic
7070
}
7171
strCtxExpr match {
7272
case '{ StringContext($parts: _*) } => splitParts(parts)

‎library/src/scala/quoted/Expr.scala‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,7 @@ package quoted {
7979
package internal {
8080
package quoted {
8181

82-
import scala.quoted._
83-
84-
/** An Expr backed by a pickled TASTY tree */
85-
final class TastyExpr[+T](val tasty: scala.runtime.quoted.Unpickler.Pickled, val args: Seq[Any]) extends Expr[T] {
86-
override def toString: String = s"Expr(<pickled tasty>)"
87-
}
82+
import scala.quoted.{Expr, QuoteContext}
8883

8984
/** An Expr backed by a tree. Only the current compiler trees are allowed.
9085
*

‎library/src/scala/quoted/Type.scala‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,9 @@ package quoted {
6868

6969
package internal {
7070
package quoted {
71-
import scala.quoted.Type
72-
import scala.runtime.quoted.Unpickler.Pickled
73-
74-
/** A Type backed by a pickled TASTY tree */
75-
final class TastyType[T](val tasty: Pickled, val args: Seq[Any]) extends Type[T] {
76-
override def toString(): String = s"Type(<pickled tasty>)"
77-
}
7871

7972
/** An Type backed by a tree */
80-
final class TreeType[Tree](val typeTree: Tree) extends Type[Any] {
73+
final class TreeType[Tree](val typeTree: Tree) extends scala.quoted.Type[Any] {
8174
override def toString: String = s"Type(<tasty tree>)"
8275
}
8376

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /