Skip to content

Commit 867bc38

Browse files
committed
Fix order of Child annotations.
Child annotations are stored in reverse order of textual occurrence. We thus have a stable ordering that we can use for typeclass derivations.
1 parent e107604 commit 867bc38

File tree

3 files changed

+31
-7
lines changed

3 files changed

+31
-7
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@ class SymUtils(val self: Symbol) extends AnyVal {
133133
def isInaccessibleChildOf(cls: Symbol)(implicit ctx: Context): Boolean =
134134
self.isLocal && !cls.topLevelClass.isLinkedWith(self.topLevelClass)
135135

136-
/** If this is a sealed class, its known children */
136+
/** If this is a sealed class, its known children in the order of textual occurrence */
137137
def children(implicit ctx: Context): List[Symbol] = {
138138
if (self.isType)
139139
self.setFlag(ChildrenQueried)
140140
self.annotations.collect {
141141
case Annotation.Child(child) => child
142-
}
142+
}.reverse
143143
}
144144

145145
def hasAnonymousChild(implicit ctx: Context): Boolean =

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,12 +499,31 @@ class Namer { typer: Typer =>
499499
vd.mods.is(JavaEnumValue) // && ownerHasEnumFlag
500500
}
501501

502+
/** Add child annotation for `child` to annotations of `cls`. The annotation
503+
* is added at the correct insertion point, so that Child annotations appear
504+
* in reverse order of their start positions.
505+
* @pre `child` must have a position.
506+
*/
507+
final def addChild(cls: Symbol, child: Symbol)(implicit ctx: Context): Unit = {
508+
val childStart = child.pos.start
509+
def insertInto(annots: List[Annotation]): List[Annotation] =
510+
annots.find(_.symbol == defn.ChildAnnot) match {
511+
case Some(Annotation.Child(other)) if childStart <= other.pos.start =>
512+
assert(childStart != other.pos.start, "duplicate child annotation $child / $other")
513+
val (prefix, otherAnnot :: rest) = annots.span(_.symbol != defn.ChildAnnot)
514+
prefix ::: otherAnnot :: insertInto(rest)
515+
case _ =>
516+
Annotation.Child(child) :: annots
517+
}
518+
cls.annotations = insertInto(cls.annotations)
519+
}
520+
502521
/** Add java enum constants */
503522
def addEnumConstants(mdef: DefTree, sym: Symbol)(implicit ctx: Context): Unit = mdef match {
504523
case vdef: ValDef if (isEnumConstant(vdef)) =>
505524
val enumClass = sym.owner.linkedClass
506525
if (!(enumClass is Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed)
507-
enumClass.addAnnotation(Annotation.Child(sym))
526+
addChild(enumClass, sym)
508527
case _ =>
509528
}
510529

@@ -814,9 +833,9 @@ class Namer { typer: Typer =>
814833
val cls = parent.classSymbol
815834
if (cls.is(Sealed)) {
816835
if ((child.isInaccessibleChildOf(cls) || child.isAnonymousClass) && !sym.hasAnonymousChild)
817-
cls.addAnnotation(Annotation.Child(cls))
836+
addChild(cls, cls)
818837
else if (!cls.is(ChildrenQueried))
819-
cls.addAnnotation(Annotation.Child(child))
838+
addChild(cls, child)
820839
else
821840
ctx.error(em"""children of ${cls} were already queried before $sym was discovered.
822841
|As a remedy, you could move $sym on the same nesting level as $cls.""",

library/src/scala/annotation/internal/Child.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import scala.annotation.Annotation
1010
* case class C() extends A
1111
*
1212
* Then the class symbol `A` would carry the annotations
13-
* `@Child[Bref] @Child[Cref]` where `Bref`, `Cref` are TypeRefs
14-
* referring to the class symbols of `B` and `C`
13+
* `@Child[Cref]`, @Child[Bref] where `Bref`, `Cref` are TypeRefs
14+
* referring to the class symbols of `B` and `C`.
15+
*
16+
* Child annotations always appear in reverse order of textual occurrence.
17+
* I.e. in the example above, it is guaranteed that the child annotation for `C`
18+
* appears before the one for `B`.
19+
*
1520
* TODO: This should be `Child[T <: AnyKind]`
1621
*/
1722
class Child[T] extends Annotation

0 commit comments

Comments
 (0)