Skip to content

Commit 0eea749

Browse files
committed
Unwiden scrutinee types, fixing match analysis
1 parent 17141e8 commit 0eea749

File tree

4 files changed

+53
-10
lines changed

4 files changed

+53
-10
lines changed

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

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -502,12 +502,13 @@ class SpaceEngine(using Context) extends SpaceLogic {
502502

503503
/** Is `tp1` a subtype of `tp2`? */
504504
def isSubType(tp1: Type, tp2: Type): Boolean = {
505-
debug.println(TypeComparer.explained(_.isSubType(tp1, tp2)))
505+
//debug.println(TypeComparer.explained(_.isSubType(tp1, tp2)))
506506
val res = if (ctx.explicitNulls) {
507507
tp1 <:< tp2
508508
} else {
509509
(tp1 != constantNullType || tp2 == constantNullType) && tp1 <:< tp2
510510
}
511+
debug.println(i"$tp1 <:< $tp2 = $res")
511512
res
512513
}
513514

@@ -663,7 +664,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
663664
|| cls.isAllOf(JavaEnumTrait)
664665
|| tp.isRef(defn.BooleanClass)
665666
|| tp.isRef(defn.UnitClass)
666-
debug.println(s"decomposable: ${tp.show} = $res")
667+
//debug.println(s"decomposable: ${tp.show} = $res")
667668
res
668669

669670
/** Show friendly type name with current scope in mind
@@ -838,14 +839,26 @@ class SpaceEngine(using Context) extends SpaceLogic {
838839
}
839840
}.apply(false, tp)
840841

842+
/** Return the underlying type of non-module, non-constant, non-enum case singleton types.
843+
* Also widen ExprType to its result type.
844+
* For example, with `val opt = None`, widen `opt.type` to `None.type`. */
845+
def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp)", show = true)(tp match {
846+
case _: ConstantType => tp
847+
case tp: TermRef if tp.symbol.is(Module) => tp
848+
case tp: TermRef if tp.symbol.isAllOf(EnumCase) => tp
849+
case tp: SingletonType => toUnderlying(tp.underlying)
850+
case tp: ExprType => toUnderlying(tp.resultType)
851+
case _ => tp
852+
})
853+
841854
def checkExhaustivity(_match: Match): Unit = {
842855
val Match(sel, cases) = _match
843-
val selTyp = sel.tpe.widen.dealias
856+
debug.println(i"checking exhaustivity of ${_match}")
844857

845858
if (!exhaustivityCheckable(sel)) return
846859

847-
debug.println("checking " + _match.show)
848-
debug.println("selTyp = " + selTyp.show)
860+
val selTyp = toUnderlying(sel.tpe).dealias
861+
debug.println(i"selTyp = $selTyp")
849862

850863
val patternSpace = Or(cases.foldLeft(List.empty[Space]) { (acc, x) =>
851864
val space = if (x.guard.isEmpty) project(x.pat) else Empty
@@ -878,13 +891,14 @@ class SpaceEngine(using Context) extends SpaceLogic {
878891
&& !sel.tpe.widen.isRef(defn.QuotedTypeClass)
879892

880893
def checkRedundancy(_match: Match): Unit = {
881-
debug.println(s"---------------checking redundant patterns ${_match.show}")
882-
883894
val Match(sel, cases) = _match
884-
val selTyp = sel.tpe.widen.dealias
895+
debug.println(i"checking redundancy in $_match")
885896

886897
if (!redundancyCheckable(sel)) return
887898

899+
val selTyp = toUnderlying(sel.tpe).dealias
900+
debug.println(i"selTyp = $selTyp")
901+
888902
val targetSpace =
889903
if !selTyp.classSymbol.isNullableClass then
890904
project(selTyp)
@@ -897,7 +911,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
897911
if (x.guard.isEmpty) project(x.pat)
898912
else Empty
899913

900-
debug.println(s"${x.pat.show} ====> ${res}")
914+
debug.println(s"${x.pat.show} ====> ${show(res)}")
901915
res
902916
}
903917

@@ -912,7 +926,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
912926
debug.println(s"prev: ${show(prevs)}")
913927

914928
var covered = simplify(intersect(curr, targetSpace))
915-
debug.println(s"covered: $covered")
929+
debug.println(s"covered: ${show(covered)}")
916930

917931
// `covered == Empty` may happen for primitive types with auto-conversion
918932
// see tests/patmat/reader.scala tests/patmat/byte.scala

tests/patmat/i13342-testing.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
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.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)