@@ -648,21 +648,38 @@ object SpaceEngine {
648
648
// we get
649
649
// <== refineUsingParent(NatT, class Succ, []) = Succ[NatT]
650
650
// <== isSub(Succ[NatT] <:< Succ[Succ[<?>]]) = false
651
- def getAppliedClass (tp : Type ): Type = tp match
652
- case tp @ AppliedType (_ : HKTypeLambda , _) => tp
653
- case tp @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass => tp
651
+ def getAppliedClass (tp : Type ): ( Type , List [ Type ]) = tp match
652
+ case tp @ AppliedType (_ : HKTypeLambda , _) => (tp, Nil )
653
+ case tp @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass => (tp, tp.args)
654
654
case tp @ AppliedType (tycon : TypeProxy , _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
655
- case tp => tp
656
- val tp = getAppliedClass(tpOriginal)
657
- def getChildren (sym : Symbol ): List [Symbol ] =
655
+ case tp => (tp, Nil )
656
+ val (tp, typeArgs) = getAppliedClass(tpOriginal)
657
+ // This function is needed to get the arguments of the types that will be applied to the class.
658
+ // This is necessary because if the arguments of the types contain Nothing,
659
+ // then this can affect whether the class will be taken into account during the exhaustiveness check
660
+ def getTypeArgs (parent : Symbol , child : Symbol , typeArgs : List [Type ]): List [Type ] =
661
+ val superType = child.typeRef.superType
662
+ if typeArgs.exists(_.isBottomType) && superType.isInstanceOf [ClassInfo ] then
663
+ val parentClass = superType.asInstanceOf [ClassInfo ].declaredParents.find(_.classSymbol == parent).get
664
+ val paramTypeMap = Map .from(parentClass.argTypes.map(_.typeSymbol).zip(typeArgs))
665
+ val substArgs = child.typeRef.typeParamSymbols.map(param => paramTypeMap.getOrElse(param, WildcardType ))
666
+ substArgs
667
+ else Nil
668
+ def getChildren (sym : Symbol , typeArgs : List [Type ]): List [Symbol ] =
658
669
sym.children.flatMap { child =>
659
670
if child eq sym then List (sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...
660
671
else if tp.classSymbol == defn.TupleClass || tp.classSymbol == defn.NonEmptyTupleClass then
661
672
List (child) // TupleN and TupleXXL classes are used for Tuple, but they aren't Tuple's children
662
- else if (child.is(Private ) || child.is(Sealed )) && child.isOneOf(AbstractOrTrait ) then getChildren(child)
663
- else List (child)
673
+ else if (child.is(Private ) || child.is(Sealed )) && child.isOneOf(AbstractOrTrait ) then
674
+ getChildren(child, getTypeArgs(sym, child, typeArgs))
675
+ else
676
+ val childSubstTypes = child.typeRef.applyIfParameterized(getTypeArgs(sym, child, typeArgs))
677
+ // if a class contains a field of type Nothing,
678
+ // then it can be ignored in pattern matching, because it is impossible to obtain an instance of it
679
+ val existFieldWithBottomType = childSubstTypes.fields.exists(_.info.isBottomType)
680
+ if existFieldWithBottomType then Nil else List (child)
664
681
}
665
- val children = trace(i " getChildren( $tp) " )(getChildren(tp.classSymbol))
682
+ val children = trace(i " getChildren( $tp) " )(getChildren(tp.classSymbol, typeArgs ))
666
683
667
684
val parts = children.map { sym =>
668
685
val sym1 = if (sym.is(ModuleClass )) sym.sourceModule else sym
0 commit comments