Skip to content

Commit 700b08c

Browse files
committed
add guard for doing rhs decompostion in computing subspaces
1 parent 712d5bc commit 700b08c

File tree

7 files changed

+61
-1
lines changed

7 files changed

+61
-1
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ object SpaceEngine {
171171

172172
/** Is `a` a subspace of `b`? Equivalent to `simplify(simplify(a) - simplify(b)) == Empty`, but faster */
173173
def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = trace(i"isSubspace($a, $b)") {
174+
/** Is decomposition allowed on the right-hand side of a pattern? */
175+
/** We only allow decomposition on the right-hand side of a pattern if the type is not a type parameter, a type parameter reference, or a deferred type reference */
176+
/** This is because decomposition on the right-hand side of a pattern can lead to false positive warnings */
177+
inline def rhsDecompositionAllowed(tp: Type): Boolean = tp.dealias match
178+
case _: TypeParamRef => false
179+
case tr: TypeRef if tr.symbol.is(TypeParam) || (tr.symbol.is(Deferred) && !tr.symbol.isClass) => false
180+
case _ => true
181+
174182
val a2 = simplify(a)
175183
val b2 = simplify(b)
176184
if (a ne a2) || (b ne b2) then isSubspace(a2, b2)
@@ -185,7 +193,7 @@ object SpaceEngine {
185193
case (a @ Typ(tp1, _), b @ Typ(tp2, _)) =>
186194
isSubType(tp1, tp2)
187195
|| canDecompose(a) && isSubspace(Or(decompose(a)), b)
188-
|| canDecompose(b) && isSubspace(a, Or(decompose(b)))
196+
|| (canDecompose(b) && rhsDecompositionAllowed(tp2)) && isSubspace(a, Or(decompose(b)))
189197
case (Prod(tp1, _, _), Typ(tp2, _)) =>
190198
isSubType(tp1, tp2)
191199
case (a @ Typ(tp1, _), Prod(tp2, fun, ss)) =>

tests/run/i20225.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
unreachable case reached

tests/run/i20225.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
sealed abstract class Parent
2+
class A extends Parent
3+
class B extends Parent
4+
5+
inline def matchAs[T <: Parent](p: Parent): Unit = p match
6+
case _: T => ()
7+
case _ => println("unreachable case reached")
8+
9+
object Test:
10+
def main(args: Array[String]): Unit =
11+
matchAs[A](new B)
12+

tests/run/i20395.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
not match

tests/run/i20395.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
sealed trait NodeId
2+
case object Hi extends NodeId
3+
case object Hello extends NodeId
4+
5+
extension (value: NodeId)
6+
inline def parse[T <: NodeId]: Unit = value match
7+
case _: T => println("match")
8+
case _ => println("not match")
9+
10+
object Test:
11+
def main(args: Array[String]): Unit =
12+
Hi.parse[Hello.type]
13+

tests/warn/i20225.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
sealed abstract class Parent
2+
class A extends Parent
3+
class B extends Parent
4+
5+
inline def matchAs[T <: Parent](p: Parent): Unit = p match
6+
case _: T => ()
7+
case _ => ()
8+
9+
object Test:
10+
def main(args: Array[String]): Unit =
11+
matchAs[A](new B)
12+

tests/warn/i20395.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
sealed trait NodeId
2+
case object Hi extends NodeId
3+
case object Hello extends NodeId
4+
5+
extension (value: NodeId)
6+
inline def parse[T <: NodeId] = value match
7+
case _: T => ()
8+
case _ => ()
9+
10+
object Test:
11+
def main(args: Array[String]): Unit =
12+
Hi.parse[Hello.type]
13+

0 commit comments

Comments
 (0)