Skip to content

Commit c73f3a3

Browse files
committed
Reorganize children handling
- set Child annotations during completion instead of in PostTyper - report an error if children are added after a `children` query. The purpose of these changes is to make it possible to query children safely during typer.
1 parent a4bbc9a commit c73f3a3

File tree

3 files changed

+42
-24
lines changed

3 files changed

+42
-24
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
103103

104104
private def processMemberDef(tree: Tree)(implicit ctx: Context): tree.type = {
105105
val sym = tree.symbol
106-
sym.registerIfChild()
107106
sym.transformAnnotations(transformAnnot)
108107
sym.defTree = tree
109108
tree

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

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -122,27 +122,6 @@ class SymUtils(val self: Symbol) extends AnyVal {
122122
self
123123
}
124124

125-
/** If this symbol is an enum value or a named class, register it as a child
126-
* in all direct parent classes which are sealed.
127-
*/
128-
def registerIfChild()(implicit ctx: Context): Unit = {
129-
def register(child: Symbol, parent: Type) = {
130-
val cls = parent.classSymbol
131-
if (cls.is(Sealed)) {
132-
if ((child.isInaccessibleChildOf(cls) || child.isAnonymousClass) && !self.hasAnonymousChild)
133-
cls.addAnnotation(Annotation.Child(cls))
134-
else cls.addAnnotation(Annotation.Child(child))
135-
}
136-
}
137-
if (self.isClass && !self.isEnumAnonymClass)
138-
self.asClass.classParents.foreach { parent =>
139-
val child = if (self.is(Module)) self.sourceModule else self
140-
register(child, parent)
141-
}
142-
else if (self.is(CaseVal, butNot = Method | Module))
143-
register(self, self.info)
144-
}
145-
146125
/** Does this symbol refer to anonymous classes synthesized by enum desugaring? */
147126
def isEnumAnonymClass(implicit ctx: Context): Boolean =
148127
self.isAnonymousClass && (self.owner.name.eq(nme.DOLLAR_NEW) || self.owner.is(CaseVal))
@@ -155,10 +134,12 @@ class SymUtils(val self: Symbol) extends AnyVal {
155134
self.isLocal && !cls.topLevelClass.isLinkedWith(self.topLevelClass)
156135

157136
/** If this is a sealed class, its known children */
158-
def children(implicit ctx: Context): List[Symbol] =
137+
def children(implicit ctx: Context): List[Symbol] = {
138+
if (self.isType) self.setFlag(ChildrenQueried)
159139
self.annotations.collect {
160140
case Annotation.Child(child) => child
161141
}
142+
}
162143

163144
def hasAnonymousChild(implicit ctx: Context): Boolean =
164145
children.exists(_ `eq` self)

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import config.Printers.typr
1818
import Annotations._
1919
import Inferencing._
2020
import transform.ValueClasses._
21+
import transform.TypeUtils._
22+
import transform.SymUtils._
2123
import reporting.diagnostic.messages._
2224

2325
trait NamerContextOps { this: Context =>
@@ -742,7 +744,10 @@ class Namer { typer: Typer =>
742744
assert(ctx.mode.is(Mode.Interactive), s"completing $denot in wrong run ${ctx.runId}, was created in ${creationContext.runId}")
743745
denot.info = UnspecifiedErrorType
744746
}
745-
else completeInCreationContext(denot)
747+
else {
748+
completeInCreationContext(denot)
749+
if (denot.isCompleted) registerIfChild(denot)
750+
}
746751
}
747752

748753
protected def addAnnotations(sym: Symbol): Unit = original match {
@@ -790,6 +795,39 @@ class Namer { typer: Typer =>
790795
}
791796
}
792797

798+
/** If completed symbol is an enum value or a named class, register it as a child
799+
* in all direct parent classes which are sealed.
800+
*/
801+
def registerIfChild(denot: SymDenotation)(implicit ctx: Context): Unit = {
802+
val sym = denot.symbol
803+
804+
def register(child: Symbol, parent: Type) = {
805+
val cls = parent.classSymbol
806+
if (cls.is(Sealed)) {
807+
if ((child.isInaccessibleChildOf(cls) || child.isAnonymousClass) && !sym.hasAnonymousChild) {
808+
cls.addAnnotation(Annotation.Child(cls))
809+
}
810+
else {
811+
if (cls.is(ChildrenQueried))
812+
ctx.error(em"""children of ${cls} were already queried before $sym was discovered.
813+
|As a remedy, you could move $sym on the same nesting level as $cls.""")
814+
else {
815+
//println(i"child $child of $cls")
816+
cls.addAnnotation(Annotation.Child(child))
817+
}
818+
}
819+
}
820+
}
821+
822+
if (denot.isClass && !sym.isEnumAnonymClass && !sym.isRefinementClass)
823+
denot.asClass.classParents.foreach { parent =>
824+
val child = if (denot.is(Module)) denot.sourceModule else denot.symbol
825+
register(child, parent)
826+
}
827+
else if (denot.is(CaseVal, butNot = Method | Module))
828+
register(denot.symbol, denot.info)
829+
}
830+
793831
/** Intentionally left without `implicit ctx` parameter. We need
794832
* to pick up the context at the point where the completer was created.
795833
*/

0 commit comments

Comments
 (0)