diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 870e985fd48e..69ba2377a456 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5214,6 +5214,10 @@ object Types extends TypeUtils { def thatReducesUsingGadt(tp: Type)(using Context): Boolean = tp.underlyingMatchType match case mt: MatchType => mt.reducesUsingGadt case _ => false + + object Normalizing: + def unapply(tp: Type)(using Context): Option[Type] = + Some(tp.tryNormalize).filter(_.exists) } enum MatchTypeCasePattern: diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 509461c794f4..082c239c6443 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -135,6 +135,7 @@ object TypeTestsCasts { def recur(X: Type, P: Type): String = trace(s"recur(${X.show}, ${P.show})") { (X <:< P) ||| P.dealias.match case _: SingletonType => "" + case MatchType.Normalizing(tp) => recur(X, tp) case _: TypeProxy if isAbstract(P) => i"it refers to an abstract type member or type parameter" case defn.ArrayOf(tpT) => diff --git a/tests/warn/i13433c/A_1.scala b/tests/warn/i13433c/A_1.scala new file mode 100644 index 000000000000..d810b8e34909 --- /dev/null +++ b/tests/warn/i13433c/A_1.scala @@ -0,0 +1,27 @@ +import scala.reflect.TypeTest + +type Matcher[A] = A match { case String => A } + +def patternMatch[A](a: Any)(using tt: TypeTest[Any, Matcher[A]]): Option[Matcher[A]] = { + // type T = RDF.Triple[Rdf] + a match { + case res: Matcher[A] => Some(res) + case _ => None + } +} + +def patternMatchWithAlias[A](a: Any)(using tt: TypeTest[Any, Matcher[A]]): Option[Matcher[A]] = { + type T = Matcher[A] + a match { + case res: T => Some(res) + case _ => None + } +} + +type S = String +type MS = Matcher[S] + +type S2 = MS +type MS2 = Matcher[S2] + +type Mstuck = Matcher[Nothing] diff --git a/tests/warn/i13433c/B_2.scala b/tests/warn/i13433c/B_2.scala new file mode 100644 index 000000000000..a0654d8cb96d --- /dev/null +++ b/tests/warn/i13433c/B_2.scala @@ -0,0 +1,23 @@ + +@main def main = { + println(patternMatch[String]("abc")) + println(patternMatchWithAlias[String]("abc")) + println(patternMatch[String]("abc")(using (s: Any) => { + if s.isInstanceOf[Matcher[String]] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None })) + println(patternMatchWithAlias[String]("abc")(using (s: Any) => { + if s.isInstanceOf[Matcher[String]] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None })) + + println(patternMatch[String](1)) + println(patternMatchWithAlias[String](1)) + + println(patternMatch[String]("abc")(using (s: Any) => { + if s.isInstanceOf[S] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None})) + println(patternMatch[String]("abc")(using (s: Any) => { + if s.isInstanceOf[MS] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None})) + println(patternMatch[String]("abc")(using (s: Any) => { + if s.isInstanceOf[S2] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None})) + println(patternMatch[String]("abc")(using (s: Any) => { + if s.isInstanceOf[MS2] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None})) + println(patternMatch[String]("abc")(using (s: Any) => { + if s.isInstanceOf[Mstuck] then Some[s.type & Matcher[String]](s.asInstanceOf[s.type & Matcher[String]]) else None})) // warn +}