Skip to content

Commit 6876240

Browse files
Merge pull request #4279 from dotty-staging/tasty-extractors
Create extractors for Tasty Trees
2 parents ba2eafc + 6f52db5 commit 6876240

File tree

75 files changed

+3483
-254
lines changed

Some content is hidden

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

75 files changed

+3483
-254
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,12 @@ class Definitions {
667667
def Unpickler_liftedExpr = ctx.requiredMethod("scala.runtime.quoted.Unpickler.liftedExpr")
668668
def Unpickler_unpickleType = ctx.requiredMethod("scala.runtime.quoted.Unpickler.unpickleType")
669669

670+
lazy val TastyUniverseModule = ctx.requiredModule("scala.tasty.Universe")
671+
def TastyUniverseModuleClass(implicit ctx: Context) = TastyUniverseModule.symbol.asClass
672+
673+
lazy val TastyUniverse_compilationUniverseR = TastyUniverseModule.requiredMethod("compilationUniverse")
674+
def TastyUniverse_compilationUniverse(implicit ctx: Context) = TastyUniverse_compilationUniverseR.symbol
675+
670676
lazy val EqType = ctx.requiredClassRef("scala.Eq")
671677
def EqClass(implicit ctx: Context) = EqType.symbol.asClass
672678
def EqModule(implicit ctx: Context) = EqClass.companionModule

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import dotty.tools.dotc.core.tasty.{TastyPickler, TastyPrinter, TastyString}
1616

1717
import scala.quoted.Types._
1818
import scala.quoted.Exprs._
19-
2019
import scala.reflect.ClassTag
2120

2221
object PickledQuotes {
@@ -53,11 +52,17 @@ object PickledQuotes {
5352

5453
/** Transform the expression into its fully spliced Tree */
5554
def quotedExprToTree[T](expr: quoted.Expr[T])(implicit ctx: Context): Tree = expr match {
56-
case expr: TastyExpr[_] => unpickleExpr(expr)
55+
case expr: TastyExpr[_] =>
56+
val unpickled = unpickleExpr(expr)
57+
val force = new TreeTraverser {
58+
def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = traverseChildren(tree)
59+
}
60+
force.traverse(unpickled)
61+
unpickled
5762
case expr: LiftedExpr[T] =>
5863
expr.value match {
5964
case value: Class[_] => ref(defn.Predef_classOf).appliedToType(classToType(value))
60-
case value=> Literal(Constant(value))
65+
case value => Literal(Constant(value))
6166
}
6267
case expr: TreeExpr[Tree] @unchecked => expr.tree
6368
case expr: FunctionAppliedTo[_, _] =>
@@ -68,7 +73,7 @@ object PickledQuotes {
6873
def quotedTypeToTree(expr: quoted.Type[_])(implicit ctx: Context): Tree = expr match {
6974
case expr: TastyType[_] => unpickleType(expr)
7075
case expr: TaggedType[_] => classTagToTypeTree(expr.ct)
71-
case expr: TreeType[Tree] @unchecked => expr.tree
76+
case expr: TreeType[Tree] @unchecked => expr.typeTree
7277
}
7378

7479
/** Unpickle the tree contained in the TastyExpr */

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,7 +1149,10 @@ class TreeUnpickler(reader: TastyReader,
11491149
val idx = readNat()
11501150
val args = until(end)(readTerm())
11511151
val splice = splices(idx)
1152-
val reifiedArgs = args.map(arg => if (arg.isTerm) new TreeExpr(arg, PickledQuotes.pickleExpr(arg)) else new TreeType(arg))
1152+
def wrap(arg: Tree) =
1153+
if (arg.isTerm) new TreeExpr(arg, PickledQuotes.pickleExpr(arg))
1154+
else new TreeType(arg)
1155+
val reifiedArgs = args.map(wrap)
11531156
if (isType) {
11541157
val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs)
11551158
PickledQuotes.quotedTypeToTree(quotedType)

compiler/src/dotty/tools/dotc/quoted/ExprCompiler.scala renamed to compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ import dotty.tools.dotc.util.Positions.Position
2020
import dotty.tools.dotc.util.SourceFile
2121
import dotty.tools.io.{AbstractFile, Path, PlainFile}
2222

23-
import scala.quoted.Expr
23+
import scala.quoted.{Expr, Type}
2424

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

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

3737
override protected def frontendPhases: List[List[Phase]] =
38-
List(List(new ExprFrontend(putInClass = true)))
38+
List(List(new QuotedFrontend(putInClass = true)))
3939

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

5151
def outputClassName: TypeName = "Quoted".toTypeName
5252

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

5757
override def isTyper = false
@@ -64,6 +64,11 @@ class ExprCompiler(directory: AbstractFile) extends Compiler {
6464
else PickledQuotes.quotedExprToTree(exprUnit.expr)
6565
val source = new SourceFile("", Seq())
6666
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
67+
case typeUnit: TypeCompilationUnit =>
68+
assert(!putInClass)
69+
val tree = PickledQuotes.quotedTypeToTree(typeUnit.tpe)
70+
val source = new SourceFile("", Seq())
71+
CompilationUnit.mkCompilationUnit(source, tree, forceTrees = true)
6772
}
6873
}
6974

@@ -93,6 +98,10 @@ class ExprCompiler(directory: AbstractFile) extends Compiler {
9398
val units = new ExprCompilationUnit(expr) :: Nil
9499
compileUnits(units)
95100
}
101+
def compileType(tpe: Type[_]): Unit = {
102+
val units = new TypeCompilationUnit(tpe) :: Nil
103+
compileUnits(units)
104+
}
96105
}
97106

98107
}

compiler/src/dotty/tools/dotc/quoted/ExprDecompiler.scala renamed to compiler/src/dotty/tools/dotc/quoted/QuoteDecompiler.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import dotty.tools.dotc.ast.tpd
44
import dotty.tools.dotc.core.Contexts.Context
55
import dotty.tools.dotc.core.Phases.Phase
66

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

1414
class QuoteTreeOutput(output: tpd.Tree => Context => Unit) extends Phase {
15-
override def phaseName: String = "quotePrinter"
15+
override def phaseName: String = "quoteOutput"
1616
override def run(implicit ctx: Context): Unit = output(ctx.compilationUnit.tpdTree)(ctx)
1717
}
1818
}

compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, VirtualDirectory
77
import dotty.tools.repl.AbstractFileClassLoader
88
import dotty.tools.dotc.printing.DecompilerPrinter
99

10-
import scala.quoted.Expr
10+
import scala.quoted.{Expr, Type}
1111

1212
import java.net.URLClassLoader
1313

@@ -28,7 +28,7 @@ class QuoteDriver extends Driver {
2828
new VirtualDirectory("(memory)", None)
2929
}
3030

31-
val driver = new ExprCompiler(outDir)
31+
val driver = new QuoteCompiler(outDir)
3232
driver.newRun(ctx).compileExpr(expr)
3333

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

65+
def withTypeTree[T](tpe: Type[_], f: (TypTree, Context) => T, settings: Settings[_]): T = {
66+
val (_, ctx: Context) = setup(settings.compilerArgs.toArray :+ "dummy.scala", initCtx.fresh)
67+
68+
var output: Option[T] = None
69+
def registerTree(tree: tpd.Tree)(ctx: Context): Unit = {
70+
assert(output.isEmpty)
71+
output = Some(f(tree.asInstanceOf[TypTree], ctx))
72+
}
73+
new QuoteDecompiler(registerTree).newRun(ctx).compileType(tpe)
74+
output.getOrElse(throw new Exception("Could not extract " + tpe))
75+
}
76+
6577
override def initCtx: Context = {
6678
val ictx = super.initCtx.fresh
6779
var classpath = System.getProperty("java.class.path")

compiler/src/dotty/tools/dotc/quoted/Toolbox.scala

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package dotty.tools.dotc.quoted
22

3-
import dotty.tools.dotc.ast.Trees._
43
import dotty.tools.dotc.ast.tpd
54
import dotty.tools.dotc.core.Constants._
6-
import dotty.tools.dotc.core.Contexts.Context
7-
import dotty.tools.dotc.core.quoted.PickledQuotes
85
import dotty.tools.dotc.printing.RefinedPrinter
96

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

51-
def toConstantOpt(expr: Expr[T]): Option[T] = {
52-
def toConstantOpt(tree: Tree): Option[T] = tree match {
53-
case Literal(Constant(c)) => Some(c.asInstanceOf[T])
54-
case Block(Nil, e) => toConstantOpt(e)
55-
case Inlined(_, Nil, e) => toConstantOpt(e)
56-
case _ => None
57-
}
58-
expr match {
59-
case expr: LiftedExpr[T] => Some(expr.value)
60-
case _ => new QuoteDriver().withTree(expr, (tree, _) => toConstantOpt(tree), Settings.run())
61-
}
62-
}
63-
6448
}
6549

6650
class Settings[T] private (val outDir: Option[String], val rawTree: Boolean, val compilerArgs: List[String])
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dotty.tools.dotc.quoted
2+
3+
import dotty.tools.dotc.CompilationUnit
4+
import dotty.tools.dotc.util.NoSource
5+
6+
import scala.quoted.Type
7+
8+
/* Compilation unit containing the contents of a quoted type */
9+
class TypeCompilationUnit(val tpe: Type[_]) extends CompilationUnit(NoSource) {
10+
override def toString = s"Type($tpe)"
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package dotty.tools.dotc.tasty
2+
3+
import dotty.tools.dotc.core.Contexts.Context
4+
5+
class CompilationUniverse(val context: Context) extends scala.tasty.Universe {
6+
val tasty: TastyImpl.type = TastyImpl
7+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package dotty.tools.dotc.tasty
2+
3+
import dotty.tools.dotc.core.Flags
4+
import dotty.tools.dotc.core.Flags._
5+
6+
class FlagSet(flags: Flags.FlagSet) extends scala.tasty.FlagSet {
7+
8+
def isProtected: Boolean = flags.is(Protected)
9+
def isAbstract: Boolean = flags.is(Abstract)
10+
def isFinal: Boolean = flags.is(Final)
11+
def isSealed: Boolean = flags.is(Sealed)
12+
def isCase: Boolean = flags.is(Case)
13+
def isImplicit: Boolean = flags.is(Implicit)
14+
def isErased: Boolean = flags.is(Erased)
15+
def isLazy: Boolean = flags.is(Lazy)
16+
def isOverride: Boolean = flags.is(Override)
17+
def isInline: Boolean = flags.is(Inline)
18+
def isMacro: Boolean = flags.is(Macro)
19+
def isStatic: Boolean = flags.is(JavaStatic)
20+
def isObject: Boolean = flags.is(Module)
21+
def isTrait: Boolean = flags.is(Trait)
22+
def isLocal: Boolean = flags.is(Local)
23+
def isSynthetic: Boolean = flags.is(Synthetic)
24+
def isArtifact: Boolean = flags.is(Artifact)
25+
def isMutable: Boolean = flags.is(Mutable)
26+
def isLabel: Boolean = flags.is(Label)
27+
def isFieldAccessor: Boolean = flags.is(Accessor)
28+
def isCaseAcessor: Boolean = flags.is(CaseAccessor)
29+
def isCovariant: Boolean = flags.is(Covariant)
30+
def isContravariant: Boolean = flags.is(Contravariant)
31+
def isScala2X: Boolean = flags.is(Scala2x)
32+
def isDefaultParameterized: Boolean = flags.is(DefaultParameterized)
33+
def isStable: Boolean = flags.is(Stable)
34+
35+
override def toString: String = {
36+
val flags = List.newBuilder[String]
37+
if (isProtected) flags += "protected "
38+
if (isAbstract) flags += "abstract"
39+
if (isFinal) flags += "final"
40+
if (isSealed) flags += "sealed"
41+
if (isCase) flags += "case"
42+
if (isImplicit) flags += "implicit"
43+
if (isErased) flags += "erased"
44+
if (isLazy) flags += "lazy"
45+
if (isOverride) flags += "override"
46+
if (isInline) flags += "inline"
47+
if (isMacro) flags += "macro"
48+
if (isStatic) flags += "javaStatic"
49+
if (isObject) flags += "module"
50+
if (isTrait) flags += "trait"
51+
if (isLocal) flags += "local"
52+
if (isSynthetic) flags += "synthetic"
53+
if (isArtifact) flags += "artifact"
54+
if (isMutable) flags += "mutable"
55+
if (isLabel) flags += "label"
56+
if (isFieldAccessor) flags += "accessor"
57+
if (isCaseAcessor) flags += "caseAccessor"
58+
if (isCovariant) flags += "covariant"
59+
if (isContravariant) flags += "contravariant"
60+
if (isScala2X) flags += "scala2x"
61+
if (isDefaultParameterized) flags += "defaultParameterized"
62+
if (isStable) flags += "stable"
63+
flags.result().mkString("<", ",", ">")
64+
}
65+
66+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dotty.tools.dotc.tasty
2+
3+
import dotty.tools.dotc.ast.tpd
4+
import dotty.tools.dotc.core.Contexts.Context
5+
import dotty.tools.dotc.core.Symbols._
6+
import dotty.tools.dotc.core.Flags._
7+
8+
object FromSymbol {
9+
10+
def definition(sym: Symbol)(implicit ctx: Context): tpd.Tree = {
11+
if (sym.is(Package)) packageDef(sym)
12+
else if (sym == defn.AnyClass) tpd.EmptyTree // FIXME
13+
else if (sym == defn.NothingClass) tpd.EmptyTree // FIXME
14+
else if (sym.isClass) classDef(sym.asClass)
15+
else if (sym.isType) typeDef(sym.asType)
16+
else if (sym.is(Method)) defDef(sym.asTerm)
17+
else valDef(sym.asTerm)
18+
}
19+
20+
def packageDef(sym: Symbol)(implicit ctx: Context): PackageDefinition = PackageDefinitionImpl(sym)
21+
22+
def classDef(cls: ClassSymbol)(implicit ctx: Context): tpd.Tree = {
23+
val constr = tpd.DefDef(cls.unforcedDecls.find(_.isPrimaryConstructor).asTerm)
24+
val body = cls.unforcedDecls.filter(!_.isPrimaryConstructor).map(s => definition(s))
25+
val superArgs = Nil // TODO
26+
tpd.ClassDef(cls, constr, body, superArgs)
27+
}
28+
29+
def typeDef(sym: TypeSymbol)(implicit ctx: Context): tpd.TypeDef = tpd.TypeDef(sym)
30+
31+
def defDef(sym: TermSymbol)(implicit ctx: Context): tpd.DefDef = tpd.DefDef(sym)
32+
33+
def valDef(sym: TermSymbol)(implicit ctx: Context): tpd.ValDef = tpd.ValDef(sym)
34+
35+
}

0 commit comments

Comments
 (0)