@@ -625,16 +625,55 @@ object SpaceEngine {
625
625
// For instance, from i15029, `decompose((X | Y).Field[T]) = [X.Field[T], Y.Field[T]]`.
626
626
parts.map(tp.derivedAppliedType(_, targs))
627
627
628
- case tp if tp.isDecomposableToChildren =>
629
- def getChildren (sym : Symbol ): List [Symbol ] =
628
+ case tpOriginal if tpOriginal.isDecomposableToChildren =>
629
+ // isDecomposableToChildren uses .classSymbol.is(Sealed)
630
+ // But that classSymbol could be from an AppliedType
631
+ // where the type constructor is a non-class type
632
+ // E.g. t11620 where `?1.AA[X]` returns as "sealed"
633
+ // but using that we're not going to infer A1[X] and A2[X]
634
+ // but end up with A1[<?>] and A2[<?>].
635
+ // So we widen (like AppliedType superType does) away
636
+ // non-class type constructors.
637
+ //
638
+ // Can't use `tpOriginal.baseType(cls)` because it causes
639
+ // i15893 to return exhaustivity warnings, because instead of:
640
+ // <== refineUsingParent(N, class Succ, []) = Succ[<? <: NatT>]
641
+ // <== isSub(Succ[<? <: NatT>] <:< Succ[Succ[<?>]]) = true
642
+ // we get
643
+ // <== refineUsingParent(NatT, class Succ, []) = Succ[NatT]
644
+ // <== isSub(Succ[NatT] <:< Succ[Succ[<?>]]) = false
645
+ def getAppliedClass (tp : Type ): (Type , List [Type ]) = tp match
646
+ case tp @ AppliedType (_ : HKTypeLambda , _) => (tp, Nil )
647
+ case tp @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass => (tp, tp.args)
648
+ case tp @ AppliedType (tycon : TypeProxy , _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
649
+ case tp => (tp, Nil )
650
+ val (tp, typeArgs) = getAppliedClass(tpOriginal)
651
+ // This function is needed to get the arguments of the types that will be applied to the class.
652
+ // This is necessary because if the arguments of the types contain Nothing,
653
+ // then this can affect whether the class will be taken into account during the exhaustiveness check
654
+ def getTypeArgs (parent : Symbol , child : Symbol , typeArgs : List [Type ]): List [Type ] =
655
+ val superType = child.typeRef.superType
656
+ if typeArgs.exists(_.isBottomType) && superType.isInstanceOf [ClassInfo ] then
657
+ val parentClass = superType.asInstanceOf [ClassInfo ].declaredParents.find(_.classSymbol == parent).get
658
+ val paramTypeMap = Map .from(parentClass.argTypes.map(_.typeSymbol).zip(typeArgs))
659
+ val substArgs = child.typeRef.typeParamSymbols.map(param => paramTypeMap.getOrElse(param, WildcardType ))
660
+ substArgs
661
+ else Nil
662
+ def getChildren (sym : Symbol , typeArgs : List [Type ]): List [Symbol ] =
630
663
sym.children.flatMap { child =>
631
664
if child eq sym then List (sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...
632
665
else if tp.classSymbol == defn.TupleClass || tp.classSymbol == defn.NonEmptyTupleClass then
633
666
List (child) // TupleN and TupleXXL classes are used for Tuple, but they aren't Tuple's children
634
- else if (child.is(Private ) || child.is(Sealed )) && child.isOneOf(AbstractOrTrait ) then getChildren(child)
635
- else List (child)
667
+ else if (child.is(Private ) || child.is(Sealed )) && child.isOneOf(AbstractOrTrait ) then
668
+ getChildren(child, getTypeArgs(sym, child, typeArgs))
669
+ else
670
+ val childSubstTypes = child.typeRef.applyIfParameterized(getTypeArgs(sym, child, typeArgs))
671
+ // if a class contains a field of type Nothing,
672
+ // then it can be ignored in pattern matching, because it is impossible to obtain an instance of it
673
+ val existFieldWithBottomType = childSubstTypes.fields.exists(_.info.isBottomType)
674
+ if existFieldWithBottomType then Nil else List (child)
636
675
}
637
- val children = trace(i " getChildren( $tp) " )(getChildren(tp.classSymbol))
676
+ val children = trace(i " getChildren( $tp) " )(getChildren(tp.classSymbol, typeArgs ))
638
677
639
678
val parts = children.map { sym =>
640
679
val sym1 = if (sym.is(ModuleClass )) sym.sourceModule else sym
0 commit comments