Skip to content

Extract quote reification from Staging phase #5763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 14, 2019
Merged
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ class Compiler {

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

/** Phases dealing with the transformation from pickled trees to backend trees */
Expand Down
23 changes: 23 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Flags._, Trees._, Types._, Contexts._
import Names._, StdNames._, NameOps._, Symbols._
import typer.ConstFold
import reporting.trace
import dotty.tools.dotc.transform.SymUtils._

import scala.annotation.tailrec

Expand Down Expand Up @@ -815,6 +816,28 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
}
}
}

/** Extractors for quotes */
object Quoted {
/** Extracts the content of a quoted tree.
* The result can be the contents of a term or type quote, which
* will return a term or type tree respectively.
*/
def unapply(tree: tpd.Tree)(implicit ctx: Context): Option[tpd.Tree] = tree match {
case tree: GenericApply[Type] if tree.symbol.isQuote => Some(tree.args.head)
case _ => None
}
}

/** Extractors for splices */
object Spliced {
/** Extracts the content of a spliced tree.
* The result can be the contents of a term or type splice, which
* will return a term or type tree respectively.
*/
def unapply(tree: tpd.Select)(implicit ctx: Context): Option[tpd.Tree] =
if (tree.symbol.isSplice) Some(tree.qualifier) else None
}
}

