Skip to content

Commit e9cdb0b

Browse files
committed
Revert "constructor not uninhabited, if field with bottom type is lazy"
This reverts commit 533f6a7.
1 parent e81801f commit e9cdb0b

File tree

4 files changed

+28
-47
lines changed

4 files changed

+28
-47
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -642,37 +642,49 @@ object SpaceEngine {
642642
// we get
643643
// <== refineUsingParent(NatT, class Succ, []) = Succ[NatT]
644644
// <== isSub(Succ[NatT] <:< Succ[Succ[<?>]]) = false
645-
def getAppliedClass(tp: Type): Type = tp match
646-
case tp @ AppliedType(_: HKTypeLambda, _) => tp
647-
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass => tp
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)
648648
case tp @ AppliedType(tycon: TypeProxy, _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
649-
case tp => tp
650-
val tp = getAppliedClass(tpOriginal)
651-
def getChildren(sym: Symbol): List[Symbol] =
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.argInfos.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] =
652663
sym.children.flatMap { child =>
653664
if child eq sym then List(sym) // i3145: sealed trait Baz, val x = new Baz {}, Baz.children returns Baz...
654665
else if tp.classSymbol == defn.TupleClass || tp.classSymbol == defn.NonEmptyTupleClass then
655666
List(child) // TupleN and TupleXXL classes are used for Tuple, but they aren't Tuple's children
656-
else if (child.is(Private) || child.is(Sealed)) && child.isOneOf(AbstractOrTrait) then getChildren(child)
657-
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)
658675
}
659-
val children = trace(i"getChildren($tp)")(getChildren(tp.classSymbol))
676+
val children = trace(i"getChildren($tp)")(getChildren(tp.classSymbol, typeArgs))
660677

661678
val parts = children.map { sym =>
662679
val sym1 = if (sym.is(ModuleClass)) sym.sourceModule else sym
663680
val refined = trace(i"refineUsingParent($tp, $sym1, $mixins)")(TypeOps.refineUsingParent(tp, sym1, mixins))
664681

665-
def containsUninhabitedField(tp: Type): Boolean =
666-
tp.fields.exists { field =>
667-
!field.symbol.flags.is(Lazy) && field.info.dealias.isBottomType
668-
}
669-
670682
def inhabited(tp: Type): Boolean = tp.dealias match
671683
case AndType(tp1, tp2) => !TypeComparer.provablyDisjoint(tp1, tp2)
672684
case OrType(tp1, tp2) => inhabited(tp1) || inhabited(tp2)
673685
case tp: RefinedType => inhabited(tp.parent)
674-
case tp: TypeRef => !containsUninhabitedField(tp) && inhabited(tp.prefix)
675-
case _ => !containsUninhabitedField(tp)
686+
case tp: TypeRef => inhabited(tp.prefix)
687+
case _ => true
676688

677689
if inhabited(refined) then refined
678690
else NoType

tests/warn/patmat-lazy-nothing-not-exhaustive.check

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/warn/patmat-lazy-nothing-not-exhaustive.scala

Lines changed: 0 additions & 12 deletions
This file was deleted.

tests/warn/patmat-type-member-nothing-exhaustive.scala

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)