Skip to content

Commit fd1b286

Browse files
committed
fix false warning about Nil
scala.Nil refines scala.collection.immutable.Nil, this commit follows redefinition of case objects.
1 parent 9a0952c commit fd1b286

File tree

12 files changed

+172
-27
lines changed

12 files changed

+172
-27
lines changed

src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,11 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {thisTrans
5151
private var _id = 0 // left for debuging
5252

5353
override def transformMatch(tree: Match)(implicit ctx: Context, info: TransformerInfo): Tree = {
54-
val Match(sel, cases) = tree
55-
5654
val translated = new Translator()(ctx).translator.translateMatch(tree)
5755

5856
// check exhaustivity and unreachability
5957
val engine = new SpaceEngine
60-
if (engine.checkable(sel.tpe.widen.elimAnonymousClass)) {
58+
if (engine.checkable(tree)) {
6159
engine.checkExhaustivity(tree)
6260
engine.checkRedundancy(tree)
6361
}

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

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ trait SpaceLogic {
116116
ss.exists(subspace(a, _)) ||
117117
(canDecompose(tp1) && subspace(Or(partitions(tp1)), b))
118118
case (Typ(tp1, _), Kon(tp2, ss)) =>
119-
isSubType(tp1, tp2) && subspace(Kon(tp2, signature(tp2).map(tp => Typ(tp, false))), b)
119+
isSubType(tp1, tp2) && subspace(Kon(tp2, signature(tp2).map(Typ(_, false))), b)
120120
case (Kon(tp1, ss), Typ(tp2, _)) =>
121121
isSubType(tp1, tp2) ||
122122
simplify(a) == Empty ||
@@ -188,7 +188,7 @@ trait SpaceLogic {
188188
minus(Or(partitions(tp1)), b)
189189
else a
190190
case (Typ(tp1, _), Kon(tp2, ss)) =>
191-
if (isSubType(tp1, tp2)) minus(Kon(tp2, signature(tp2).map(tp => Typ(tp, false))), b)
191+
if (isSubType(tp1, tp2)) minus(Kon(tp2, signature(tp2).map(Typ(_, false))), b)
192192
else if (isSubType(tp2, tp1) && canDecompose(tp1))
193193
minus(Or(partitions(tp1)), b)
194194
else a
@@ -242,15 +242,17 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
242242
def project(pat: Tree, roundUp: Boolean = true)(implicit ctx: Context): Space = pat match {
243243
case Literal(c) => Const(c, c.tpe)
244244
case _: BackquotedIdent => Var(pat.symbol, pat.tpe)
245-
case Ident(_) =>
246-
Typ(pat.tpe.stripAnnots, false)
247-
case Select(_, _) =>
248-
if (pat.symbol.is(Module))
249-
Typ(pat.tpe.stripAnnots, false)
250-
else if (pat.symbol.is(Enum))
251-
Const(Constant(pat.symbol), pat.tpe)
252-
else
253-
Var(pat.symbol, pat.tpe)
245+
case Ident(_) | Select(_, _) =>
246+
pat.tpe.stripAnnots match {
247+
case tp: TermRef =>
248+
if (pat.symbol.is(Enum))
249+
Const(Constant(pat.symbol), tp)
250+
else if (tp.underlyingIterator.exists(_.classSymbol.is(Module)))
251+
Typ(tp.widenTermRefExpr.stripAnnots, false)
252+
else
253+
Var(pat.symbol, tp)
254+
case tp => Typ(tp, false)
255+
}
254256
case Alternative(trees) => Or(trees.map(project(_, roundUp)))
255257
case Bind(_, pat) => project(pat)
256258
case UnApply(_, _, pats) =>
@@ -295,6 +297,7 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
295297
ktor
296298
}
297299

300+
// refine path-dependent type in params. refer to t9672
298301
meth.firstParamTypes.map(_.stripTypeVar).map(refine(tp, _))
299302
}
300303

@@ -415,37 +418,42 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
415418
if (mergeList) "_" else "List(_)"
416419
else if (tp.classSymbol.is(CaseClass))
417420
// use constructor syntax for case class
418-
showType(tp) + signature(tp).map(_ => "_").mkString("(", ",", ")")
421+
showType(tp) + signature(tp).map(_ => "_").mkString("(", ", ", ")")
419422
else if (signature(tp).nonEmpty)
420-
tp.classSymbol.name + signature(tp).map(_ => "_").mkString("(", ",", ")")
423+
tp.classSymbol.name + signature(tp).map(_ => "_").mkString("(", ", ", ")")
421424
else if (decomposed) "_: " + showType(tp)
422425
else "_"
423426
case Kon(tp, params) =>
424427
if (ctx.definitions.isTupleType(tp))
425-
"(" + params.map(p => doShow(p)).mkString(", ") + ")"
428+
"(" + params.map(doShow(_)).mkString(", ") + ")"
426429
else if (tp.widen.classSymbol.showFullName == "scala.collection.immutable.::")
427-
if (mergeList) params.map(p => doShow(p, mergeList)).mkString(", ")
428-
else params.map(p => doShow(p, true)).mkString("List(", ", ", ")")
430+
if (mergeList) params.map(doShow(_, mergeList)).mkString(", ")
431+
else params.map(doShow(_, true)).filter(_ != "Nil").mkString("List(", ", ", ")")
429432
else
430-
showType(tp) + params.map(p => doShow(p)).mkString("(", ", ", ")")
433+
showType(tp) + params.map(doShow(_)).mkString("(", ", ", ")")
431434
case Or(_) =>
432435
throw new Exception("incorrect flatten result " + s)
433436
}
434437

435438
flatten(s).map(doShow(_, false)).distinct.mkString(", ")
436439
}
437440

438-
def checkable(tp: Type): Boolean = tp match {
439-
case AnnotatedType(tp, annot) =>
440-
(ctx.definitions.UncheckedAnnot != annot.symbol) && checkable(tp)
441-
case _ => true // actually everything is checkable unless @unchecked
441+
def checkable(tree: Match): Boolean = {
442+
def isCheckable(tp: Type): Boolean = tp match {
443+
case AnnotatedType(tp, annot) =>
444+
(ctx.definitions.UncheckedAnnot != annot.symbol) && isCheckable(tp)
445+
case _ => true // actually everything is checkable unless @unchecked
442446

443447
// tp.classSymbol.is(Sealed) ||
444448
// tp.isInstanceOf[OrType] ||
445449
// tp.classSymbol.is(Enum) ||
446450
// Boolean
447451
// Int
448452
// ...
453+
}
454+
455+
val Match(sel, cases) = tree
456+
isCheckable(sel.tpe.widen.elimAnonymousClass)
449457
}
450458

451459
def checkExhaustivity(_match: Match): Unit = {

tests/patmat/enum/expected.check

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
It would fail on the following input: SATURDAY, FRIDAY, THURSDAY, SUNDAY
33
day match {
44
^
5-
one warning found
5+
./tests/patmat/enum/patmat-enum.scala:15: warning: match may not be exhaustive.
6+
It would fail on the following input: SATURDAY, FRIDAY, THURSDAY
7+
day match {
8+
^
9+
two warnings found

tests/patmat/enum/patmat-enum.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1-
object Test {
1+
object Test1 {
22
val day: Day = ???
33

44
day match {
55
case Day.MONDAY => true
66
case Day.TUESDAY => true
77
case Day.WEDNESDAY => true
88
}
9+
}
10+
11+
object Test2 {
12+
import Day._
13+
val day: Day = ???
14+
15+
day match {
16+
case MONDAY => true
17+
case TUESDAY => true
18+
case WEDNESDAY => true
19+
case SUNDAY => true
20+
}
921
}

tests/patmat/patmat-adt.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@ object PatmatADT {
5050
def foo5(tree: Tree) : Any = tree match {
5151
case LetL(CharLit) =>
5252
}
53+
54+
def foo6[T](l: List[T]): Boolean = l match {
55+
case x::xs => true
56+
case Nil => false
57+
}
5358
}

tests/patmat/patmat-indent.check

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
./tests/patmat/patmat-indent.scala:9: warning: match may not be exhaustive.
2+
It would fail on the following input: Nil
3+
def foo1a[T](l: List[T]) = l match {
4+
^
5+
./tests/patmat/patmat-indent.scala:23: warning: match may not be exhaustive.
6+
It would fail on the following input: _: Boolean
7+
def foo2(b: Boolean) = b match {
8+
^
9+
./tests/patmat/patmat-indent.scala:27: warning: match may not be exhaustive.
10+
It would fail on the following input: _: Int
11+
def foo3(x: Int) = x match {
12+
^
13+
three warnings found

tests/patmat/patmat-indent.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
object Test {
2+
val Nil = scala.Nil
3+
val X = 5
4+
5+
object Inner {
6+
val Y = false
7+
}
8+
9+
def foo1a[T](l: List[T]) = l match {
10+
case x::xs => false
11+
}
12+
13+
def foo1b[T](l: List[T]) = l match {
14+
case Nil => true
15+
case x::xs => false
16+
}
17+
18+
def foo1c[T](l: List[T]) = l match {
19+
case Test.Nil => true
20+
case x::xs => false
21+
}
22+
23+
def foo2(b: Boolean) = b match {
24+
case Inner.Y => false
25+
}
26+
27+
def foo3(x: Int) = x match {
28+
case X => 0
29+
}
30+
}

tests/patmat/t7466.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
./tests/patmat/t7466.scala:8: warning: match may not be exhaustive.
2-
It would fail on the following input: (true, _), (false, _), (_, true), (_, false)
2+
It would fail on the following input: (_, _)
33
(b1, b2) match {
44
^
55
one warning found

tests/patmat/t9411a.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
object OhNoes {
2+
3+
sealed trait F
4+
sealed abstract class FA extends F
5+
sealed abstract class FB extends F
6+
7+
case object FA1 extends FA
8+
case object FB1 extends FB
9+
case object FB2 extends FB
10+
11+
sealed trait G
12+
case object G1 extends G
13+
case object G2 extends G
14+
15+
sealed trait H
16+
case class H1(a: FB, b: G) extends H
17+
case class H2(a: F) extends H
18+
19+
val demo: H => Unit = {
20+
case H1(FB1, G1) =>
21+
case H1(FB2, G2) =>
22+
case H2(_: FB) =>
23+
case H2(_: FA) =>
24+
case H1(FB1, G2) =>
25+
case H1(FB2, G1) =>
26+
}
27+
}

tests/patmat/t9411b.scala

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
object OhNoes {
2+
3+
sealed trait F
4+
sealed abstract class FA extends F
5+
sealed abstract class FB extends F
6+
7+
case object FA1 extends FA
8+
case object FB1 extends FB
9+
case object FB2 extends FB
10+
11+
sealed trait G
12+
case object G1 extends G
13+
case object G2 extends G
14+
15+
sealed trait H
16+
case class H1(a: FB, b: G) extends H
17+
case class H2(b: F) extends H
18+
19+
val demo: H => Unit = {
20+
case H1(FB1, G1) =>
21+
case H1(FB2, G2) =>
22+
case H2(_: FB) =>
23+
case H2(_: FA) =>
24+
case H1(FB1, G2) =>
25+
case H1(FB2, G1) =>
26+
}
27+
28+
val demo2: H => Unit = {
29+
case H2(_: FA) =>
30+
case H2(_: FB) =>
31+
case H1(FB1, G1) =>
32+
case H1(FB2, G1) =>
33+
case H1(FB1, G2) =>
34+
case H1(FB2, G2) =>
35+
}
36+
}

tests/patmat/virtpatmat_apply.check

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
./tests/patmat/virtpatmat_apply.scala:2: warning: match may not be exhaustive.
2+
It would fail on the following input: List(_)
3+
List(1, 2, 3) match {
4+
^
5+
one warning found

tests/patmat/virtpatmat_apply.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Test {
2+
List(1, 2, 3) match {
3+
case Nil => println("FAIL")
4+
case x :: y :: xs if xs.length == 2 => println("FAIL")
5+
case x :: y :: xs if xs.length == 1 => println("OK "+ y)
6+
}
7+
}

0 commit comments

Comments
 (0)