Skip to content

Create extractors for Tasty Trees #4279

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 21 commits into from
May 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,12 @@ class Definitions {
def Unpickler_liftedExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr")
def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")

lazy val TastyUniverseModule = ctx.requiredModule("scala.tasty.Universe")
def TastyUniverseModuleClass(implicit ctx: Context) = TastyUniverseModule.symbol.asClass

lazy val TastyUniverse_compilationUniverseR = TastyUniverseModule.requiredMethod("compilationUniverse")
def TastyUniverse_compilationUniverse(implicit ctx: Context) = TastyUniverse_compilationUniverseR.symbol

lazy val EqType = ctx.requiredClassRef("scala.Eq")
def EqClass(implicit ctx: Context) = EqType.symbol.asClass
def EqModule(implicit ctx: Context) = EqClass.companionModule
Expand Down
13 changes: 9 additions & 4 deletions compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import dotty.tools.dotc.core.tasty.{TastyPickler, TastyPrinter, TastyString}

import scala.quoted.Types._
import scala.quoted.Exprs._

import scala.reflect.ClassTag

object PickledQuotes {
Expand Down Expand Up @@ -53,11 +52,17 @@ object PickledQuotes {

/** Transform the expression into its fully spliced Tree */
def quotedExprToTree[T](expr: quoted.Expr[T])(implicit ctx: Context): Tree = expr match {
case expr: TastyExpr[_] => unpickleExpr(expr)
case expr: TastyExpr[_] =>
val unpickled = unpickleExpr(expr)
val force = new TreeTraverser {
def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = traverseChildren(tree)
}
force.traverse(unpickled)
unpickled
case expr: LiftedExpr[T] =>
expr.value match {
case value: Class[_] => ref(defn.Predef_classOf).appliedToType(classToType(value))
case value=> Literal(Constant(value))
case value => Literal(Constant(value))
}
case expr: TreeExpr[Tree] @unchecked => expr.tree
case expr: FunctionAppliedTo[_, _] =>
Expand All @@ -68,7 +73,7 @@ object PickledQuotes {
def quotedTypeToTree(expr: quoted.Type[_])(implicit ctx: Context): Tree = expr match {
case expr: TastyType[_] => unpickleType(expr)
case expr: TaggedType[_] => classTagToTypeTree(expr.ct)
case expr: TreeType[Tree] @unchecked => expr.tree
case expr: TreeType[Tree] @unchecked => expr.typeTree
}

/** Unpickle the tree contained in the TastyExpr */
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,10 @@ class TreeUnpickler(reader: TastyReader,
val idx = readNat()
val args = until(end)(readTerm())
val splice = splices(idx)
val reifiedArgs = args.map(arg => if (arg.isTerm) new TreeExpr(arg, PickledQuotes.pickleExpr(arg)) else new TreeType(arg))
def wrap(arg: Tree) =
if (arg.isTerm) new TreeExpr(arg, PickledQuotes.pickleExpr(arg))
else new TreeType(arg)
val reifiedArgs = args.map(wrap)
if (isType) {
val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs)
PickledQuotes.quotedTypeToTree(quotedType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import dotty.tools.dotc.util.Positions.Position
import dotty.tools.dotc.util.SourceFile
import dotty.tools.io.{AbstractFile, Path, PlainFile}

import scala.quoted.Expr
import scala.quoted.{Expr, Type}

/** Compiler that takes the contents of a quoted expression `expr` and produces
* a class file with `class ' { def apply: Object = expr }`.
*/
class ExprCompiler(directory: AbstractFile) extends Compiler {
class QuoteCompiler(directory: AbstractFile) extends Compiler {
import tpd._

/** A GenBCode phase that outputs to a virtual directory */
Expand All @@ -35,7 +35,7 @@ class ExprCompiler(directory: AbstractFile) extends Compiler {
}

override protected def frontendPhases: List[List[Phase]] =
List(List(new ExprFrontend(putInClass = true)))
List(List(new QuotedFrontend(putInClass = true)))

override protected def picklerPhases: List[List[Phase]] =
List(List(new ReifyQuotes))
Expand All @@ -50,8 +50,8 @@ class ExprCompiler(directory: AbstractFile) extends Compiler {

def outputClassName: TypeName = "Quoted".toTypeName

/** Frontend that receives scala.quoted.Expr as input */
class ExprFrontend(putInClass: Boolean) extends FrontEnd {
/** Frontend that receives a scala.quoted.Expr or scala.quoted.Type as input */
class QuotedFrontend(putInClass: Boolean) extends FrontEnd {
import tpd._

override def isTyper = false
Expand All @@ -64,6 +64,11 @@ class ExprCompiler(directory: AbstractFile) extends Compiler {
else PickledQuotes.quotedExprToTree(exprUnit.expr)
val source = new SourceFile("", Seq())
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
case typeUnit: TypeCompilationUnit =>
assert(!putInClass)
val tree = PickledQuotes.quotedTypeToTree(typeUnit.tpe)
val source = new SourceFile("", Seq())
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
}
}

Expand Down Expand Up @@ -93,6 +98,10 @@ class ExprCompiler(directory: AbstractFile) extends Compiler {
val units = new ExprCompilationUnit(expr) :: Nil
compileUnits(units)
}
def compileType(tpe: Type[_]): Unit = {
val units = new TypeCompilationUnit(tpe) :: Nil
compileUnits(units)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Phases.Phase

/** Compiler that takes the contents of a quoted expression `expr` and outputs it's tree. */
class ExprDecompiler(output: tpd.Tree => Context => Unit) extends ExprCompiler(null) {
/** Compiler that takes the contents of a quoted expression (or type) and outputs it's tree. */
class QuoteDecompiler(output: tpd.Tree => Context => Unit) extends QuoteCompiler(null) {
override def phases: List[List[Phase]] = List(
List(new ExprFrontend(putInClass = false)), // Create class from Expr
List(new QuotedFrontend(putInClass = false)), // Create class from Expr
List(new QuoteTreeOutput(output))
)

class QuoteTreeOutput(output: tpd.Tree => Context => Unit) extends Phase {
override def phaseName: String = "quotePrinter"
override def phaseName: String = "quoteOutput"
override def run(implicit ctx: Context): Unit = output(ctx.compilationUnit.tpdTree)(ctx)
}
}
18 changes: 15 additions & 3 deletions compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, VirtualDirectory
import dotty.tools.repl.AbstractFileClassLoader
import dotty.tools.dotc.printing.DecompilerPrinter

import scala.quoted.Expr
import scala.quoted.{Expr, Type}

import java.net.URLClassLoader

Expand All @@ -28,7 +28,7 @@ class QuoteDriver extends Driver {
new VirtualDirectory("(memory)", None)
}

val driver = new ExprCompiler(outDir)
val driver = new QuoteCompiler(outDir)
driver.newRun(ctx).compileExpr(expr)

val classLoader = new AbstractFileClassLoader(outDir, this.getClass.getClassLoader)
Expand Down Expand Up @@ -58,10 +58,22 @@ class QuoteDriver extends Driver {
assert(output.isEmpty)
output = Some(f(tree, ctx))
}
new ExprDecompiler(registerTree).newRun(ctx).compileExpr(expr)
new QuoteDecompiler(registerTree).newRun(ctx).compileExpr(expr)
output.getOrElse(throw new Exception("Could not extract " + expr))
}

def withTypeTree[T](tpe: Type[_], f: (TypTree, Context) => T, settings: Settings[_]): T = {
val (_, ctx: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)

var output: Option[T] = None
def registerTree(tree: tpd.Tree)(ctx: Context): Unit = {
assert(output.isEmpty)
output = Some(f(tree.asInstanceOf[TypTree], ctx))
}
new QuoteDecompiler(registerTree).newRun(ctx).compileType(tpe)
output.getOrElse(throw new Exception("Could not extract " + tpe))
}

override def initCtx: Context = {
val ictx = super.initCtx.fresh
var classpath = System.getProperty("java.class.path")
Expand Down
16 changes: 0 additions & 16 deletions compiler/src/dotty/tools/dotc/quoted/Toolbox.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package dotty.tools.dotc.quoted

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Constants._
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.quoted.PickledQuotes
import dotty.tools.dotc.printing.RefinedPrinter

import scala.quoted.Expr
Expand Down Expand Up @@ -48,19 +45,6 @@ object Toolbox {
case _ => new QuoteDriver().show(expr, showSettings)
}

def toConstantOpt(expr: Expr[T]): Option[T] = {
def toConstantOpt(tree: Tree): Option[T] = tree match {
case Literal(Constant(c)) => Some(c.asInstanceOf[T])
case Block(Nil, e) => toConstantOpt(e)
case Inlined(_, Nil, e) => toConstantOpt(e)
case _ => None
}
expr match {
case expr: LiftedExpr[T] => Some(expr.value)
case _ => new QuoteDriver().withTree(expr, (tree, _) => toConstantOpt(tree), Settings.run())
}
}

}

class Settings[T] private (val outDir: Option[String], val rawTree: Boolean, val compilerArgs: List[String])
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/quoted/TypeCompilationUnit.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dotty.tools.dotc.quoted

import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.util.NoSource

import scala.quoted.Type

/* Compilation unit containing the contents of a quoted type */
class TypeCompilationUnit(val tpe: Type[_]) extends CompilationUnit(NoSource) {
override def toString = s"Type($tpe)"
}
7 changes: 7 additions & 0 deletions compiler/src/dotty/tools/dotc/tasty/CompilationUniverse.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dotty.tools.dotc.tasty

import dotty.tools.dotc.core.Contexts.Context

class CompilationUniverse(val context: Context) extends scala.tasty.Universe {
val tasty: TastyImpl.type = TastyImpl
}
66 changes: 66 additions & 0 deletions compiler/src/dotty/tools/dotc/tasty/FlagSet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dotty.tools.dotc.tasty

import dotty.tools.dotc.core.Flags
import dotty.tools.dotc.core.Flags._

class FlagSet(flags: Flags.FlagSet) extends scala.tasty.FlagSet {

def isProtected: Boolean = flags.is(Protected)
def isAbstract: Boolean = flags.is(Abstract)
def isFinal: Boolean = flags.is(Final)
def isSealed: Boolean = flags.is(Sealed)
def isCase: Boolean = flags.is(Case)
def isImplicit: Boolean = flags.is(Implicit)
def isErased: Boolean = flags.is(Erased)
def isLazy: Boolean = flags.is(Lazy)
def isOverride: Boolean = flags.is(Override)
def isInline: Boolean = flags.is(Inline)
def isMacro: Boolean = flags.is(Macro)
def isStatic: Boolean = flags.is(JavaStatic)
def isObject: Boolean = flags.is(Module)
def isTrait: Boolean = flags.is(Trait)
def isLocal: Boolean = flags.is(Local)
def isSynthetic: Boolean = flags.is(Synthetic)
def isArtifact: Boolean = flags.is(Artifact)
def isMutable: Boolean = flags.is(Mutable)
def isLabel: Boolean = flags.is(Label)
def isFieldAccessor: Boolean = flags.is(Accessor)
def isCaseAcessor: Boolean = flags.is(CaseAccessor)
def isCovariant: Boolean = flags.is(Covariant)
def isContravariant: Boolean = flags.is(Contravariant)
def isScala2X: Boolean = flags.is(Scala2x)
def isDefaultParameterized: Boolean = flags.is(DefaultParameterized)
def isStable: Boolean = flags.is(Stable)

override def toString: String = {
val flags = List.newBuilder[String]
if (isProtected) flags += "protected "
if (isAbstract) flags += "abstract"
if (isFinal) flags += "final"
if (isSealed) flags += "sealed"
if (isCase) flags += "case"
if (isImplicit) flags += "implicit"
if (isErased) flags += "erased"
if (isLazy) flags += "lazy"
if (isOverride) flags += "override"
if (isInline) flags += "inline"
if (isMacro) flags += "macro"
if (isStatic) flags += "javaStatic"
if (isObject) flags += "module"
if (isTrait) flags += "trait"
if (isLocal) flags += "local"
if (isSynthetic) flags += "synthetic"
if (isArtifact) flags += "artifact"
if (isMutable) flags += "mutable"
if (isLabel) flags += "label"
if (isFieldAccessor) flags += "accessor"
if (isCaseAcessor) flags += "caseAccessor"
if (isCovariant) flags += "covariant"
if (isContravariant) flags += "contravariant"
if (isScala2X) flags += "scala2x"
if (isDefaultParameterized) flags += "defaultParameterized"
if (isStable) flags += "stable"
flags.result().mkString("<", ",", ">")
}

}
35 changes: 35 additions & 0 deletions compiler/src/dotty/tools/dotc/tasty/FromSymbol.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package dotty.tools.dotc.tasty

import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.Flags._

object FromSymbol {

def definition(sym: Symbol)(implicit ctx: Context): tpd.Tree = {
if (sym.is(Package)) packageDef(sym)
else if (sym == defn.AnyClass) tpd.EmptyTree // FIXME
else if (sym == defn.NothingClass) tpd.EmptyTree // FIXME
else if (sym.isClass) classDef(sym.asClass)
else if (sym.isType) typeDef(sym.asType)
else if (sym.is(Method)) defDef(sym.asTerm)
else valDef(sym.asTerm)
}

def packageDef(sym: Symbol)(implicit ctx: Context): PackageDefinition = PackageDefinitionImpl(sym)

def classDef(cls: ClassSymbol)(implicit ctx: Context): tpd.Tree = {
val constr = tpd.DefDef(cls.unforcedDecls.find(_.isPrimaryConstructor).asTerm)
val body = cls.unforcedDecls.filter(!_.isPrimaryConstructor).map(s => definition(s))
val superArgs = Nil // TODO
tpd.ClassDef(cls, constr, body, superArgs)
}

def typeDef(sym: TypeSymbol)(implicit ctx: Context): tpd.TypeDef = tpd.TypeDef(sym)

def defDef(sym: TermSymbol)(implicit ctx: Context): tpd.DefDef = tpd.DefDef(sym)

def valDef(sym: TermSymbol)(implicit ctx: Context): tpd.ValDef = tpd.ValDef(sym)

}
Loading