Skip to content

Commit 13577d1

Browse files
committed
Implement extractors for TASTY trees
* Define TASTY data types in scala.tasty * Add method get a TASTY term from a quoted.Expr[T] * Implement TASTY tree extractors
1 parent 6f6816d commit 13577d1

File tree

146 files changed

+4152
-242
lines changed

Some content is hidden

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

146 files changed

+4152
-242
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 TastyContextModule = ctx.requiredModule("scala.tasty.Context")
671+
def TastyContextModuleClass(implicit ctx: Context) = TastyContextModule.symbol.asClass
672+
673+
lazy val TastyContext_compilationContextR = TastyContextModule.requiredMethod("compilationContext")
674+
def TastyContext_compilationContext(implicit ctx: Context) = TastyContext_compilationContextR.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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ object PickledQuotes {
3939
case expr: LiftedExpr[T] =>
4040
expr.value match {
4141
case value: Class[_] => ref(defn.Predef_classOf).appliedToType(classToType(value))
42-
case value=> Literal(Constant(value))
42+
case value => Literal(Constant(value))
4343
}
4444
case expr: TreeExpr[Tree] @unchecked => expr.tree
4545
case expr: FunctionAppliedTo[_, _] =>
@@ -50,7 +50,7 @@ object PickledQuotes {
5050
def quotedTypeToTree(expr: quoted.Type[_])(implicit ctx: Context): Tree = expr match {
5151
case expr: TastyType[_] => unpickleType(expr)
5252
case expr: TaggedType[_] => classTagToTypeTree(expr.ct)
53-
case expr: TreeType[Tree] @unchecked => expr.tree
53+
case expr: TreeType[Tree] @unchecked => expr.typeTree
5454
}
5555

5656
/** 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
@@ -1142,7 +1142,10 @@ class TreeUnpickler(reader: TastyReader,
11421142
val idx = readNat()
11431143
val args = until(end)(readTerm())
11441144
val splice = splices(idx)
1145-
val reifiedArgs = args.map(arg => if (arg.isTerm) new TreeExpr(arg) else new TreeType(arg))
1145+
def wrap(arg: Tree) =
1146+
if (arg.isTerm) new TreeExpr(arg)
1147+
else new TreeType(arg)
1148+
val reifiedArgs = args.map(wrap)
11461149
if (isType) {
11471150
val quotedType = splice.asInstanceOf[Seq[Any] => quoted.Type[_]](reifiedArgs)
11481151
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: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
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._
5+
import dotty.tools.dotc.core.Contexts.Context
66
import dotty.tools.dotc.printing.RefinedPrinter
7+
import dotty.tools.dotc.tasty.internal
8+
import dotty.tools.dotc.tasty.internal.TastyContext
79

8-
import scala.quoted.Expr
10+
import scala.quoted.{Expr, Type}
11+
import scala.quoted.Exprs.{LiftedExpr, TreeExpr}
12+
import scala.quoted.Types.TreeType
913
import scala.runtime.BoxedUnit
10-
import scala.quoted.Exprs.LiftedExpr
1114
import scala.runtime.quoted._
15+
import scala.tasty.trees
1216

1317
/** Default runners for quoted expressions */
1418
object Toolbox {
@@ -42,19 +46,6 @@ object Toolbox {
4246
case _ => new QuoteDriver().show(expr, showSettings)
4347
}
4448

45-
def toConstantOpt(expr: Expr[T]): Option[T] = {
46-
def toConstantOpt(tree: Tree): Option[T] = tree match {
47-
case Literal(Constant(c)) => Some(c.asInstanceOf[T])
48-
case Block(Nil, e) => toConstantOpt(e)
49-
case Inlined(_, Nil, e) => toConstantOpt(e)
50-
case _ => None
51-
}
52-
expr match {
53-
case expr: LiftedExpr[T] => Some(expr.value)
54-
case _ => new QuoteDriver().withTree(expr, (tree, _) => toConstantOpt(tree), Settings.run())
55-
}
56-
}
57-
5849
}
5950

6051
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: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dotty.tools.dotc.tasty
2+
package internal
3+
4+
import dotty.tools.dotc.core.Contexts.Context
5+
import dotty.tools.dotc.core.Annotations.Annotation
6+
7+
import scala.tasty.modifiers
8+
9+
object AnnotationModifier {
10+
11+
def apply(tree: Annotation): modifiers.Annotation = new Impl(tree)
12+
13+
def unapplyAnnotation(arg: Impl)(implicit ctx: Context): Option[modifiers.Annotation.Data] = {
14+
Some(Term(arg.annot.tree))
15+
}
16+
17+
private[tasty] class Impl(val annot: Annotation) extends modifiers.Annotation {
18+
override def toString: String = "Annotation"
19+
}
20+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package dotty.tools.dotc.tasty
2+
package internal
3+
4+
import dotty.tools.dotc.ast.Trees
5+
import dotty.tools.dotc.ast.tpd
6+
import dotty.tools.dotc.core.Contexts.Context
7+
8+
import scala.tasty.trees
9+
10+
object CaseDef {
11+
12+
def apply(tree: tpd.CaseDef): trees.CaseDef = new Impl(tree)
13+
14+
def unapplyCaseDef(arg: Impl)(implicit ctx: Context): Option[trees.CaseDef.Data] = {
15+
val Trees.CaseDef(pat, guard, body) = arg.tree
16+
Some(Pattern(pat), if (guard.isEmpty) None else Some(Term(guard)), Term(body))
17+
}
18+
19+
private[tasty] class Impl(val tree: tpd.CaseDef) extends trees.CaseDef with Positioned {
20+
override def toString: String = "CaseDef"
21+
}
22+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package dotty.tools.dotc.tasty
2+
package internal
3+
4+
import dotty.tools.dotc.ast.{Trees, tpd}
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.Flags._
7+
import dotty.tools.dotc.core.Symbols.ClassSymbol
8+
9+
import scala.tasty.modifiers
10+
import scala.tasty.trees
11+
import scala.tasty.types
12+
13+
object ClassDef {
14+
15+
def apply(tree: tpd.TypeDef): trees.ClassDef = new Impl(tree)
16+
17+
def apply(sym: ClassSymbol)(implicit ctx: Context): trees.ClassDef = {
18+
def toTree(sym: ClassSymbol): tpd.TypeDef = {
19+
val constr = tpd.DefDef(sym.unforcedDecls.find(_.isPrimaryConstructor).asTerm)
20+
val body = sym.unforcedDecls.filter(!_.isPrimaryConstructor).map(s =>
21+
if (s.isClass) toTree(s.asClass)
22+
else if (s.isType) tpd.TypeDef(s.asType)
23+
else if (s.is(Method)) tpd.DefDef(s.asTerm)
24+
else tpd.ValDef(s.asTerm)
25+
)
26+
val superArgs = Nil // TODO
27+
tpd.ClassDef(sym, constr, body, superArgs)
28+
}
29+
new Impl(toTree(sym))
30+
}
31+
32+
def unapplyClassDef(arg: Impl)(implicit ctx: Context): Option[trees.ClassDef.Data] = {
33+
val Trees.TypeDef(name, impl@Trees.Template(constr, parents, self, _)) = arg.tree
34+
val className = TypeName(name)
35+
val constructor = DefDef(constr)
36+
val classParents = parents.map(p => if (!p.isType) Term(p) else TypeTree(p))
37+
val selfVal = if (self.isEmpty) None else Some(ValDef(self))
38+
val body = impl.body.map(Statement(_))
39+
Some((className, constructor, classParents, selfVal, body))
40+
}
41+
42+
private[tasty] class Impl(val tree: tpd.TypeDef) extends trees.ClassDef with Definition with Positioned {
43+
def tpe: types.Type = Type(tree.tpe)
44+
def mods(implicit ctx: scala.tasty.Context): List[modifiers.Modifier] = Modifiers(tree)
45+
override def toString: String = "ClassDef"
46+
}
47+
48+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package dotty.tools.dotc.tasty
2+
package internal
3+
4+
import dotty.tools.dotc.core.Constants
5+
6+
import scala.tasty.constants
7+
8+
object Constant {
9+
10+
def apply(constant: Constants.Constant): constants.Constant = new Impl(constant)
11+
12+
def unapplyUnit(arg: Impl): Boolean = arg.const.tag == Constants.UnitTag
13+
14+
def unapplyNull(arg: Impl): Boolean = arg.const.tag == Constants.NullTag
15+
16+
def unapplyBoolean(arg: Impl): Option[Boolean] =
17+
if (arg.const.tag == Constants.BooleanTag) Some(arg.const.booleanValue)
18+
else None
19+
20+
def unapplyByte(arg: Impl): Option[Byte] =
21+
if (arg.const.tag == Constants.ByteTag) Some(arg.const.byteValue)
22+
else None
23+
24+
def unapplyChar(arg: Impl): Option[Char] =
25+
if (arg.const.tag == Constants.CharTag) Some(arg.const.charValue)
26+
else None
27+
28+
def unapplyShort(arg: Impl): Option[Short] =
29+
if (arg.const.tag == Constants.ShortTag) Some(arg.const.shortValue)
30+
else None
31+
32+
def unapplyInt(arg: Impl): Option[Int] =
33+
if (arg.const.tag == Constants.IntTag) Some(arg.const.intValue)
34+
else None
35+
36+
def unapplyLong(arg: Impl): Option[Long] =
37+
if (arg.const.tag == Constants.LongTag) Some(arg.const.longValue)
38+
else None
39+
40+
def unapplyFloat(arg: Impl): Option[Float] =
41+
if (arg.const.tag == Constants.FloatTag) Some(arg.const.floatValue)
42+
else None
43+
44+
def unapplyDouble(arg: Impl): Option[Double] =
45+
if (arg.const.tag == Constants.DoubleTag) Some(arg.const.doubleValue)
46+
else None
47+
48+
def unapplyString(arg: Impl): Option[String] =
49+
if (arg.const.tag == Constants.StringTag) Some(arg.const.stringValue)
50+
else None
51+
52+
private[tasty] class Impl(val const: Constants.Constant) extends constants.Constant {
53+
54+
def value: Any = const.value
55+
56+
override def toString: String = "Constant"
57+
}
58+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package dotty.tools.dotc.tasty
2+
package internal
3+
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.Symbols.TermSymbol
7+
8+
import scala.tasty.modifiers
9+
import scala.tasty.trees
10+
import scala.tasty.types
11+
12+
object DefDef {
13+
14+
def apply(tree: tpd.DefDef): trees.DefDef = new Impl(tree)
15+
16+
def apply(sym: TermSymbol)(implicit ctx: Context): trees.DefDef = new Impl(tpd.DefDef(sym))
17+
18+
def unapplyDefDef(arg: Impl)(implicit ctx: Context): Option[trees.DefDef.Data] = {
19+
val ddef = arg.tree
20+
Some((TermName(ddef.name), ddef.tparams.map(TypeDef(_)), ddef.vparamss.map(_.map(ValDef(_))), TypeTree(ddef.tpt), if (ddef.rhs.isEmpty) None else Some(Term(ddef.rhs))))
21+
}
22+
23+
private[tasty] class Impl(val tree: tpd.DefDef) extends trees.DefDef with Definition with Positioned {
24+
def tpe: types.Type = Type(tree.tpe)
25+
def mods(implicit ctx: scala.tasty.Context): List[modifiers.Modifier] = Modifiers(tree)
26+
override def toString: String = "DefDef"
27+
}
28+
29+
}

0 commit comments

Comments
 (0)