Skip to content

Commit ab10e41

Browse files
authored
Merge pull request #639 from scala/backport-lts-3.3-23909
Backport "Use upper bound of abstract types in exhaustivity checking" to 3.3 LTS
2 parents 4bc458b + 7e2aa57 commit ab10e41

File tree

6 files changed

+109
-1
lines changed

6 files changed

+109
-1
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,8 @@ object SpaceEngine {
687687
else NoType
688688
}.filter(_.exists)
689689
parts
690+
case tref: TypeRef if tref.isUpperBoundedAbstract =>
691+
rec(tref.info.hiBound, mixins)
690692
case _ => ListOfNoType
691693
end rec
692694

@@ -702,6 +704,10 @@ object SpaceEngine {
702704
&& !cls.hasAnonymousChild // can't name anonymous classes as counter-examples
703705
&& cls.children.nonEmpty // can't decompose without children
704706

707+
extension (tref: TypeRef)
708+
def isUpperBoundedAbstract(using Context): Boolean =
709+
tref.symbol.isAbstractOrAliasType && !tref.info.hiBound.isNothingType
710+
705711
val ListOfNoType = List(NoType)
706712
val ListOfTypNoType = ListOfNoType.map(Typ(_, decomposed = true))
707713

@@ -826,7 +832,11 @@ object SpaceEngine {
826832
classSym.is(Case) && {
827833
if seen.add(classSym) then productSelectorTypes(tpw, sel.srcPos).exists(isCheckable(_))
828834
else true // recursive case class: return true and other members can still fail the check
829-
}
835+
} ||
836+
(tpw.isInstanceOf[TypeRef] && {
837+
val tref = tpw.asInstanceOf[TypeRef]
838+
tref.isUpperBoundedAbstract && isCheckable(tref.info.hiBound)
839+
})
830840

831841
!sel.tpe.hasAnnotation(defn.UncheckedAnnot)
832842
&& {

tests/pos/i23620.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
trait Foo
2+
trait Bar
3+
4+
type FooOrBar = FooOrBar.Type
5+
object FooOrBar:
6+
opaque type Type <: (Foo | Bar) = Foo | Bar
7+
8+
def bar: FooOrBar = new Bar {}
9+
10+
trait Buz
11+
12+
@main def main =
13+
val p: FooOrBar | Buz = FooOrBar.bar
14+
15+
p match
16+
case _: Foo => println("foo")
17+
case _: Buz => println("buz")
18+
case _: Bar => println("bar")

tests/warn/i23620b.check

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i23620b.scala:20:2 --------------------------------------------
2+
20 | p match // warn
3+
| ^
4+
| match may not be exhaustive.
5+
|
6+
| It would fail on pattern case: _: Bar
7+
|
8+
| longer explanation available when compiling with `-explain`
9+
-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i23620b.scala:23:2 --------------------------------------------
10+
23 | p2 match { // warn
11+
| ^^
12+
| match may not be exhaustive.
13+
|
14+
| It would fail on pattern case: _: Bar
15+
|
16+
| longer explanation available when compiling with `-explain`
17+
-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i23620b.scala:37:2 --------------------------------------------
18+
37 | x match // warn
19+
| ^
20+
| match may not be exhaustive.
21+
|
22+
| It would fail on pattern case: B
23+
|
24+
| longer explanation available when compiling with `-explain`

tests/warn/i23620b.scala

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
trait Foo
2+
trait Bar
3+
4+
type FooOrBar = FooOrBar.Type
5+
object FooOrBar:
6+
opaque type Type <: (Foo | Bar) = Foo | Bar
7+
8+
def bar: FooOrBar = new Bar {}
9+
10+
type OnlyFoo = OnlyFoo.Type
11+
object OnlyFoo:
12+
opaque type Type <: (Foo | Bar) = Foo
13+
14+
def foo: OnlyFoo = new Foo {}
15+
16+
@main def main =
17+
val p: FooOrBar= FooOrBar.bar
18+
val p2: OnlyFoo = OnlyFoo.foo
19+
20+
p match // warn
21+
case _: Foo => println("foo")
22+
23+
p2 match { // warn
24+
case _: Foo => println("foo")
25+
}
26+
27+
sealed trait S
28+
trait Z
29+
30+
case object A extends S, Z
31+
case object B extends S, Z
32+
33+
trait HasT:
34+
type T <: S & Z
35+
36+
def nonExhaustive(h: HasT, x: h.T) =
37+
x match // warn
38+
case A => ()

tests/warn/i24246.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- [E029] Pattern Match Exhaustivity Warning: tests/warn/i24246.scala:8:2 ----------------------------------------------
2+
8 | x match { // warn
3+
| ^
4+
| match may not be exhaustive.
5+
|
6+
| It would fail on pattern case: ZZ
7+
|
8+
| longer explanation available when compiling with `-explain`

tests/warn/i24246.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait X
2+
3+
sealed trait Y
4+
case object YY extends Y, X
5+
case object ZZ extends Y, X
6+
7+
def foo[A <: X & Y](x: A): Unit =
8+
x match { // warn
9+
case YY => ()
10+
}

0 commit comments

Comments
 (0)