Skip to content

Fix #2363: better handle extractors in exhaustivity check #2424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 16, 2017
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ object desugar {
case IdPattern(named, tpt) =>
Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body)
case _ =>
makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false)
makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil)
}

/** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -351,15 +351,17 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer {
/* (Nil, body) means that `body` is the default case
* It's a bit hacky but it simplifies manipulations.
*/
def extractSwitchCase(treeMakers: List[TreeMaker]): (List[Int], BodyTreeMaker) = treeMakers match {
def extractSwitchCase(treeMakers: List[TreeMaker]): (List[Int], BodyTreeMaker) = (treeMakers: @unchecked) match {
// case 5 =>
case List(IntEqualityTestTreeMaker(intValue), body: BodyTreeMaker) =>
(List(intValue), body)

// case 5 | 6 =>
case List(AlternativesTreeMaker(_, alts, _), body: BodyTreeMaker) =>
val intValues = alts.map {
case List(IntEqualityTestTreeMaker(intValue)) => intValue
val intValues = alts.map { alt =>
(alt: @unchecked) match {
case List(IntEqualityTestTreeMaker(intValue)) => intValue
}
}
(intValues, body)

Expand Down
192 changes: 151 additions & 41 deletions compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ final case class Text(text: String) extends Inline
abstract class EntityLink(val title: Inline) extends Inline { def link: LinkTo }
object EntityLink {
def apply(title: Inline, linkTo: LinkTo) = new EntityLink(title) { def link: LinkTo = linkTo }
def unapply(el: EntityLink): Option[(Inline, LinkTo)] = Some((el.title, el.link))
def unapply(el: EntityLink): Some[(Inline, LinkTo)] = Some((el.title, el.link))
}
final case class HtmlTag(data: String) extends Inline {
private val Pattern = """(?ms)\A<(/?)(.*?)[\s>].*\z""".r
Expand Down
4 changes: 4 additions & 0 deletions doc-tool/src/dotty/tools/dottydoc/staticsite/tags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ object tags {
title

case ConstantReference(title) => title

case _ => // EmptyReference
ctx.docbase.error(s"invalid reference: $ref")
null
}
override def render(tctx: TemplateContext, nodes: LNode*): AnyRef = nodes(0).render(tctx) match {
case map: JMap[String, AnyRef] @unchecked =>
Expand Down
2 changes: 2 additions & 0 deletions doc-tool/src/dotty/tools/dottydoc/util/MemberLookup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ trait MemberLookup {
case (x :: xs, _) =>
if (xs.nonEmpty) globalLookup
else lookup(entity, packages, "scala." + query)
case (Nil, _) =>
throw new IllegalArgumentException("`query` cannot be empty")
}
}

Expand Down
17 changes: 17 additions & 0 deletions tests/patmat/dotty-unreachable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
object Types {
abstract case class TermRef(val prefix: String, name: String) {
type ThisType = TermRef

def alts: List[TermRef] = ???
}
}

class Test {
def foo(tp: Types.TermRef): Unit = {
tp.alts.filter(_.name == "apply") match {
case Nil =>
case alt :: Nil =>
case alt =>
}
}
}
30 changes: 30 additions & 0 deletions tests/patmat/dotty.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
object IntEqualityTestTreeMaker {
def unapply(xs: Int): Option[Int] = ???
}

class Test {
def isBelow(n: Int, s: String): Boolean = false

def foo(xs: List[(Int, String)]): Unit = (xs filter (isBelow _).tupled) match {
case Nil =>
case matches =>
}

def linkCompanions(xs: List[(Int, Int)]): Unit = {
xs.groupBy(_._1).foreach {
case (_, List(x1, x2)) =>
case _ => ()
}
}

def bar(xs: List[(Int, String)]): Unit = xs match {
case (x, s) :: Nil =>
case Nil =>
case _ =>
}

def patmat(alts: List[List[Int]]): Unit = alts.forall {
case List(IntEqualityTestTreeMaker(_)) => false
case _ => true
}
}
2 changes: 1 addition & 1 deletion tests/patmat/exhausting.check
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
21: Pattern Match Exhaustivity: List(_), List(_, _, _)
27: Pattern Match Exhaustivity: Nil
32: Pattern Match Exhaustivity: List(_, _)
32: Pattern Match Exhaustivity: List(_, _*)
39: Pattern Match Exhaustivity: Bar3
44: Pattern Match Exhaustivity: (Bar2, Bar2)
53: Pattern Match Exhaustivity: (Bar2, Bar2), (Bar2, Bar1), (Bar1, Bar3), (Bar1, Bar2)
2 changes: 2 additions & 0 deletions tests/patmat/for.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ object Test {
def foo[A, B](l: List[(A, B)]): List[A] = {
for ((a, b) <- l) yield a
}

def bar(xs: List[(Int, List[Int])]): Unit = for ( (_, x :: y :: xs) <- xs) yield x
}
2 changes: 2 additions & 0 deletions tests/patmat/i2363.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
15: Pattern Match Exhaustivity: List(_, _*)
21: Pattern Match Exhaustivity: _: Expr
25 changes: 25 additions & 0 deletions tests/patmat/i2363.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
sealed trait Expr
class IntExpr extends Expr
class BooleanExpr extends Expr

object IntExpr {
def unapply(expr: Expr): Option[IntExpr] = ???
}

object BooleanExpr {
def unapply(expr: Expr): Option[BooleanExpr] = ???
}


class Test {
def foo(x: List[Expr]): Int = x match {
case IntExpr(_) :: xs => 1
case BooleanExpr(_) :: xs => 1
case Nil => 2
}

def bar(x: Expr): Int = x match {
case IntExpr(_) => 1
case BooleanExpr(_) => 2
}
}
3 changes: 3 additions & 0 deletions tests/patmat/optionless.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
20: Pattern Match Exhaustivity: _: Tree
24: Pattern Match Exhaustivity: _: Tree
28: Pattern Match Exhaustivity: _: Tree
32 changes: 32 additions & 0 deletions tests/patmat/optionless.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
sealed trait Tree
case class Ident(name: String) extends Tree

object Ident1 {
def unapply(tree: Tree): Ident = ???
}

trait Cap
object Ident2 {
def unapply(tree: Tree)(implicit cap: Cap): Ident = ???
}

object Ident3 {
def unapply(tree: Tree)(implicit cap: Cap): Option[Ident] = ???
}



class Test {
def foo(t: Tree): Unit = t match {
case Ident1(t) =>
}

def bar(t: Tree)(implicit c: Cap): Unit = t match {
case Ident2(t) =>
}

def qux(t: Tree)(implicit c: Cap): Unit = t match {
case Ident3(t) =>
}

}
2 changes: 1 addition & 1 deletion tests/patmat/patmat-adt.check
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
7: Pattern Match Exhaustivity: Bad(Good(_)), Good(Bad(_))
19: Pattern Match Exhaustivity: Some(_)
24: Pattern Match Exhaustivity: (None, Some(_)), (_, Some(_))
24: Pattern Match Exhaustivity: (_, Some(_))
29: Pattern Match Exhaustivity: (None, None), (Some(_), Some(_))
50: Pattern Match Exhaustivity: LetL(BooleanLit), LetL(IntLit)
2 changes: 2 additions & 0 deletions tests/patmat/patmat-extractor.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
13: Pattern Match Exhaustivity: _: Node
15: Match case Unreachable
1 change: 1 addition & 0 deletions tests/patmat/patmatexhaust.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
11: Pattern Match Exhaustivity: Bar(_)
23: Pattern Match Exhaustivity: (Qult(), Qult()), (Kult(_), Kult(_))
49: Pattern Match Exhaustivity: _: Gp
59: Pattern Match Exhaustivity: Nil
75: Pattern Match Exhaustivity: _: B
100: Pattern Match Exhaustivity: _: C1
114: Pattern Match Exhaustivity: D2(), D1
Expand Down
2 changes: 1 addition & 1 deletion tests/patmat/t6420.check
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5: Pattern Match Exhaustivity: (Nil, _), (List(true, _), _), (List(false, _), _), (_, Nil), (_, List(true, _)), (_, List(false, _))
5: Pattern Match Exhaustivity: (_: List, Nil), (_: List, List(true, _*)), (_: List, List(false, _*))
8 changes: 4 additions & 4 deletions tests/patmat/t7020.check
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
3: Pattern Match Exhaustivity: List(_, _)
10: Pattern Match Exhaustivity: List(_, _)
17: Pattern Match Exhaustivity: List(_, _)
24: Pattern Match Exhaustivity: List(_, _)
3: Pattern Match Exhaustivity: List(_, _*)
10: Pattern Match Exhaustivity: List(_, _*)
17: Pattern Match Exhaustivity: List(_, _*)
24: Pattern Match Exhaustivity: List(_, _*)
2 changes: 1 addition & 1 deletion tests/patmat/t7466.check
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8: Pattern Match Exhaustivity: (true, _), (false, _), (_, true), (_, false)
8: Pattern Match Exhaustivity: (_, true), (_, false)
2 changes: 1 addition & 1 deletion tests/patmat/t9129.check
Original file line number Diff line number Diff line change
@@ -1 +1 @@
21: Pattern Match Exhaustivity: Two(B2, A2), Two(_, A2)
21: Pattern Match Exhaustivity: Two(_, A2)
2 changes: 1 addition & 1 deletion tests/patmat/t9232.check
Original file line number Diff line number Diff line change
@@ -1 +1 @@
13: Pattern Match Exhaustivity: Node2()
13: Pattern Match Exhaustivity: Node2(), Node1(Foo(_))
2 changes: 1 addition & 1 deletion tests/patmat/t9351.check
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
8: Pattern Match Exhaustivity: _: A
17: Pattern Match Exhaustivity: (_, _), (_, None), (_, Some(_))
17: Pattern Match Exhaustivity: (_, None), (_, Some(_))
28: Pattern Match Exhaustivity: (_, _)