Skip to content
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