From abb6909f22df2148d3719c3567ba5c5488a35636 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Wed, 24 Apr 2024 19:18:10 +0200 Subject: [PATCH 1/2] Normalize when verifying if TypeTestCasts are unchecked --- .../tools/dotc/transform/TypeTestsCasts.scala | 1 + tests/pos/i13433c/A_1.scala | 25 +++++++++++++++++++ tests/pos/i13433c/B_2.scala | 22 ++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 tests/pos/i13433c/A_1.scala create mode 100644 tests/pos/i13433c/B_2.scala diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 509461c794f4..2007cbe45ff5 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 tp if tp.isMatchAlias => recur(X, tp.tryNormalize) case _: TypeProxy if isAbstract(P) => i"it refers to an abstract type member or type parameter" case defn.ArrayOf(tpT) => diff --git a/tests/pos/i13433c/A_1.scala b/tests/pos/i13433c/A_1.scala new file mode 100644 index 000000000000..8163c4f6e990 --- /dev/null +++ b/tests/pos/i13433c/A_1.scala @@ -0,0 +1,25 @@ +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] diff --git a/tests/pos/i13433c/B_2.scala b/tests/pos/i13433c/B_2.scala new file mode 100644 index 000000000000..5f2b0e6e0830 --- /dev/null +++ b/tests/pos/i13433c/B_2.scala @@ -0,0 +1,22 @@ +//> using options -Xfatal-warnings -deprecation -feature + +@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})) +} From 1f9987cafd5851555f324a81915e27562f28e576 Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 25 Apr 2024 09:45:28 +0200 Subject: [PATCH 2/2] Only recurse for TypeTests checkability with normalizing match types --- compiler/src/dotty/tools/dotc/core/Types.scala | 4 ++++ compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 2 +- tests/{pos => warn}/i13433c/A_1.scala | 2 ++ tests/{pos => warn}/i13433c/B_2.scala | 3 ++- 4 files changed, 9 insertions(+), 2 deletions(-) rename tests/{pos => warn}/i13433c/A_1.scala (94%) rename tests/{pos => warn}/i13433c/B_2.scala (87%) 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 2007cbe45ff5..082c239c6443 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -135,7 +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 tp if tp.isMatchAlias => recur(X, tp.tryNormalize) + 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/pos/i13433c/A_1.scala b/tests/warn/i13433c/A_1.scala similarity index 94% rename from tests/pos/i13433c/A_1.scala rename to tests/warn/i13433c/A_1.scala index 8163c4f6e990..d810b8e34909 100644 --- a/tests/pos/i13433c/A_1.scala +++ b/tests/warn/i13433c/A_1.scala @@ -23,3 +23,5 @@ type MS = Matcher[S] type S2 = MS type MS2 = Matcher[S2] + +type Mstuck = Matcher[Nothing] diff --git a/tests/pos/i13433c/B_2.scala b/tests/warn/i13433c/B_2.scala similarity index 87% rename from tests/pos/i13433c/B_2.scala rename to tests/warn/i13433c/B_2.scala index 5f2b0e6e0830..a0654d8cb96d 100644 --- a/tests/pos/i13433c/B_2.scala +++ b/tests/warn/i13433c/B_2.scala @@ -1,4 +1,3 @@ -//> using options -Xfatal-warnings -deprecation -feature @main def main = { println(patternMatch[String]("abc")) @@ -19,4 +18,6 @@ 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 }