Skip to content

Commit c25c4e1

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

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -858,14 +858,26 @@ 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.
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 _ => tp
871+
})
872+
861873
def checkExhaustivity(_match: Match): Unit = {
862874
val Match(sel, cases) = _match
863-
val selTyp = sel.tpe.widen.dealias
875+
debug.println(i"checking exhaustivity of ${_match}")
864876

865877
if (!exhaustivityCheckable(sel)) return
866878

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

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

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

906916
if (!redundancyCheckable(sel)) return
907917

918+
val selTyp = toUnderlying(sel.tpe).dealias
919+
debug.println(i"selTyp = $selTyp")
920+
908921
val isNullable = selTyp.classSymbol.isNullableClass
909922
val targetSpace = if isNullable
910923
then project(OrType(selTyp, constantNullType, soft = false))

tests/patmat/i13342-testing.check

Lines changed: 5 additions & 0 deletions
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

Lines changed: 18 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
8: Match case Unreachable

tests/patmat/i13342.scala

Lines changed: 10 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)