Skip to content

Commit d101462

Browse files
authored
Merge pull request #5763 from dotty-staging/split-staging-2
Extract quote reification from Staging phase
2 parents fa8471d + bb9874c commit d101462

Some content is hidden

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

51 files changed

+1048
-751
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 */

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Flags._, Trees._, Types._, Contexts._
77
import Names._, StdNames._, NameOps._, Symbols._
88
import typer.ConstFold
99
import reporting.trace
10+
import dotty.tools.dotc.transform.SymUtils._
1011

1112
import scala.annotation.tailrec
1213

@@ -815,6 +816,28 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
815816
}
816817
}
817818
}
819+
820+
/** Extractors for quotes */
821+
object Quoted {
822+
/** Extracts the content of a quoted tree.
823+
* The result can be the contents of a term or type quote, which
824+
* will return a term or type tree respectively.
825+
*/
826+
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
827+
case tree: GenericApply[Type] if tree.symbol.isQuote => Some(tree.args.head)
828+
case _ => None
829+
}
830+
}
831+
832+
/** Extractors for splices */
833+
object Spliced {
834+
/** Extracts the content of a spliced tree.
835+
* The result can be the contents of a term or type splice, which
836+
* will return a term or type tree respectively.
837+
*/
838+
def unapply(tree: tpd.Select)(implicit ctx: Context): Option[tpd.Tree] =
839+
if (tree.symbol.isSplice) Some(tree.qualifier) else None
840+
}
818841
}
819842

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

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

@@ -1438,6 +1439,8 @@ object Trees {
14381439
this(this(x, arg), annot)
14391440
case Thicket(ts) =>
14401441
this(x, ts)
1442+
case Hole(_, args) =>
1443+
this(x, args)
14411444
case _ =>
14421445
foldMoreCases(x, tree)
14431446
}

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: 0 additions & 20 deletions
This file was deleted.

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,11 @@ 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+
val isQuote = tree.fun.hasType && tree.fun.symbol == defn.QuotedType_apply
256+
val (open, close) = if (isQuote) (keywordStr("'["), keywordStr("]")) else ("[", "]")
257+
toTextLocal(tree.fun).provided(!isQuote) ~ open ~ toTextGlobal(tree.args, ", ") ~ close
258+
}
256259

257260
protected def toTextCore[T >: Untyped](tree: Tree[T]): Text = {
258261
import untpd.{modsDeco => _, _}
@@ -320,7 +323,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
320323
if (name.isTypeName) typeText(txt)
321324
else txt
322325
case tree @ Select(qual, name) =>
323-
if (tree.hasType && tree.symbol == defn.QuotedExpr_~ || tree.symbol == defn.QuotedType_~) keywordStr("~(") ~ toTextLocal(qual) ~ keywordStr(")")
326+
if (tree.hasType && tree.symbol == defn.QuotedExpr_~) keywordStr("~(") ~ toTextLocal(qual) ~ keywordStr(")")
327+
else if (tree.hasType && tree.symbol == defn.QuotedType_~) typeText("~(") ~ toTextLocal(qual) ~ typeText(")")
324328
else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name))
325329
else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR)
326330
case tree: This =>
@@ -334,8 +338,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
334338
}
335339
else if (fun.hasType && fun.symbol == defn.QuotedExpr_apply)
336340
keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
337-
else if (fun.hasType && fun.symbol == defn.QuotedType_apply)
338-
keywordStr("'[") ~ toTextGlobal(args, ", ") ~ keywordStr("]")
339341
else
340342
toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
341343
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)