Skip to content

Commit 1b0297e

Browse files
committed
TASTy reflect load complete definition trees
Currently only works with -Yretain-tree. Also fix an issue with TASTy reflect
1 parent e612d55 commit 1b0297e

File tree

25 files changed

+184
-50
lines changed

25 files changed

+184
-50
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class Compiler {
5252
/** Phases dealing with TASTY tree pickling and unpickling */
5353
protected def picklerPhases: List[List[Phase]] =
5454
List(new Pickler) :: // Generate TASTY info
55+
List(new RetainTrees) :: // Retain trees of the compilation units if -Yretain-trees is set
5556
List(new ReifyQuotes) :: // Turn quoted trees into explicit run-time data structures
5657
Nil
5758

compiler/src/dotty/tools/dotc/tastyreflect/FromSymbol.scala

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import dotty.tools.dotc.core.Types._
1010
object FromSymbol {
1111

1212
def definitionFromSym(sym: Symbol)(implicit ctx: Context): tpd.Tree = {
13+
assert(sym.exists)
1314
if (sym.is(Package)) packageDefFromSym(sym)
1415
else if (sym.isClass) classDef(sym.asClass)
1516
else if (sym.isType) typeDefFromSym(sym.asType)
@@ -19,21 +20,52 @@ object FromSymbol {
1920

2021
def packageDefFromSym(sym: Symbol)(implicit ctx: Context): PackageDefinition = PackageDefinitionImpl(sym)
2122

22-
def classDef(cls: ClassSymbol)(implicit ctx: Context): tpd.TypeDef = {
23-
val constrSym = cls.unforcedDecls.find(_.isPrimaryConstructor).orElse(
24-
// Dummy constructor for classes such as `<refinement>`
25-
ctx.newSymbol(cls, nme.CONSTRUCTOR, EmptyFlags, NoType)
26-
)
27-
val constr = tpd.DefDef(constrSym.asTerm)
28-
val parents = cls.classParents.map(tpd.TypeTree(_))
29-
val body = cls.unforcedDecls.filter(!_.isPrimaryConstructor).map(s => definitionFromSym(s))
30-
tpd.ClassDefWithParents(cls, constr, parents, body)
23+
def classDef(cls: ClassSymbol)(implicit ctx: Context): tpd.TypeDef = cls.tree match {
24+
case tree: tpd.TypeDef => tree
25+
case tpd.EmptyTree =>
26+
val constrSym = cls.unforcedDecls.find(_.isPrimaryConstructor).orElse(
27+
// Dummy constructor for classes such as `<refinement>`
28+
ctx.newSymbol(cls, nme.CONSTRUCTOR, EmptyFlags, NoType)
29+
)
30+
val constr = tpd.DefDef(constrSym.asTerm)
31+
val parents = cls.classParents.map(tpd.TypeTree(_))
32+
val body = cls.unforcedDecls.filter(!_.isPrimaryConstructor).map(s => definitionFromSym(s))
33+
tpd.ClassDefWithParents(cls, constr, parents, body)
3134
}
3235

33-
def typeDefFromSym(sym: TypeSymbol)(implicit ctx: Context): tpd.TypeDef = tpd.TypeDef(sym)
36+
// TODO: this logic could be moved inside sym.tree
3437

35-
def defDefFromSym(sym: TermSymbol)(implicit ctx: Context): tpd.DefDef = tpd.DefDef(sym)
38+
def typeDefFromSym(sym: TypeSymbol)(implicit ctx: Context): tpd.TypeDef = tree(sym) match {
39+
case tree: tpd.TypeDef => tree
40+
case tpd.EmptyTree => tpd.TypeDef(sym)
41+
}
42+
43+
def defDefFromSym(sym: TermSymbol)(implicit ctx: Context): tpd.DefDef = tree(sym) match {
44+
case tree: tpd.DefDef => tree
45+
case tpd.EmptyTree => tpd.DefDef(sym)
46+
}
47+
48+
def valDefFromSym(sym: TermSymbol)(implicit ctx: Context): tpd.ValDef = tree(sym) match {
49+
case tree: tpd.ValDef => tree
50+
case tpd.EmptyTree => tpd.ValDef(sym)
51+
}
52+
53+
private def tree(sym: Symbol)(implicit ctx: Context): tpd.Tree = sym.topLevelClass match {
54+
case top: ClassSymbol =>
55+
val findTree = new tpd.TreeAccumulator[tpd.Tree] {
56+
def apply(x: tpd.Tree, tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
57+
if (!x.isEmpty) x
58+
else tree match {
59+
case tree: tpd.DefTree if tree.symbol == sym => tree
60+
// TODO avoid searching in all the tree, look at sym.ownerIterator.toSet
61+
case _ => foldOver(x, tree)
62+
}
3663

37-
def valDefFromSym(sym: TermSymbol)(implicit ctx: Context): tpd.ValDef = tpd.ValDef(sym)
64+
}
65+
}
66+
findTree(tpd.EmptyTree, top.tree)
67+
68+
case _ => tpd.EmptyTree
69+
}
3870

3971
}

compiler/src/dotty/tools/dotc/tastyreflect/TreeOpsImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ trait TreeOpsImpl extends scala.tasty.reflect.TreeOps with TastyCoreImpl with He
344344
}
345345

346346
object Inlined extends InlinedExtractor {
347-
def unapply(x: Term)(implicit ctx: Context): Option[(Option[Term], List[Statement], Term)] = x match {
347+
def unapply(x: Term)(implicit ctx: Context): Option[(Option[Parent], List[Statement], Term)] = x match {
348348
case x: tpd.Inlined =>
349349
Some((optional(x.call), x.bindings, x.expansion))
350350
case _ => None
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import dotty.tools.dotc.ast.tpd
5+
import dotty.tools.dotc.ast.Trees._
6+
import dotty.tools.dotc.core.Contexts._
7+
import dotty.tools.dotc.core.Phases._
8+
9+
/** Retain trees of the compilation units if -Yretain-trees is set */
10+
class RetainTrees extends Phase {
11+
import tpd._
12+
13+
def phaseName: String = "RetainTrees"
14+
15+
def run(implicit ctx: Context): Unit = {
16+
if (ctx.settings.YretainTrees.value)
17+
retainTopLevelClassTrees(ctx.compilationUnit.tpdTree)
18+
}
19+
20+
private def retainTopLevelClassTrees(tree: Tree)(implicit ctx: Context): Unit = tree match {
21+
case PackageDef(_, stats) => stats.foreach(retainTopLevelClassTrees)
22+
case tree: TypeDef => tree.symbol.asClass.treeOrProvider = tree
23+
case _ =>
24+
}
25+
26+
}

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ class CompilationTests extends ParallelTesting {
168168

169169
@Test def runAll: Unit = {
170170
implicit val testGroup: TestGroup = TestGroup("runAll")
171+
compileFilesInDir("tests/run-custom-args/Yretain-trees", defaultOptions and "-Yretain-trees") +
171172
compileFilesInDir("tests/run", defaultOptions)
172173
}.checkRuns()
173174

library/src/scala/tasty/reflect/TreeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ trait TreeOps extends TastyCore {
291291

292292
val Inlined: InlinedExtractor
293293
abstract class InlinedExtractor {
294-
def unapply(tree: Tree)(implicit ctx: Context): Option[(Option[Term], List[Definition], Term)]
294+
def unapply(tree: Tree)(implicit ctx: Context): Option[(Option[Parent], List[Definition], Term)]
295295
}
296296

297297
val SelectOuter: SelectOuterExtractor

library/src/scala/tasty/util/ShowExtractors.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
6767
case Term.Repeated(elems) =>
6868
this += "Term.Repeated(" ++= elems += ")"
6969
case Term.Inlined(call, bindings, expansion) =>
70-
this += "Term.Inlined(" += call += ", " ++= bindings += ", " += expansion += ")"
70+
this += "Term.Inlined("
71+
visitOption(call, visitParent)
72+
this += ", " ++= bindings += ", " += expansion += ")"
7173
case ValDef(name, tpt, rhs) =>
7274
this += "ValDef(\"" += name += "\", " += tpt += ", " += rhs += ")"
7375
case DefDef(name, typeParams, paramss, returnTpt, rhs) =>
@@ -76,10 +78,7 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
7678
this += "TypeDef(\"" += name += "\", " += rhs += ")"
7779
case ClassDef(name, constr, parents, self, body) =>
7880
this += "ClassDef(\"" += name += "\", " += constr += ", "
79-
visitList[Parent](parents, {
80-
case IsTerm(parent) => this += parent
81-
case IsTypeTree(parent) => this += parent
82-
})
81+
visitList[Parent](parents, visitParent)
8382
this += ", " += self += ", " ++= body += ")"
8483
case PackageDef(name, owner) =>
8584
this += "PackageDef(\"" += name += "\", " += owner += ")"
@@ -140,6 +139,11 @@ class ShowExtractors[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
140139
this += "Pattern.TypeTest(" += tpt += ")"
141140
}
142141

142+
def visitParent(x: Parent): Buffer = x match {
143+
case IsTerm(parent) => this += parent
144+
case IsTypeTree(parent) => this += parent
145+
}
146+
143147
def visitConstant(x: Constant): Buffer = x match {
144148
case Constant.Unit() => this += "Constant.Unit()"
145149
case Constant.Null() => this += "Constant.Null()"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DefDef("foo", Nil, Nil, TypeTree.TypeIdent("Int"), Some(Term.Apply(Term.Select(Term.Literal(Constant.Int(1)), "+", Some(Signature(List(scala.Int), scala.Int))), List(Term.Literal(Constant.Int(2))))))
2+
ValDef("bar", TypeTree.TypeIdent("Int"), Some(Term.Apply(Term.Select(Term.Literal(Constant.Int(2)), "+", Some(Signature(List(scala.Int), scala.Int))), List(Term.Literal(Constant.Int(3))))))

0 commit comments

Comments
 (0)