Skip to content

Commit af8093e

Browse files
committed
Extract quote reification from Staging
Split current `Staging` into `Staging` and `ReifyQuotes` - `Staging` - Just before `Pickler` - Checks PCP - Heals phase consistency by replacing `T` with `~implicitly[Type[T]]({{t}})` (actually `~t`) - Expand macros - Ycheck that PCP holds (without healing) until `ReifyQuotes` - `ReifyQuotes` - Aliases all type splices by replacing `~t` by `T$1` and inserting `type T$1 = ~t` at the start of the quoted block. - Transform `'{ ... ~(... ) ... }` into `unpickle('{ ... Hole(...) ... }, List(args => ....))` - `TreeMapWithStages` a new `TreeMap` that contains the logic to track quotation levels while mapping the tree. - Moved logic from `MacroTransformWithImplicits` to `TreeMapWithImplicits` to be able to tranform a tree without the need to be in a macro transform. This will be useful to integrate the PCP checks and macro expansion in `Typer`.
1 parent d8ddbf7 commit af8093e

Some content is hidden

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

50 files changed

+1049
-726
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class Compiler {
4545

4646
/** Phases dealing with TASTY tree pickling and unpickling */
4747
protected def picklerPhases: List[List[Phase]] =
48+
List(new Staging) :: // Check PCP, heal quoted types and expand macros
4849
List(new Pickler) :: // Generate TASTY info
49-
List(new Staging) :: // Expand macros and turn quoted trees into explicit run-time data structures
50+
List(new ReifyQuotes) :: // Turn quoted trees into explicit run-time data structures
5051
Nil
5152

5253
/** Phases dealing with the transformation from pickled trees to backend trees */
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package dotty.tools.dotc
2+
package ast
3+
4+
import core._
5+
import ast.Trees._
6+
import Contexts._
7+
import Symbols._
8+
import annotation.tailrec
9+
10+
/** A TreeMap that maintains the necessary infrastructore to support
11+
* contxtual implicit searches (type-scope implicits are supported anyway).
12+
*/
13+
class TreeMapWithImplicits extends ast.tpd.TreeMap {
14+
import ast.tpd._
15+
16+
protected def localCtx(tree: Tree)(implicit ctx: Context): FreshContext = {
17+
val sym = tree.symbol
18+
val owner = if (sym is Flags.PackageVal) sym.moduleClass else sym
19+
ctx.fresh.setTree(tree).setOwner(owner)
20+
}
21+
22+
def transformSelf(vd: ValDef)(implicit ctx: Context): ValDef =
23+
cpy.ValDef(vd)(tpt = transform(vd.tpt))
24+
25+
/** Transform statements, while maintaining import contexts and expression contexts
26+
* in the same way as Typer does. The code addresses additional concerns:
27+
* - be tail-recursive where possible
28+
* - don't re-allocate trees where nothing has changed
29+
*/
30+
def transformStats(stats: List[Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
31+
32+
@tailrec def traverse(curStats: List[Tree])(implicit ctx: Context): List[Tree] = {
33+
34+
def recur(stats: List[Tree], changed: Tree, rest: List[Tree])(implicit ctx: Context): List[Tree] = {
35+
if (stats eq curStats) {
36+
val rest1 = transformStats(rest, exprOwner)
37+
changed match {
38+
case Thicket(trees) => trees ::: rest1
39+
case tree => tree :: rest1
40+
}
41+
}
42+
else stats.head :: recur(stats.tail, changed, rest)
43+
}
44+
45+
curStats match {
46+
case stat :: rest =>
47+
val statCtx = stat match {
48+
case stat: DefTree => ctx
49+
case _ => ctx.exprContext(stat, exprOwner)
50+
}
51+
val restCtx = stat match {
52+
case stat: Import => ctx.importContext(stat, stat.symbol)
53+
case _ => ctx
54+
}
55+
val stat1 = transform(stat)(statCtx)
56+
if (stat1 ne stat) recur(stats, stat1, rest)(restCtx)
57+
else traverse(rest)(restCtx)
58+
case nil =>
59+
stats
60+
}
61+
}
62+
traverse(stats)
63+
}
64+
65+
private def nestedScopeCtx(defs: List[Tree])(implicit ctx: Context): Context = {
66+
val nestedCtx = ctx.fresh.setNewScope
67+
defs foreach {
68+
case d: DefTree => nestedCtx.enter(d.symbol)
69+
case _ =>
70+
}
71+
nestedCtx
72+
}
73+
74+
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
75+
try tree match {
76+
case tree: Block =>
77+
super.transform(tree)(nestedScopeCtx(tree.stats))
78+
case tree: DefDef =>
79+
implicit val ctx1 = localCtx(tree)(ctx)
80+
cpy.DefDef(tree)(
81+
tree.name,
82+
transformSub(tree.tparams),
83+
tree.vparamss mapConserve (transformSub(_)),
84+
transform(tree.tpt),
85+
transform(tree.rhs)(nestedScopeCtx(tree.vparamss.flatten)))
86+
case EmptyValDef =>
87+
tree
88+
case _: PackageDef | _: MemberDef =>
89+
super.transform(tree)(localCtx(tree))
90+
case impl @ Template(constr, parents, self, _) =>
91+
cpy.Template(tree)(
92+
transformSub(constr),
93+
transform(parents)(ctx.superCallContext),
94+
Nil,
95+
transformSelf(self),
96+
transformStats(impl.body, tree.symbol))
97+
case _ =>
98+
super.transform(tree)
99+
}
100+
catch {
101+
case ex: TypeError =>
102+
ctx.error(ex.toMessage, tree.sourcePos)
103+
tree
104+
}
105+
}
106+
107+
}

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import annotation.internal.sharable
1515
import annotation.unchecked.uncheckedVariance
1616
import annotation.constructorOnly
1717
import Decorators._
18+
import dotty.tools.dotc.core.tasty.TreePickler.Hole
1819

1920
object Trees {
2021

@@ -1435,6 +1436,8 @@ object Trees {
14351436
this(this(x, arg), annot)
14361437
case Thicket(ts) =>
14371438
this(x, ts)
1439+
case Hole(_, args) =>
1440+
this(x, args)
14381441
case _ =>
14391442
foldMoreCases(x, tree)
14401443
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ object Contexts {
473473
def typerPhase: Phase = base.typerPhase
474474
def sbtExtractDependenciesPhase: Phase = base.sbtExtractDependenciesPhase
475475
def picklerPhase: Phase = base.picklerPhase
476+
def reifyQuotesPhase: Phase = base.reifyQuotesPhase
476477
def refchecksPhase: Phase = base.refchecksPhase
477478
def patmatPhase: Phase = base.patmatPhase
478479
def elimRepeatedPhase: Phase = base.elimRepeatedPhase

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ object Phases {
219219
private[this] var myTyperPhase: Phase = _
220220
private[this] var mySbtExtractDependenciesPhase: Phase = _
221221
private[this] var myPicklerPhase: Phase = _
222+
private[this] var myReifyQuotesPhase: Phase = _
222223
private[this] var myCollectNullableFieldsPhase: Phase = _
223224
private[this] var myRefChecksPhase: Phase = _
224225
private[this] var myPatmatPhase: Phase = _
@@ -235,6 +236,7 @@ object Phases {
235236
final def typerPhase: Phase = myTyperPhase
236237
final def sbtExtractDependenciesPhase: Phase = mySbtExtractDependenciesPhase
237238
final def picklerPhase: Phase = myPicklerPhase
239+
final def reifyQuotesPhase: Phase = myReifyQuotesPhase
238240
final def collectNullableFieldsPhase: Phase = myCollectNullableFieldsPhase
239241
final def refchecksPhase: Phase = myRefChecksPhase
240242
final def patmatPhase: Phase = myPatmatPhase
@@ -254,6 +256,7 @@ object Phases {
254256
myTyperPhase = phaseOfClass(classOf[FrontEnd])
255257
mySbtExtractDependenciesPhase = phaseOfClass(classOf[sbt.ExtractDependencies])
256258
myPicklerPhase = phaseOfClass(classOf[Pickler])
259+
myReifyQuotesPhase = phaseOfClass(classOf[ReifyQuotes])
257260
myCollectNullableFieldsPhase = phaseOfClass(classOf[CollectNullableFields])
258261
myRefChecksPhase = phaseOfClass(classOf[RefChecks])
259262
myElimRepeatedPhase = phaseOfClass(classOf[ElimRepeated])

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import dotty.tools.dotc.transform.SymUtils._
1010
object Quoted {
1111

1212
/** Extracts the content of a quoted tree.
13-
* The result can be the contents of a term ot type quote, which
13+
* The result can be the contents of a term or type quote, which
1414
* will return a term or type tree respectively.
1515
*/
1616
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dotty.tools.dotc.core.quoted
2+
3+
import dotty.tools.dotc.ast.Trees._
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.Types.Type
7+
import dotty.tools.dotc.transform.SymUtils._
8+
9+
/** Extractors for splices */
10+
object Spliced {
11+
12+
/** Extracts the content of a spliced tree.
13+
* The result can be the contents of a term or type splice, which
14+
* will return a term or type tree respectively.
15+
*/
16+
def unapply(tree: tpd.Select)(implicit ctx: Context): Option[tpd.Tree] =
17+
if (tree.symbol.isSplice) Some(tree.qualifier) else None
18+
19+
}

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
251251
protected def blockText[T >: Untyped](trees: List[Tree[T]]): Text =
252252
("{" ~ toText(trees, "\n") ~ "}").close
253253

254-
protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text =
255-
toTextLocal(tree.fun) ~ "[" ~ toTextGlobal(tree.args, ", ") ~ "]"
254+
protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text = {
255+
if (tree.fun.hasType && tree.fun.symbol == defn.QuotedType_apply)
256+
keywordStr("'[") ~ toTextGlobal(tree.args, ", ") ~ keywordStr("]")
257+
else
258+
toTextLocal(tree.fun) ~ "[" ~ toTextGlobal(tree.args, ", ") ~ "]"
259+
}
256260

257261
protected def toTextCore[T >: Untyped](tree: Tree[T]): Text = {
258262
import untpd.{modsDeco => _, _}
@@ -320,7 +324,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
320324
if (name.isTypeName) typeText(txt)
321325
else txt
322326
case tree @ Select(qual, name) =>
323-
if (tree.hasType && tree.symbol == defn.QuotedExpr_~ || tree.symbol == defn.QuotedType_~) keywordStr("~(") ~ toTextLocal(qual) ~ keywordStr(")")
327+
if (tree.hasType && tree.symbol == defn.QuotedExpr_~) keywordStr("~(") ~ toTextLocal(qual) ~ keywordStr(")")
328+
else if (tree.hasType && tree.symbol == defn.QuotedType_~) typeText("~(") ~ toTextLocal(qual) ~ typeText(")")
324329
else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name))
325330
else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR)
326331
case tree: This =>
@@ -334,8 +339,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
334339
}
335340
else if (fun.hasType && fun.symbol == defn.QuotedExpr_apply)
336341
keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
337-
else if (fun.hasType && fun.symbol == defn.QuotedType_apply)
338-
keywordStr("'[") ~ toTextGlobal(args, ", ") ~ keywordStr("]")
339342
else
340343
toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
341344
case tree: TypeApply =>

compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers
777777
tpd.Return(expr, ctx.owner)
778778

779779
def copy(original: Tree)(expr: Term)(implicit ctx: Context): Return =
780-
tpd.cpy.Return(original)(expr, tpd.EmptyTree)
780+
tpd.cpy.Return(original)(expr, tpd.ref(ctx.owner))
781781

782782
def unapply(x: Term)(implicit ctx: Context): Option[Term] = x match {
783783
case x: tpd.Return => Some(x.expr)

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

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

0 commit comments

Comments
 (0)