Skip to content

Commit c307705

Browse files
Merge pull request #3819 from dotty-staging/encode-large-quotes
Encode large quotes
2 parents d7deabf + b53d3ff commit c307705

File tree

7 files changed

+5052
-14
lines changed

7 files changed

+5052
-14
lines changed

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,22 @@ import dotty.tools.dotc.core.Symbols._
1111
import dotty.tools.dotc.core.tasty.{TastyPickler, TastyPrinter, TastyString}
1212
import dotty.tools.dotc.interpreter.RawQuoted
1313

14+
import scala.runtime.quoted.Unpickler.Pickled
15+
1416
object PickledQuotes {
1517
import tpd._
1618

17-
/** Pickle the quote into a TASTY string */
18-
def pickleQuote(tree: Tree)(implicit ctx: Context): String = {
19-
if (ctx.reporter.hasErrors) "<error>"
19+
/** Pickle the quote into strings */
20+
def pickleQuote(tree: Tree)(implicit ctx: Context): Tree = {
21+
if (ctx.reporter.hasErrors) Literal(Constant("<error>"))
2022
else {
2123
val encapsulated = encapsulateQuote(tree)
2224
val pickled = pickle(encapsulated)
23-
TastyString.tastyToString(pickled)
25+
TastyString.pickle(pickled).foldRight[Tree](ref(defn.NilModule)) { (x, acc) =>
26+
acc.select("::".toTermName)
27+
.appliedToType(defn.StringType)
28+
.appliedTo(Literal(Constant(x)))
29+
}
2430
}
2531
}
2632

@@ -33,7 +39,7 @@ object PickledQuotes {
3339

3440
/** Unpickle the tree contained in the TastyQuoted */
3541
private def unpickleQuote(expr: quoted.TastyQuoted)(implicit ctx: Context): Tree = {
36-
val tastyBytes = TastyString.stringToTasty(expr.tasty)
42+
val tastyBytes = TastyString.unpickle(expr.tasty)
3743
val unpickled = unpickle(tastyBytes, expr.args)
3844
unpickled match {
3945
case PackageDef(_, (vdef: ValDef) :: Nil) => vdef.rhs

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

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

3+
import scala.runtime.quoted.Unpickler.Pickled
4+
35
/** Utils for String representation of TASTY */
46
object TastyString {
57

8+
// Conservative encoding, each byte is encoded in a char
9+
// TODO improve encoding compression
10+
private final val maxStringSize = 65535 / 2
11+
12+
/** Encode TASTY bytes into an Seq of String */
13+
def pickle(bytes: Array[Byte]): Pickled =
14+
bytes.sliding(maxStringSize, maxStringSize).map(bytesToString).toList
15+
616
/** Decode the TASTY String into TASTY bytes */
7-
def stringToTasty(str: String): Array[Byte] = {
8-
val bytes = new Array[Byte](str.length)
9-
for (i <- str.indices) bytes(i) = str.charAt(i).toByte
17+
def unpickle(strings: Pickled): Array[Byte] = {
18+
val bytes = new Array[Byte](strings.map(_.length).sum)
19+
var i = 0
20+
for (str <- strings; j <- str.indices) {
21+
bytes(i) = str.charAt(j).toByte
22+
i += 1
23+
}
1024
bytes
1125
}
1226

13-
/** Encode TASTY bytes into a TASTY String */
14-
def tastyToString(bytes: Array[Byte]): String = {
27+
/** Encode bytes into a String */
28+
private def bytesToString(bytes: Array[Byte]): String = {
29+
assert(bytes.length <= maxStringSize)
1530
val chars = new Array[Char](bytes.length)
1631
for (i <- bytes.indices) chars(i) = (bytes(i) & 0xff).toChar
1732
new String(chars)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ class ReifyQuotes extends MacroTransform {
269269
ref(if (isType) defn.Unpickler_unpickleType else defn.Unpickler_unpickleExpr)
270270
.appliedToType(if (isType) body1.tpe else body1.tpe.widen)
271271
.appliedTo(
272-
Literal(Constant(PickledQuotes.pickleQuote(body1))),
272+
PickledQuotes.pickleQuote(body1),
273273
SeqLiteral(splices, TypeTree(defn.AnyType)))
274274
}
275275
}.withPos(quote.pos)

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ class CompilationTests extends ParallelTesting {
201201
compileFile("../tests/run-special/quote-run-constants.scala", defaultRunWithCompilerOptions) +
202202
compileFile("../tests/run-special/quote-run.scala", defaultRunWithCompilerOptions) +
203203
compileFile("../tests/run-special/quote-run-2.scala", defaultRunWithCompilerOptions) +
204+
compileFile("../tests/run-special/quote-run-large.scala", defaultRunWithCompilerOptions) +
204205
compileFile("../tests/run-special/quote-run-staged-interpreter.scala", defaultRunWithCompilerOptions)
205206
}.checkRuns()
206207

library/src/scala/runtime/quoted/Unpickler.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import scala.quoted._
55
/** Provides methods to unpickle `Expr` and `Type` trees. */
66
object Unpickler {
77

8-
/** Representation of pickled trees. For now it's String, but it
9-
* should be changed to some kind of TASTY bundle.
8+
/** Representation of pickled trees. For now a List[String],
9+
* but it should be changed to some kind of TASTY bundle.
1010
*/
11-
type Pickled = String
11+
type Pickled = List[String]
1212

1313
/** Unpickle `repr` which represents a pickled `Expr` tree,
1414
* replacing splice nodes with `args`
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Foo5000(5)

0 commit comments

Comments
 (0)