Skip to content

Commit 299341f

Browse files
committed
WIP Try to fix management of compiler instances of quoted.Expr run and show
Also fix some issues along the way.
1 parent 2f64743 commit 299341f

File tree

186 files changed

+1017
-885
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

186 files changed

+1017
-885
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class ScalaSettings extends Settings.SettingGroup {
116116
val YprintDebug: Setting[Boolean] = BooleanSetting("-Yprint-debug", "when printing trees, print some extra information useful for debugging.")
117117
val YprintDebugOwners: Setting[Boolean] = BooleanSetting("-Yprint-debug-owners", "when printing trees, print owners of definitions.")
118118
val YshowPrintErrors: Setting[Boolean] = BooleanSetting("-Yshow-print-errors", "don't suppress exceptions thrown during tree printing.")
119+
val YshowRawTree: Setting[Boolean] = BooleanSetting("-Yshow-raw-tree", "don't remove quote artifacts")
119120
val YtestPickler: Setting[Boolean] = BooleanSetting("-Ytest-pickler", "self-test for pickling functionality; should be used with -Ystop-after:pickler")
120121
val YcheckReentrant: Setting[Boolean] = BooleanSetting("-Ycheck-reentrant", "check that compiled program does not contain vars that can be accessed from a global root.")
121122
val YdropComments: Setting[Boolean] = BooleanSetting("-Ydrop-comments", "Drop comments when scanning source files.")

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -690,16 +690,30 @@ class Definitions {
690690
lazy val QuotedLiftableType: TypeRef = ctx.requiredClassRef("scala.quoted.Liftable")
691691
def QuotedLiftableClass(implicit ctx: Context): ClassSymbol = QuotedLiftableType.symbol.asClass
692692

693-
def Unpickler_unpickleExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleExpr")
694-
def Unpickler_liftedExpr: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr")
695-
def Unpickler_unpickleType: TermSymbol = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")
693+
lazy val UnpicklerModuleRef: TermRef = ctx.requiredModuleRef("scala.runtime.quoted.Unpickler")
694+
def UnpicklerModule(implicit ctx: Context): Symbol = UnpicklerModuleRef.symbol
695+
lazy val UnpicklerType: TypeRef = ctx.requiredClassRef("scala.runtime.quoted.Unpickler")
696+
def UnpicklerClass(implicit ctx: Context): ClassSymbol = UnpicklerType.symbol.asClass
697+
698+
lazy val Unpickler_unpickleExprR: TermRef = UnpicklerModule.requiredMethodRef("unpickleExpr")
699+
def Unpickler_unpickleExpr: Symbol = Unpickler_unpickleExprR.symbol
700+
lazy val Unpickler_liftedExprR: TermRef = UnpicklerModule.requiredMethodRef("liftedExpr")
701+
def Unpickler_liftedExpr: Symbol = Unpickler_liftedExprR.symbol
702+
lazy val Unpickler_unpickleTypeR: TermRef = UnpicklerModule.requiredMethodRef("unpickleType")
703+
def Unpickler_unpickleType: Symbol = Unpickler_unpickleTypeR.symbol
696704

697705
lazy val TastyTastyType: TypeRef = ctx.requiredClassRef("scala.tasty.Tasty")
698706
def TastyTastyClass(implicit ctx: Context): ClassSymbol = TastyTastyType.symbol.asClass
699707

700708
lazy val TastyTastyModule: TermSymbol = ctx.requiredModule("scala.tasty.Tasty")
701709
lazy val TastyTasty_macroContext: TermSymbol = TastyTastyModule.requiredMethod("macroContext")
702710

711+
lazy val QuoteContextType: TypeRef = ctx.requiredClassRef("scala.quoted.QuoteContext")
712+
def QuoteContextClass(implicit ctx: Context): ClassSymbol = QuoteContextType.symbol.asClass
713+
714+
lazy val QuoteContextModule: TermSymbol = ctx.requiredModule("scala.quoted.QuoteContext")
715+
lazy val QuoteContext_macroContext: TermSymbol = QuoteContextModule.requiredMethod("macroContext")
716+
703717
lazy val EqType: TypeRef = ctx.requiredClassRef("scala.Eq")
704718
def EqClass(implicit ctx: Context): ClassSymbol = EqType.symbol.asClass
705719
def EqModule(implicit ctx: Context): Symbol = EqClass.companionModule

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

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ import scala.reflect.ClassTag
2222
object PickledQuotes {
2323
import tpd._
2424

25-
/** Pickle the tree of the quoted.Expr */
26-
def pickleExpr(tree: Tree)(implicit ctx: Context): scala.quoted.Expr[Any] = {
27-
val pickled = pickleQuote(tree)
28-
scala.runtime.quoted.Unpickler.unpickleExpr(pickled, Nil)
29-
}
30-
3125
/** Pickle the tree of the quote into strings */
3226
def pickleQuote(tree: Tree)(implicit ctx: Context): scala.runtime.quoted.Unpickler.Pickled = {
3327
if (ctx.reporter.hasErrors) Nil
@@ -40,13 +34,6 @@ object PickledQuotes {
4034

4135
/** Transform the expression into its fully spliced Tree */
4236
def quotedExprToTree[T](expr: quoted.Expr[T])(implicit ctx: Context): Tree = expr match {
43-
case expr: TastyExpr[_] =>
44-
val unpickled = unpickleExpr(expr)
45-
val force = new TreeTraverser {
46-
def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = traverseChildren(tree)
47-
}
48-
force.traverse(unpickled)
49-
unpickled
5037
case expr: LiftedExpr[T] =>
5138
expr.value match {
5239
case value: Class[_] => ref(defn.Predef_classOf).appliedToType(classToType(value))
@@ -59,21 +46,26 @@ object PickledQuotes {
5946

6047
/** Transform the expression into its fully spliced TypeTree */
6148
def quotedTypeToTree(expr: quoted.Type[_])(implicit ctx: Context): Tree = expr match {
62-
case expr: TastyType[_] => unpickleType(expr)
6349
case expr: TaggedType[_] => classTagToTypeTree(expr.ct)
6450
case expr: TreeType[Tree] @unchecked => expr.typeTree
6551
}
6652

6753
/** Unpickle the tree contained in the TastyExpr */
68-
private def unpickleExpr(expr: TastyExpr[_])(implicit ctx: Context): Tree = {
69-
val tastyBytes = TastyString.unpickle(expr.tasty)
70-
unpickle(tastyBytes, expr.args, isType = false)(ctx.addMode(Mode.ReadPositions))
54+
def unpickleExpr(tasty: scala.runtime.quoted.Unpickler.Pickled, args: Seq[Any])(implicit ctx: Context): Tree = {
55+
val tastyBytes = TastyString.unpickle(tasty)
56+
val unpickled = unpickle(tastyBytes, args, isType = false)(ctx.addMode(Mode.ReadPositions))
57+
// TODO force should not be done here it should be in run and show
58+
val force = new TreeTraverser {
59+
def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = traverseChildren(tree)
60+
}
61+
force.traverse(unpickled)
62+
unpickled
7163
}
7264

7365
/** Unpickle the tree contained in the TastyType */
74-
private def unpickleType(ttpe: TastyType[_])(implicit ctx: Context): Tree = {
75-
val tastyBytes = TastyString.unpickle(ttpe.tasty)
76-
unpickle(tastyBytes, ttpe.args, isType = true)(ctx.addMode(Mode.ReadPositions))
66+
def unpickleType(tasty: scala.runtime.quoted.Unpickler.Pickled, args: Seq[Any])(implicit ctx: Context): Tree = {
67+
val tastyBytes = TastyString.unpickle(tasty)
68+
unpickle(tastyBytes, args, isType = true)(ctx.addMode(Mode.ReadPositions))
7769
}
7870

7971
// TASTY picklingtests/pos/quoteTest.scala

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package dotty.tools.dotc.quoted
33
import dotty.tools.dotc.CompilationUnit
44
import dotty.tools.dotc.util.NoSource
55

6-
import scala.quoted.Expr
6+
import scala.quoted.{Expr, QuoteContext}
77

88
/* Compilation unit containing the contents of a quoted expression */
9-
class ExprCompilationUnit(val expr: Expr[_]) extends CompilationUnit(NoSource) {
10-
override def toString: String = s"Expr($expr)"
11-
}
9+
class ExprCompilationUnit(val expr: QuoteContext => Expr[_]) extends CompilationUnit(NoSource)

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ import dotty.tools.dotc.core.StdNames.nme
1313
import dotty.tools.dotc.core.Symbols.defn
1414
import dotty.tools.dotc.core.Types.ExprType
1515
import dotty.tools.dotc.core.quoted.PickledQuotes
16+
import dotty.tools.dotc.tastyreflect.TastyImpl
1617
import dotty.tools.dotc.transform.ReifyQuotes
1718
import dotty.tools.dotc.typer.FrontEnd
1819
import dotty.tools.dotc.util.Positions.Position
1920
import dotty.tools.dotc.util.SourceFile
2021
import dotty.tools.io.{Path, PlainFile}
2122

22-
import scala.quoted.{Expr, Type}
23+
import scala.quoted.{Expr, QuoteContext, Type}
24+
import scala.runtime.quoted.Unpickler.Pickled
2325

2426
/** Compiler that takes the contents of a quoted expression `expr` and produces
2527
* a class file with `class ' { def apply: Object = expr }`.
@@ -50,7 +52,7 @@ class QuoteCompiler extends Compiler {
5052
case exprUnit: ExprCompilationUnit =>
5153
val tree =
5254
if (putInClass) inClass(exprUnit.expr)
53-
else PickledQuotes.quotedExprToTree(exprUnit.expr)
55+
else unpickleExpr(exprUnit.expr)
5456
val source = new SourceFile("", "")
5557
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
5658
case typeUnit: TypeCompilationUnit =>
@@ -61,11 +63,16 @@ class QuoteCompiler extends Compiler {
6163
}
6264
}
6365

66+
private def unpickleExpr(code: QuoteContext => Expr[_])(implicit ctx: Context) = {
67+
val expr = code(new QuoteContextImpl)
68+
PickledQuotes.quotedExprToTree(expr)
69+
}
70+
6471
/** Places the contents of expr in a compilable tree for a class
6572
* with the following format.
6673
* `package __root__ { class ' { def apply: Any = <expr> } }`
6774
*/
68-
private def inClass(expr: Expr[_])(implicit ctx: Context): Tree = {
75+
private def inClass(code: QuoteContext => Expr[_])(implicit ctx: Context): Tree = {
6976
val pos = Position(0)
7077
val assocFile = new PlainFile(Path("<quote>"))
7178

@@ -74,7 +81,7 @@ class QuoteCompiler extends Compiler {
7481
cls.enter(ctx.newDefaultConstructor(cls), EmptyScope)
7582
val meth = ctx.newSymbol(cls, nme.apply, Method, ExprType(defn.AnyType), coord = pos).entered
7683

77-
val quoted = PickledQuotes.quotedExprToTree(expr)(ctx.withOwner(meth))
84+
val quoted = unpickleExpr(code)(ctx.withOwner(meth))
7885

7986
val run = DefDef(meth, quoted)
8087
val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil)
@@ -83,7 +90,7 @@ class QuoteCompiler extends Compiler {
8390
}
8491

8592
class ExprRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) {
86-
def compileExpr(expr: Expr[_]): Unit = {
93+
def compileExpr(expr: QuoteContext => Expr[_]): Unit = {
8794
val units = new ExprCompilationUnit(expr) :: Nil
8895
compileUnits(units)
8996
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.core.Contexts._
4+
import dotty.tools.dotc.core.quoted.PickledQuotes
5+
import dotty.tools.dotc.tastyreflect.TastyImpl
6+
7+
import scala.quoted.{Expr, Type}
8+
import scala.runtime.quoted.Unpickler.Pickled
9+
10+
class QuoteContextImpl(implicit ctx: Context) extends scala.quoted.QuoteContext {
11+
12+
def unpickleExpr[T](repr: Pickled, args: Seq[Any]): Expr[T] =
13+
new scala.quoted.Exprs.TastyTreeExpr(PickledQuotes.unpickleExpr(repr, args)).asInstanceOf[Expr[T]]
14+
15+
def unpickleType[T](repr: Pickled, args: Seq[Any]): Type[T] =
16+
new scala.quoted.Types.TreeType(PickledQuotes.unpickleType(repr, args)).asInstanceOf[Type[T]]
17+
18+
def show[T](expr: Expr[T]): String = {
19+
val tree = PickledQuotes.quotedExprToTree(expr)
20+
// TODO freshen names
21+
val tree1 =
22+
if (ctx.settings.YshowRawTree.value) tree else (new TreeCleaner).transform(tree)
23+
new TastyImpl(ctx).showSourceCode.showTree(tree1)
24+
}
25+
26+
def show[T](tpe: Type[T]): String = {
27+
val tree = PickledQuotes.quotedTypeToTree(tpe)
28+
// TODO freshen names
29+
val tree1 = if (ctx.settings.YshowRawTree.value) tree else (new TreeCleaner).transform(tree)
30+
new TastyImpl(ctx).showSourceCode.showTypeOrBoundsTree(tree1)
31+
}
32+
33+
}

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

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

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

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import dotty.tools.dotc.tastyreflect.TastyImpl
77
import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, VirtualDirectory}
88
import dotty.tools.repl.AbstractFileClassLoader
99

10-
import scala.quoted.{Expr, Type}
10+
import scala.quoted.{Expr, QuoteContext, Type}
1111
import scala.quoted.Toolbox
1212
import java.net.URLClassLoader
1313

14+
import dotty.tools.dotc.core.quoted.PickledQuotes
15+
1416
class QuoteDriver extends Driver {
15-
import tpd._
1617

1718
private[this] val contextBase: ContextBase = new ContextBase
1819

19-
def run[T](expr: Expr[T], settings: Toolbox.Settings): T = {
20+
def run[T](code: QuoteContext => Expr[T], settings: Toolbox.Settings): T = {
2021
val outDir: AbstractFile = settings.outDir match {
2122
case Some(out) =>
2223
val dir = Directory(out)
@@ -27,10 +28,10 @@ class QuoteDriver extends Driver {
2728
}
2829

2930
val (_, ctx0: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)
30-
val ctx = setColor(ctx0.fresh.setSetting(ctx0.settings.outputDir, outDir), settings)
31+
val ctx = setQuoteSettings(ctx0.fresh.setSetting(ctx0.settings.outputDir, outDir), settings)
3132

3233
val driver = new QuoteCompiler
33-
driver.newRun(ctx).compileExpr(expr)
34+
driver.newRun(ctx).compileExpr(code)
3435

3536
val classLoader = new AbstractFileClassLoader(outDir, this.getClass.getClassLoader)
3637

@@ -42,35 +43,17 @@ class QuoteDriver extends Driver {
4243
}
4344

4445
def show(expr: Expr[_], settings: Toolbox.Settings): String = {
45-
def show(tree: Tree, ctx: Context): String = {
46-
val tree1 = if (settings.showRawTree) tree else (new TreeCleaner).transform(tree)(ctx)
47-
new TastyImpl(ctx).showSourceCode.showTree(tree1)(ctx)
48-
}
49-
withTree(expr, show, settings)
50-
}
51-
52-
def withTree[T](expr: Expr[_], f: (Tree, Context) => T, settings: Toolbox.Settings): T = {
53-
val ctx = setColor(setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)._2.fresh, settings)
54-
55-
var output: Option[T] = None
56-
def registerTree(tree: tpd.Tree)(ctx: Context): Unit = {
57-
assert(output.isEmpty)
58-
output = Some(f(tree, ctx))
59-
}
60-
new QuoteDecompiler(registerTree).newRun(ctx).compileExpr(expr)
61-
output.getOrElse(throw new Exception("Could not extract " + expr))
46+
val (_, ctx: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)
47+
val tree = PickledQuotes.quotedExprToTree(expr)(ctx)
48+
val tree1 = if (settings.showRawTree) tree else (new TreeCleaner).transform(tree)(ctx)
49+
new TastyImpl(ctx).showSourceCode.showTree(tree1)(ctx)
6250
}
6351

64-
def withTypeTree[T](tpe: Type[_], f: (TypTree, Context) => T, settings: Toolbox.Settings): T = {
52+
def show(tpe: Type[_], settings: Toolbox.Settings): String = {
6553
val (_, ctx: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)
66-
67-
var output: Option[T] = None
68-
def registerTree(tree: tpd.Tree)(ctx: Context): Unit = {
69-
assert(output.isEmpty)
70-
output = Some(f(tree.asInstanceOf[TypTree], ctx))
71-
}
72-
new QuoteDecompiler(registerTree).newRun(ctx).compileType(tpe)
73-
output.getOrElse(throw new Exception("Could not extract " + tpe))
54+
val tree = PickledQuotes.quotedTypeToTree(tpe)(ctx)
55+
val tree1 = if (settings.showRawTree) tree else (new TreeCleaner).transform(tree)(ctx)
56+
new TastyImpl(ctx).showSourceCode.showTypeOrBoundsTree(tree1)(ctx)
7457
}
7558

7659
override def initCtx: Context = {
@@ -79,8 +62,10 @@ class QuoteDriver extends Driver {
7962
ictx
8063
}
8164

82-
private def setColor(ctx: FreshContext, settings: Toolbox.Settings): FreshContext =
65+
private def setQuoteSettings(ctx: FreshContext, settings: Toolbox.Settings): ctx.type = {
8366
ctx.setSetting(ctx.settings.color, if (settings.color) "always" else "never")
67+
ctx.setSetting(ctx.settings.YshowRawTree, settings.showRawTree)
68+
}
8469

8570
}
8671

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import dotty.tools.dotc.core.NameKinds.{NumberedInfo, UniqueName}
88
import dotty.tools.dotc.core.SymDenotations.SymDenotation
99
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
1010

11+
// TODO use this in some form again
1112
/** Refreshes local names starting from the second use of the name. Intended for readability of the pretty printed code. */
1213
class RefreshNames extends MiniPhase with SymTransformer {
1314

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,18 @@
11
package dotty.tools.dotc.quoted
22

3-
import dotty.tools.dotc.ast.tpd
4-
5-
import scala.quoted.Expr
6-
import scala.quoted.Exprs.{LiftedExpr, TastyTreeExpr}
3+
import scala.quoted.{Expr, QuoteContext, Type}
74

85
/** Default runners for quoted expressions */
96
object ToolboxImpl {
10-
import tpd._
117

128
def make(settings: scala.quoted.Toolbox.Settings): scala.quoted.Toolbox = new scala.quoted.Toolbox {
139

1410
private[this] val driver: QuoteDriver = new QuoteDriver()
1511

16-
def run[T](expr: Expr[T]): T = expr match {
17-
case expr: LiftedExpr[T] =>
18-
expr.value
19-
case expr: TastyTreeExpr[Tree] @unchecked =>
20-
throw new Exception("Cannot call `Expr.run` on an `Expr` that comes from a macro argument.")
21-
case _ =>
22-
synchronized(driver.run(expr, settings))
12+
protected def runImpl[T](code: QuoteContext => Expr[T]): T = {
13+
// TODO check for recursion and throw if possible (i.e. run inside a run)
14+
synchronized(driver.run(code, settings))
2315
}
2416

25-
def show[T](expr: Expr[T]): String = synchronized(driver.show(expr, settings))
26-
2717
}
2818
}

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,18 @@ class ReifyQuotes extends MacroTransformWithImplicits {
396396
val meth =
397397
if (isType) ref(defn.Unpickler_unpickleType).appliedToType(originalTp)
398398
else ref(defn.Unpickler_unpickleExpr).appliedToType(originalTp.widen)
399-
meth.appliedTo(
400-
liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType),
401-
liftList(splices, defn.AnyType))
399+
val unpickler = ctx.typer.inferImplicitArg(defn.UnpicklerType, body.pos)
400+
unpickler.tpe match {
401+
case fail: SearchFailureType =>
402+
ctx.error("Missing an implicit to unpickle the quote. Use Staged[...] as return type", body.pos) // FIXME change text
403+
EmptyTree
404+
case _ =>
405+
meth.appliedTo(
406+
liftList(PickledQuotes.pickleQuote(body).map(x => Literal(Constant(x))), defn.StringType),
407+
liftList(splices, defn.AnyType),
408+
unpickler
409+
)
410+
}
402411
}
403412
if (splices.nonEmpty) pickleAsTasty()
404413
else if (isType) {

0 commit comments

Comments
 (0)