Skip to content

Commit

Permalink
Do not consider uninhabited constructors when performing exhaustive m…
Browse files Browse the repository at this point in the history
…atch checking
  • Loading branch information
Alex1005a committed Oct 10, 2024
1 parent 6fa81cf commit b61af65
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 2 deletions.
13 changes: 11 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -649,8 +649,13 @@ object SpaceEngine {
// <== refineUsingParent(NatT, class Succ, []) = Succ[NatT]
// <== isSub(Succ[NatT] <:< Succ[Succ[<?>]]) = false
def getAppliedClass(tp: Type): Type = tp match
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass =>
// apply arguments if they contain Nothing,
// because it may affect further selection of children of the class
val argsNotContainsNothing = tp.args.forall(_.classSymbol != defn.NothingClass)
if argsNotContainsNothing then tp
else getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
case tp @ AppliedType(_: HKTypeLambda, _) => tp
case tp @ AppliedType(tycon: TypeRef, _) if tycon.symbol.isClass => tp
case tp @ AppliedType(tycon: TypeProxy, _) => getAppliedClass(tycon.superType.applyIfParameterized(tp.args))
case tp => tp
val tp = getAppliedClass(tpOriginal)
Expand All @@ -660,7 +665,11 @@ object SpaceEngine {
else if tp.classSymbol == defn.TupleClass || tp.classSymbol == defn.NonEmptyTupleClass then
List(child) // TupleN and TupleXXL classes are used for Tuple, but they aren't Tuple's children
else if (child.is(Private) || child.is(Sealed)) && child.isOneOf(AbstractOrTrait) then getChildren(child)
else List(child)
else
// if a class contains a field of type Nothing,
// then it can be ignored in pattern matching, because it is impossible to obtain an instance of it
val noFieldsWithTypeNothing = child.typeRef.fields.forall(_.symbol.typeRef.classSymbol != defn.NothingClass)
if noFieldsWithTypeNothing then List(child) else Nil
}
val children = trace(i"getChildren($tp)")(getChildren(tp.classSymbol))

Expand Down
12 changes: 12 additions & 0 deletions tests/pos/patmat-nothing-exhaustive.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//> using options -Xfatal-warnings -deprecation -feature

enum TestAdt:
case Inhabited
case Uninhabited(no: Nothing)

def test1(t: TestAdt): Int = t match
case TestAdt.Inhabited => 1

def test2(o: Option[Option[Nothing]]): Int = o match
case Some(None) => 1
case None => 2

0 comments on commit b61af65

Please sign in to comment.