Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/patmat/Space.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ object SpaceEngine {

/** Is `a` a subspace of `b`? Equivalent to `simplify(simplify(a) - simplify(b)) == Empty`, but faster */
def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = trace(i"isSubspace($a, $b)") {
/** Is decomposition allowed on the right-hand side of a pattern? */
/** 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 */
/** This is because decomposition on the right-hand side of a pattern can lead to false positive warnings */
inline def rhsDecompositionAllowed(tp: Type): Boolean = tp.dealias match
case _: TypeParamRef => false
case tr: TypeRef if tr.symbol.is(TypeParam) || (tr.symbol.is(Deferred) && !tr.symbol.isClass) => false
case _ => true

val a2 = simplify(a)
val b2 = simplify(b)
if (a ne a2) || (b ne b2) then isSubspace(a2, b2)
Expand All @@ -185,7 +193,7 @@ object SpaceEngine {
case (a @ Typ(tp1, _), b @ Typ(tp2, _)) =>
isSubType(tp1, tp2)
|| canDecompose(a) && isSubspace(Or(decompose(a)), b)
|| canDecompose(b) && isSubspace(a, Or(decompose(b)))
|| (canDecompose(b) && rhsDecompositionAllowed(tp2)) && isSubspace(a, Or(decompose(b)))
case (Prod(tp1, _, _), Typ(tp2, _)) =>
isSubType(tp1, tp2)
case (a @ Typ(tp1, _), Prod(tp2, fun, ss)) =>
Expand Down
12 changes: 12 additions & 0 deletions tests/pos/i20225.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sealed abstract class Parent
class A extends Parent
class B extends Parent

inline def matchAs[T <: Parent](p: Parent): Unit = p match
case _: T => ()
case _ => ()

object Test:
def main(args: Array[String]): Unit =
matchAs[A](new B)

13 changes: 13 additions & 0 deletions tests/pos/i20395.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
sealed trait NodeId
case object Hi extends NodeId
case object Hello extends NodeId

extension (value: NodeId)
inline def parse[T <: NodeId] = value match
case _: T => ()
case _ => ()

object Test:
def main(args: Array[String]): Unit =
Hi.parse[Hello.type]

1 change: 1 addition & 0 deletions tests/run/i20225.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
unreachable case reached
12 changes: 12 additions & 0 deletions tests/run/i20225.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
sealed abstract class Parent
class A extends Parent
class B extends Parent

inline def matchAs[T <: Parent](p: Parent): Unit = p match
case _: T => ()
case _ => println("unreachable case reached")

object Test:
def main(args: Array[String]): Unit =
matchAs[A](new B)

1 change: 1 addition & 0 deletions tests/run/i20395.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
not match
13 changes: 13 additions & 0 deletions tests/run/i20395.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
sealed trait NodeId
case object Hi extends NodeId
case object Hello extends NodeId

extension (value: NodeId)
inline def parse[T <: NodeId]: Unit = value match
case _: T => println("match")
case _ => println("not match")

object Test:
def main(args: Array[String]): Unit =
Hi.parse[Hello.type]

Loading