Skip to content

Commit 5ffdaf8

Browse files
committed
Unwiden scrutinee types, fixing match analysis
1 parent 7d1cddb commit 5ffdaf8

File tree

6 files changed

+55
-7
lines changed

6 files changed

+55
-7
lines changed

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

+20-6
Original file line numberDiff line numberDiff line change
@@ -858,14 +858,27 @@ class SpaceEngine(using Context) extends SpaceLogic {
858858
}
859859
}.apply(false, tp)
860860

861+
/** Return the underlying type of non-module, non-constant, non-enum case singleton types.
862+
* Also widen ExprType to its result type, and rewrap any annotation wrappers.
863+
* For example, with `val opt = None`, widen `opt.type` to `None.type`. */
864+
def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp)", show = true)(tp match {
865+
case _: ConstantType => tp
866+
case tp: TermRef if tp.symbol.is(Module) => tp
867+
case tp: TermRef if tp.symbol.isAllOf(EnumCase) => tp
868+
case tp: SingletonType => toUnderlying(tp.underlying)
869+
case tp: ExprType => toUnderlying(tp.resultType)
870+
case AnnotatedType(tp, annot) => AnnotatedType(toUnderlying(tp), annot)
871+
case _ => tp
872+
})
873+
861874
def checkExhaustivity(_match: Match): Unit = {
862875
val Match(sel, cases) = _match
863-
val selTyp = sel.tpe.widen.dealias
876+
debug.println(i"checking exhaustivity of ${_match}")
864877

865878
if (!exhaustivityCheckable(sel)) return
866879

867-
debug.println("checking " + _match.show)
868-
debug.println("selTyp = " + selTyp.show)
880+
val selTyp = toUnderlying(sel.tpe).dealias
881+
debug.println(i"selTyp = $selTyp")
869882

870883
val patternSpace = Or(cases.foldLeft(List.empty[Space]) { (acc, x) =>
871884
val space = if (x.guard.isEmpty) project(x.pat) else Empty
@@ -898,13 +911,14 @@ class SpaceEngine(using Context) extends SpaceLogic {
898911
&& !sel.tpe.widen.isRef(defn.QuotedTypeClass)
899912

900913
def checkRedundancy(_match: Match): Unit = {
901-
debug.println(s"---------------checking redundant patterns ${_match.show}")
902-
903914
val Match(sel, cases) = _match
904-
val selTyp = sel.tpe.widen.dealias
915+
debug.println(i"checking redundancy in $_match")
905916

906917
if (!redundancyCheckable(sel)) return
907918

919+
val selTyp = toUnderlying(sel.tpe).dealias
920+
debug.println(i"selTyp = $selTyp")
921+
908922
val isNullable = selTyp.classSymbol.isNullableClass
909923
val targetSpace = if isNullable
910924
then project(OrType(selTyp, constantNullType, soft = false))

tests/patmat/i13342-testing.check

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
13: Match case Unreachable
2+
13: Match case Unreachable
3+
14: Match case Unreachable
4+
14: Match case Unreachable
5+
15: Pattern Match Exhaustivity: Thu, Fri

tests/patmat/i13342-testing.scala

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class C {
2+
val bool: true = true
3+
val not1: None.type = None
4+
5+
def t1 = true match { case true => "inline true" }
6+
def t2 = bool match { case true => "valdef true" }
7+
def t3 = None match { case None => "inline None" }
8+
def t4 = not1 match { case None => "valdef None" }
9+
10+
val monday: Day.Mon.type = Day.Mon
11+
val someday: Day = Day.Mon
12+
13+
def t5 = Day.Mon match { case Day.Mon => 1 case Day.Tue => 2 case Day.Wed => 3 }
14+
def t6 = monday match { case Day.Mon => 1 case Day.Tue => 2 case Day.Wed => 3 }
15+
def t7 = someday match { case Day.Mon => 1 case Day.Tue => 2 case Day.Wed => 3 }
16+
}
17+
18+
enum Day { case Mon, Tue, Wed, Thu, Fri }

tests/patmat/i13342.check

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
8: Match case Unreachable

tests/patmat/i13342.scala

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class C {
2+
def m(x: true) = x match { // was: match may not be exhaustive.\nIt would fail on pattern case: false
3+
case true => println("the one true path")
4+
}
5+
6+
def n(x: true) = x match {
7+
case true => 1
8+
case false => 2 // was: no reachability warning on this case
9+
}
10+
}

tests/pos-special/fatal-warnings/i3589b.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Test {
2-
def test(x: 1) = (x: @annotation.switch) match {
2+
def test(x: 1 | 2 | 3) = (x: @annotation.switch) match {
33
case 1 => 1
44
case 2 => 2
55
case 3 => 3

0 commit comments

Comments
 (0)