Skip to content

Commit b61af65

Browse files
committed
Do not consider uninhabited constructors when performing exhaustive match checking
1 parent 6fa81cf commit b61af65

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

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

+11-2
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,13 @@ object SpaceEngine {
649649
// <== refineUsingParent(NatT, class Succ, []) = Succ[NatT]
650650
// <== isSub(Succ[NatT] <:< Succ[Succ[<?>]]) = false
651651
def getAppliedClass(tp: Type): Type = tp match
652+
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass =>
653+
// apply arguments if they contain Nothing,
654+
// because it may affect further selection of children of the class
655+
val argsNotContainsNothing = tp.args.forall(_.classSymbol != defn.NothingClass)
656+
if argsNotContainsNothing then tp
657+
else getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
652658
case tp @ AppliedType(_: HKTypeLambda, _) => tp
653-
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass => tp
654659
case tp @ AppliedType(tycon: TypeProxy, _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
655660
case tp => tp
656661
val tp = getAppliedClass(tpOriginal)
@@ -660,7 +665,11 @@ object SpaceEngine {
660665
else if tp.classSymbol == defn.TupleClass || tp.classSymbol == defn.NonEmptyTupleClass then
661666
List(child) // TupleN and TupleXXL classes are used for Tuple, but they aren't Tuple's children
662667
else if (child.is(Private) || child.is(Sealed)) && child.isOneOf(AbstractOrTrait) then getChildren(child)
663-
else List(child)
668+
else
669+
// if a class contains a field of type Nothing,
670+
// then it can be ignored in pattern matching, because it is impossible to obtain an instance of it
671+
val noFieldsWithTypeNothing = child.typeRef.fields.forall(_.symbol.typeRef.classSymbol != defn.NothingClass)
672+
if noFieldsWithTypeNothing then List(child) else Nil
664673
}
665674
val children = trace(i"getChildren($tp)")(getChildren(tp.classSymbol))
666675

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//> using options -Xfatal-warnings -deprecation -feature
2+
3+
enum TestAdt:
4+
case Inhabited
5+
case Uninhabited(no: Nothing)
6+
7+
def test1(t: TestAdt): Int = t match
8+
case TestAdt.Inhabited => 1
9+
10+
def test2(o: Option[Option[Nothing]]): Int = o match
11+
case Some(None) => 1
12+
case None => 2

0 commit comments

Comments
 (0)