@@ -630,13 +630,7 @@ object SpaceEngine {
630
630
// For instance, from i15029, `decompose((X | Y).Field[T]) = [X.Field[T], Y.Field[T]]`.
631
631
parts.map(tp.derivedAppliedType(_, targs))
632
632
633
- case tp if {
634
- val cls = tp.classSymbol
635
- cls.is(Sealed )
636
- && cls.isOneOf(AbstractOrTrait )
637
- && ! cls.hasAnonymousChild
638
- && cls.children.nonEmpty
639
- } =>
633
+ case tp if tp.classSymbol.isDecomposableToChildren =>
640
634
def getChildren (sym : Symbol ): List [Symbol ] =
641
635
sym.children.flatMap { child =>
642
636
if child eq sym then List (sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...
@@ -672,6 +666,18 @@ object SpaceEngine {
672
666
rec(tp, Nil )
673
667
}
674
668
669
+ extension (cls : Symbol )
670
+ /** A type is decomposable to children if it's sealed,
671
+ * abstract (or a trait) - so its not a sealed concrete class that can be instantiated on its own,
672
+ * has no anonymous children, which we wouldn't be able to name as counter-examples,
673
+ * but does have children.
674
+ *
675
+ * A sealed trait with no subclasses is considered not decomposable and thus is treated as an opaque type.
676
+ * A sealed trait with subclasses that then get removed after `refineUsingParent`, decomposes to the empty list.
677
+ * So that's why we consider whether a type has children. */
678
+ def isDecomposableToChildren (using Context ): Boolean =
679
+ cls.is(Sealed ) && cls.isOneOf(AbstractOrTrait ) && ! cls.hasAnonymousChild && cls.children.nonEmpty
680
+
675
681
val ListOfNoType = List (NoType )
676
682
val ListOfTypNoType = ListOfNoType .map(Typ (_, decomposed = true ))
677
683
0 commit comments