Skip to content

Commit 49d879f

Browse files
committed
Support on-demand Symbol.defTree synchronization
In the current compiler, the defTree associated with a symbol becomes out-of-sync when we transform the trees. This creates a problem for all analysis that depend on Symbol.defTree. An analysis that depend on tasty should perform the analysis immediately after the picklerPhases --- as it has to handle trees loaded from Tasty which are without any lowering. Analysis that do not cross boundaries of compilation units (e.g. linters) are not subject to the restriction above.
1 parent ecbe3d2 commit 49d879f

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ object Phases {
105105
prevPhases += phase.phaseName
106106
phase
107107
}
108+
109+
// synchronize symbol.defTree if necessary
110+
if phaseToAdd.synchronizeDefTree then
111+
fusedPhases += new SyncDefTree
108112
fusedPhases += phaseToAdd
109113
val shouldAddYCheck = YCheckAfter.containsPhase(phaseToAdd) || YCheckAll
110114
if (shouldAddYCheck) {
@@ -290,9 +294,16 @@ object Phases {
290294
/** If set, implicit search is enabled */
291295
def allowsImplicitSearch: Boolean = false
292296

293-
/** List of names of phases that should precede this phase */
297+
/** List of names of phases that should precede this phase */
294298
def runsAfter: Set[String] = Set.empty
295299

300+
/** Whether this phase require synchronization of symbol.defTree?
301+
*
302+
* The phase `DefTreeSync` will be inserted immediately before this phase
303+
* if `synchronizeDefTree == true`.
304+
*/
305+
def synchronizeDefTree: Boolean = false
306+
296307
/** @pre `isRunnable` returns true */
297308
def run(using Context): Unit
298309

compiler/src/dotty/tools/dotc/transform/MegaPhase.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
144144
private var relaxedTypingCache: Boolean = _
145145
private var relaxedTypingKnown = false
146146

147+
override val synchronizeDefTree: Boolean = miniPhases.exists(_.synchronizeDefTree)
148+
147149
override final def relaxedTyping: Boolean = {
148150
if (!relaxedTypingKnown) {
149151
relaxedTypingCache = miniPhases.exists(_.relaxedTypingInGroup)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
5+
import dotty.tools.dotc._
6+
import ast.tpd
7+
import tpd._
8+
9+
import dotty.tools.dotc.core._
10+
import Contexts._
11+
import Types._
12+
import Symbols._
13+
14+
import dotty.tools.dotc.transform._
15+
import MegaPhase._
16+
17+
18+
/** Synchronize the tree definition associated with symbols
19+
*
20+
* This phase will be automatically inserted before a phase if
21+
* `phase.synchronizeDefTree == true`.
22+
*
23+
*/
24+
class SyncDefTree extends MiniPhase {
25+
26+
val phaseName = "syncDefTree"
27+
28+
override def transformTypeDef(tree: TypeDef)(using Context): Tree = {
29+
tree.symbol.defTree = tree
30+
tree
31+
}
32+
33+
override def transformValDef(tree: ValDef)(using Context): Tree = {
34+
tree.symbol.defTree = tree
35+
tree
36+
}
37+
38+
override def transformDefDef(tree: DefDef)(using Context): Tree = {
39+
tree.symbol.defTree = tree
40+
tree
41+
}
42+
}

compiler/src/dotty/tools/dotc/transform/init/Checker.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class Checker extends MiniPhase {
3030
override def isEnabled(using Context): Boolean =
3131
super.isEnabled && ctx.settings.YcheckInit.value
3232

33+
override def synchronizeDefTree: Boolean = true
34+
3335
override def transformTypeDef(tree: TypeDef)(using Context): tpd.Tree = {
3436
if (!tree.isClassDef) return tree
3537

0 commit comments

Comments
 (0)