object TreeInfo {
Expand Down
106 changes: 106 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/TreeMapWithImplicits.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package dotty.tools.dotc.ast

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Flags._
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.TypeError

import scala.annotation.tailrec

/** A TreeMap that maintains the necessary infrastructure to support
* contxtual implicit searches (type-scope implicits are supported anyway).
*
* This incudes impicits defined in scope as well as imported implicits.
*/
class TreeMapWithImplicits extends tpd.TreeMap {
import tpd._

def transformSelf(vd: ValDef)(implicit ctx: Context): ValDef =
cpy.ValDef(vd)(tpt = transform(vd.tpt))

/** Transform statements, while maintaining import contexts and expression contexts
* in the same way as Typer does. The code addresses additional concerns:
* - be tail-recursive where possible
* - don't re-allocate trees where nothing has changed
*/
def transformStats(stats: List[Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {

@tailrec def traverse(curStats: List[Tree])(implicit ctx: Context): List[Tree] = {

def recur(stats: List[Tree], changed: Tree, rest: List[Tree])(implicit ctx: Context): List[Tree] = {
if (stats eq curStats) {
val rest1 = transformStats(rest, exprOwner)
changed match {
case Thicket(trees) => trees ::: rest1
case tree => tree :: rest1
}
}
else stats.head :: recur(stats.tail, changed, rest)
}

curStats match {
case stat :: rest =>
val statCtx = stat match {
case stat: DefTree => ctx
case _ => ctx.exprContext(stat, exprOwner)
}
val restCtx = stat match {
case stat: Import => ctx.importContext(stat, stat.symbol)
case _ => ctx
}
val stat1 = transform(stat)(statCtx)
if (stat1 ne stat) recur(stats, stat1, rest)(restCtx)
else traverse(rest)(restCtx)
case nil =>
stats
}
}
traverse(stats)
}

private def nestedScopeCtx(defs: List[Tree])(implicit ctx: Context): Context = {
val nestedCtx = ctx.fresh.setNewScope
defs foreach {
case d: DefTree => nestedCtx.enter(d.symbol)
case _ =>
}
nestedCtx
}

override def transform(tree: Tree)(implicit ctx: Context): Tree = {
def localCtx =
if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx
try tree match {
case tree: Block =>
super.transform(tree)(nestedScopeCtx(tree.stats))
case tree: DefDef =>
implicit val ctx = localCtx
cpy.DefDef(tree)(
tree.name,
transformSub(tree.tparams),
tree.vparamss mapConserve (transformSub(_)),
transform(tree.tpt),
transform(tree.rhs)(nestedScopeCtx(tree.vparamss.flatten)))
case EmptyValDef =>
tree
case _: PackageDef | _: MemberDef =>
super.transform(tree)(localCtx)
case impl @ Template(constr, parents, self, _) =>
cpy.Template(tree)(
transformSub(constr),
transform(parents)(ctx.superCallContext),
Nil,
transformSelf(self),
transformStats(impl.body, tree.symbol))
case _ =>
super.transform(tree)
}
catch {
case ex: TypeError =>
ctx.error(ex.toMessage, tree.sourcePos)
tree
}
}

}
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import annotation.internal.sharable
import annotation.unchecked.uncheckedVariance
import annotation.constructorOnly
import Decorators._
import dotty.tools.dotc.core.tasty.TreePickler.Hole

object Trees {

Expand Down Expand Up @@ -1435,6 +1436,8 @@ object Trees {
this(this(x, arg), annot)
case Thicket(ts) =>
this(x, ts)
case Hole(_, args) =>
this(x, args)
case _ =>
foldMoreCases(x, tree)
}
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ object Contexts {
def typerPhase: Phase = base.typerPhase
def sbtExtractDependenciesPhase: Phase = base.sbtExtractDependenciesPhase
def picklerPhase: Phase = base.picklerPhase
def reifyQuotesPhase: Phase = base.reifyQuotesPhase
def refchecksPhase: Phase = base.refchecksPhase
def patmatPhase: Phase = base.patmatPhase
def elimRepeatedPhase: Phase = base.elimRepeatedPhase
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ object Phases {
private[this] var myTyperPhase: Phase = _
private[this] var mySbtExtractDependenciesPhase: Phase = _
private[this] var myPicklerPhase: Phase = _
private[this] var myReifyQuotesPhase: Phase = _
private[this] var myCollectNullableFieldsPhase: Phase = _
private[this] var myRefChecksPhase: Phase = _
private[this] var myPatmatPhase: Phase = _
Expand All @@ -235,6 +236,7 @@ object Phases {
final def typerPhase: Phase = myTyperPhase
final def sbtExtractDependenciesPhase: Phase = mySbtExtractDependenciesPhase
final def picklerPhase: Phase = myPicklerPhase
final def reifyQuotesPhase: Phase = myReifyQuotesPhase
final def collectNullableFieldsPhase: Phase = myCollectNullableFieldsPhase
final def refchecksPhase: Phase = myRefChecksPhase
final def patmatPhase: Phase = myPatmatPhase
Expand All @@ -254,6 +256,7 @@ object Phases {
myTyperPhase = phaseOfClass(classOf[FrontEnd])
mySbtExtractDependenciesPhase = phaseOfClass(classOf[sbt.ExtractDependencies])
myPicklerPhase = phaseOfClass(classOf[Pickler])
myReifyQuotesPhase = phaseOfClass(classOf[ReifyQuotes])
myCollectNullableFieldsPhase = phaseOfClass(classOf[CollectNullableFields])
myRefChecksPhase = phaseOfClass(classOf[RefChecks])
myElimRepeatedPhase = phaseOfClass(classOf[ElimRepeated])
Expand Down
20 changes: 0 additions & 20 deletions compiler/src/dotty/tools/dotc/core/quoted/Quoted.scala

This file was deleted.

12 changes: 7 additions & 5 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
protected def blockText[T >: Untyped](trees: List[Tree[T]]): Text =
("{" ~ toText(trees, "\n") ~ "}").close

protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text =
toTextLocal(tree.fun) ~ "[" ~ toTextGlobal(tree.args, ", ") ~ "]"
protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text = {
val isQuote = tree.fun.hasType && tree.fun.symbol == defn.QuotedType_apply
val (open, close) = if (isQuote) (keywordStr("'["), keywordStr("]")) else ("[", "]")
toTextLocal(tree.fun).provided(!isQuote) ~ open ~ toTextGlobal(tree.args, ", ") ~ close
}

protected def toTextCore[T >: Untyped](tree: Tree[T]): Text = {
import untpd.{modsDeco => _, _}
Expand Down Expand Up @@ -320,7 +323,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
if (name.isTypeName) typeText(txt)
else txt
case tree @ Select(qual, name) =>
if (tree.hasType && tree.symbol == defn.QuotedExpr_~ || tree.symbol == defn.QuotedType_~) keywordStr("~(") ~ toTextLocal(qual) ~ keywordStr(")")
if (tree.hasType && tree.symbol == defn.QuotedExpr_~) keywordStr("~(") ~ toTextLocal(qual) ~ keywordStr(")")
else if (tree.hasType && tree.symbol == defn.QuotedType_~) typeText("~(") ~ toTextLocal(qual) ~ typeText(")")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why typeText instead if keywordStr? (I don't know enough about the syntax highlighting stuff to be able to tell).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this:
screenshot 2019-02-12 at 10 33 08

I added it because in some large examples it was easyer to see which where types splices and which where terms splices.

else if (qual.isType) toTextLocal(qual) ~ "#" ~ typeText(toText(name))
else toTextLocal(qual) ~ ("." ~ nameIdText(tree) provided name != nme.CONSTRUCTOR)
case tree: This =>
Expand All @@ -334,8 +338,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
else if (fun.hasType && fun.symbol == defn.QuotedExpr_apply)
keywordStr("'{") ~ toTextGlobal(args, ", ") ~ keywordStr("}")
else if (fun.hasType && fun.symbol == defn.QuotedType_apply)
keywordStr("'[") ~ toTextGlobal(args, ", ") ~ keywordStr("]")
else
toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")"
case tree: TypeApply =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with CoreImpl with Helpers
tpd.Return(expr, ctx.owner)

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

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

This file was deleted.

Loading