Skip to content

Commit adc55d7

Browse files
committed
Fix inaccessibility criterion
It turns out we have to know a priori whether we should register a local class as a child and we need to be precise about it.
1 parent 80e50c9 commit adc55d7

File tree

3 files changed

+17
-9
lines changed

3 files changed

+17
-9
lines changed

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -570,12 +570,11 @@ class TreePickler(pickler: TastyPickler) {
570570
if (flags is Covariant) writeByte(COVARIANT)
571571
if (flags is Contravariant) writeByte(CONTRAVARIANT)
572572
}
573-
sym.annotations.foreach(pickleAnnotation)
573+
sym.annotations.foreach(pickleAnnotation(sym, _))
574574
}
575575

576-
private def isUnpicklable(ann: Annotation)(implicit ctx: Context) = ann match {
577-
case Annotation.Child(sym) =>
578-
sym.isLocal && ctx.owner.topLevelClass != sym.topLevelClass
576+
private def isUnpicklable(owner: Symbol, ann: Annotation)(implicit ctx: Context) = ann match {
577+
case Annotation.Child(sym) => sym.isInaccessibleChildOf(owner)
579578
// If child annotation refers to a local class or enum value under
580579
// a different toplevel class, it is impossible to pickle a reference to it.
581580
// Such annotations will be reconstituted when unpickling the child class.
@@ -584,8 +583,8 @@ class TreePickler(pickler: TastyPickler) {
584583
// inline bodies are reconstituted automatically when unpickling
585584
}
586585

587-
def pickleAnnotation(ann: Annotation)(implicit ctx: Context) =
588-
if (!isUnpicklable(ann)) {
586+
def pickleAnnotation(owner: Symbol, ann: Annotation)(implicit ctx: Context) =
587+
if (!isUnpicklable(owner, ann)) {
589588
writeByte(ANNOTATION)
590589
withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) }
591590
}

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
705705
if ((sym.isClass || sym.is(CaseVal)) && sym.isLocal)
706706
// Child annotations for local classes and enum values are not pickled, so
707707
// need to be re-established here.
708-
sym.registerIfChild()
708+
sym.registerIfChild(late = true)
709709
tree
710710
}
711711

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,13 @@ class SymUtils(val self: Symbol) extends AnyVal {
137137

138138
/** If this symbol is an enum value or a named class, register it as a child
139139
* in all direct parent classes which are sealed.
140+
* @param @late If true, register only inaccessible children (all others are already
141+
* entered at this point).
140142
*/
141-
def registerIfChild()(implicit ctx: Context): Unit = {
143+
def registerIfChild(late: Boolean = false)(implicit ctx: Context): Unit = {
142144
def register(child: Symbol, parent: Type) = {
143145
val cls = parent.classSymbol
144-
if (cls.is(Sealed) && !cls.children.contains(child))
146+
if (cls.is(Sealed) && (!late || child.isInaccessibleChildOf(cls)))
145147
cls.addAnnotation(Annotation.Child(child))
146148
}
147149
if (self.isClass && !self.isAnonymousClass)
@@ -153,6 +155,13 @@ class SymUtils(val self: Symbol) extends AnyVal {
153155
register(self, self.info)
154156
}
155157

158+
/** Is this symbol defined locally (i.e. at some level owned by a term) and
159+
* defined in a different toplevel class than its supposed parent class `cls`?
160+
* Such children are not pickled, and have to be reconstituted manually.
161+
*/
162+
def isInaccessibleChildOf(cls: Symbol)(implicit ctx: Context) =
163+
self.isLocal && !cls.topLevelClass.isLinkedWith(self.topLevelClass)
164+
156165
/** If this is a sealed class, its known children */
157166
def children(implicit ctx: Context): List[Symbol] =
158167
self.annotations.collect {

0 commit comments

Comments
 (0)