Skip to content

Commit decf07b

Browse files
committed
Apply review feedback: use NonStaleChild extractor
Add a `NonStaleChild` extractor in `Annotations` that wraps `Child` with a `StaleSymbol` catch, and use it in `Namer.addChild` so the surrounding logic stays untouched. [Cherry-picked 05d29fd][modified]
1 parent 0c5c2cc commit decf07b

2 files changed

Lines changed: 18 additions & 25 deletions

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,16 @@ object Annotations {
254254

255255
def makeSourceFile(path: String, span: Span)(using Context): Annotation =
256256
apply(defn.SourceFileAnnot, Literal(Constant(path)), span)
257+
/** Like `Child`, but yields `None` instead of throwing `StaleSymbol` when
258+
* the annotation refers to a child symbol from a previous run that is no
259+
* longer valid (e.g. after compilation was suspended and the child class
260+
* has been re-typechecked in the current run; see tests/pos/i24414).
261+
*/
262+
object NonStaleChild {
263+
def unapply(ann: Annotation)(using Context): Option[Symbol] =
264+
try Child.unapply(ann)
265+
catch case _: Denotations.StaleSymbol => None
266+
}
257267
}
258268

259269
@sharable val EmptyAnnotation = Annotation(EmptyTree)

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

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -479,34 +479,17 @@ class Namer { typer: Typer =>
479479
// to just prepending the new Child annotation.
480480
def isReady(ann: Annotation): Boolean =
481481
ann.symbol == defn.ChildAnnot && !ann.isEvaluating
482-
// Forcing a Child annotation may throw `StaleSymbol` if it refers to a
483-
// symbol from a previous run that is no longer valid. This happens when
484-
// compilation was suspended and the child class is re-typechecked in the
485-
// current run, leaving an outdated Child annotation on the parent (see
486-
// tests/pos/i24414). Treat such annotations as stale and drop them.
487-
def childOf(ann: Annotation): Option[Symbol] =
488-
try Annotation.Child.unapply(ann)
489-
catch case _: StaleSymbol => None
490482
def insertInto(annots: List[Annotation]): List[Annotation] =
491483
annots.find(isReady) match {
492-
case Some(ann) =>
493-
childOf(ann) match {
494-
case Some(other) if other.span.exists && childStart <= other.span.start =>
495-
if (child == other)
496-
annots // can happen if a class has several inaccessible children
497-
else {
498-
assert(childStart != other.span.start || child.source != other.source, i"duplicate child annotation $child / $other")
499-
val (prefix, otherAnnot :: rest) = annots.span(a => (a ne ann)): @unchecked
500-
prefix ::: otherAnnot :: insertInto(rest)
501-
}
502-
case None =>
503-
// Drop the stale Child annotation and continue searching.
504-
val (prefix, rest) = annots.span(a => (a ne ann))
505-
prefix ::: insertInto(rest.tail)
506-
case _ =>
507-
Annotation.Child(child, cls.span.startPos) :: annots
484+
case Some(Annotation.NonStaleChild(other)) if other.span.exists && childStart <= other.span.start =>
485+
if (child == other)
486+
annots // can happen if a class has several inaccessible children
487+
else {
488+
assert(childStart != other.span.start || child.source != other.source, i"duplicate child annotation $child / $other")
489+
val (prefix, otherAnnot :: rest) = annots.span(ann => !isReady(ann)): @unchecked
490+
prefix ::: otherAnnot :: insertInto(rest)
508491
}
509-
case None =>
492+
case _ =>
510493
Annotation.Child(child, cls.span.startPos) :: annots
511494
}
512495
cls.annotations = insertInto(cls.annotations)

0 commit comments

Comments
 (0)