From 6daf419ebfde398e8087d6eb177a987706b4ca6e Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Thu, 11 Apr 2024 17:18:32 +0200 Subject: [PATCH 1/2] Normalize before attempting to record a failed match type reduction `MatchTypeTrace.recurseWith` will restore the previous entries if op succeeds, which is the true as long one reduction could be done, but we may miss an underlying failed reduction that was attempted. The issue could not be detected without separate compilation, since the successful normalizations already happened in `TypeOps#simplify`. --- .../dotty/tools/dotc/core/MatchTypeTrace.scala | 2 +- compiler/src/dotty/tools/dotc/core/Types.scala | 3 ++- .../dotty/tools/dotc/typer/ErrorReporting.scala | 8 ++++---- tests/neg/{i12049.check => i12049a.check} | 14 +++++++------- tests/neg/{i12049.scala => i12049a.scala} | 0 tests/neg/i12049b.check | 17 +++++++++++++++++ tests/neg/i12049b/A_1.scala | 6 ++++++ tests/neg/i12049b/B_2.scala | 2 ++ 8 files changed, 39 insertions(+), 13 deletions(-) rename tests/neg/{i12049.check => i12049a.check} (92%) rename tests/neg/{i12049.scala => i12049a.scala} (100%) create mode 100644 tests/neg/i12049b.check create mode 100644 tests/neg/i12049b/A_1.scala create mode 100644 tests/neg/i12049b/B_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala b/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala index e16a950aa32a..fe62ea5f534e 100644 --- a/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala +++ b/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala @@ -23,7 +23,7 @@ object MatchTypeTrace: private val MatchTrace = new Property.Key[MatchTrace] - /** Execute `op` and if it involves a failed match type reduction + /** Execute `op` and if it is a failed match type reduction * return the trace of that reduction. Otherwise return the empty string. */ def record(op: Context ?=> Any)(using Context): String = diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 38b3f870fd8d..d7647e651f4f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1536,7 +1536,8 @@ object Types extends TypeUtils { /** If this type can be normalized at the top-level by rewriting match types * of S[n] types, the result after applying all toplevel normalizations, - * otherwise NoType + * otherwise NoType. Note applied match aliases are not beta reduced + * if the underlying MatchType is stuck. */ def tryNormalize(using Context): Type = NoType diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 68143dfd2ba0..48b13e0b46d9 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -65,10 +65,10 @@ object ErrorReporting { val collectMatchTrace = new TypeAccumulator[String]: def apply(s: String, tp: Type): String = if s.nonEmpty then s - else tp match - case tp: AppliedType if tp.isMatchAlias => MatchTypeTrace.record(tp.tryNormalize) - case tp: MatchType => MatchTypeTrace.record(tp.tryNormalize) - case _ => foldOver(s, tp) + else + val normed = tp.normalized + val r = MatchTypeTrace.record(normed.tryNormalize) + if r.nonEmpty then r else foldOver(s, tp) tps.foldLeft("")(collectMatchTrace) /** A mixin trait that can produce added elements for an error message */ diff --git a/tests/neg/i12049.check b/tests/neg/i12049a.check similarity index 92% rename from tests/neg/i12049.check rename to tests/neg/i12049a.check index e0c2d498f119..e4fab0dc36de 100644 --- a/tests/neg/i12049.check +++ b/tests/neg/i12049a.check @@ -1,4 +1,4 @@ --- [E007] Type Mismatch Error: tests/neg/i12049.scala:6:16 ------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/i12049a.scala:6:16 ------------------------------------------------------------ 6 |val x: String = ??? : M[B] // error | ^^^^^^^^^^ | Found: M[B] @@ -15,7 +15,7 @@ | case B => String | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/i12049.scala:14:17 ------------------------------------------------------------ +-- [E007] Type Mismatch Error: tests/neg/i12049a.scala:14:17 ----------------------------------------------------------- 14 |val y3: String = ??? : Last[Int *: Int *: Boolean *: String *: EmptyTuple] // error | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | Found: Last[EmptyTuple] @@ -31,7 +31,7 @@ | case t *: EmptyTuple => t | | longer explanation available when compiling with `-explain` --- [E007] Type Mismatch Error: tests/neg/i12049.scala:22:20 ------------------------------------------------------------ +-- [E007] Type Mismatch Error: tests/neg/i12049a.scala:22:20 ----------------------------------------------------------- 22 |val z3: (A, B, A) = ??? : Reverse[(A, B, A)] // error | ^^^^^^^^^^^^^^^^^^^^^^^^ | Found: Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)] @@ -48,7 +48,7 @@ | case EmptyTuple => EmptyTuple | | longer explanation available when compiling with `-explain` --- [E172] Type Error: tests/neg/i12049.scala:24:20 --------------------------------------------------------------------- +-- [E172] Type Error: tests/neg/i12049a.scala:24:20 -------------------------------------------------------------------- 24 |val _ = summon[M[B]] // error | ^ | No given instance of type M[B] was found for parameter x of method summon in object Predef @@ -62,7 +62,7 @@ | Therefore, reduction cannot advance to the remaining case | | case B => String --- [E172] Type Error: tests/neg/i12049.scala:25:78 --------------------------------------------------------------------- +-- [E172] Type Error: tests/neg/i12049a.scala:25:78 -------------------------------------------------------------------- 25 |val _ = summon[String =:= Last[Int *: Int *: Boolean *: String *: EmptyTuple]] // error | ^ | Cannot prove that String =:= Last[EmptyTuple]. @@ -75,7 +75,7 @@ | | case _ *: _ *: t => Last[t] | case t *: EmptyTuple => t --- [E172] Type Error: tests/neg/i12049.scala:26:48 --------------------------------------------------------------------- +-- [E172] Type Error: tests/neg/i12049a.scala:26:48 -------------------------------------------------------------------- 26 |val _ = summon[(A, B, A) =:= Reverse[(A, B, A)]] // error | ^ | Cannot prove that (A, B, A) =:= Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)]. @@ -89,7 +89,7 @@ | | case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)] | case EmptyTuple => EmptyTuple --- [E008] Not Found Error: tests/neg/i12049.scala:28:21 ---------------------------------------------------------------- +-- [E008] Not Found Error: tests/neg/i12049a.scala:28:21 --------------------------------------------------------------- 28 |val _ = (??? : M[B]).length // error | ^^^^^^^^^^^^^^^^^^^ | value length is not a member of M[B] diff --git a/tests/neg/i12049.scala b/tests/neg/i12049a.scala similarity index 100% rename from tests/neg/i12049.scala rename to tests/neg/i12049a.scala diff --git a/tests/neg/i12049b.check b/tests/neg/i12049b.check new file mode 100644 index 000000000000..291124281472 --- /dev/null +++ b/tests/neg/i12049b.check @@ -0,0 +1,17 @@ + +-- [E007] Type Mismatch Error: tests/neg/i12049b/B_2.scala:2:17 -------------------------------------------------------- +2 |val y1: String = foo // error + | ^^^ + | Found: Last[(Int, Int, Boolean, String)] + | Required: String + | + | Note: a match type could not be fully reduced: + | + | trying to reduce Last[EmptyTuple] + | failed since selector EmptyTuple + | matches none of the cases + | + | case _ *: _ *: t => Last[t] + | case t *: EmptyTuple => t + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i12049b/A_1.scala b/tests/neg/i12049b/A_1.scala new file mode 100644 index 000000000000..5f115c4dbd96 --- /dev/null +++ b/tests/neg/i12049b/A_1.scala @@ -0,0 +1,6 @@ + +type Last[X <: Tuple] = X match + case _ *: _ *: t => Last[t] + case t *: EmptyTuple => t + +def foo: Last[Int *: Int *: Boolean *: String *: EmptyTuple] = ??? diff --git a/tests/neg/i12049b/B_2.scala b/tests/neg/i12049b/B_2.scala new file mode 100644 index 000000000000..152a734bd5ba --- /dev/null +++ b/tests/neg/i12049b/B_2.scala @@ -0,0 +1,2 @@ + +val y1: String = foo // error From a5064e405051698f3722f93b53380ad82400cebb Mon Sep 17 00:00:00 2001 From: Eugene Flesselle Date: Sun, 14 Apr 2024 00:31:06 +0200 Subject: [PATCH 2/2] Dealias for MatchTypeTrace --- .../tools/dotc/typer/ErrorReporting.scala | 3 +- tests/neg/i12049c.check | 34 +++++++++++++++++++ tests/neg/i12049c.scala | 12 +++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i12049c.check create mode 100644 tests/neg/i12049c.scala diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 48b13e0b46d9..e34ecd563f99 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -67,7 +67,8 @@ object ErrorReporting { if s.nonEmpty then s else val normed = tp.normalized - val r = MatchTypeTrace.record(normed.tryNormalize) + val toTrace = if normed.isMatchAlias then normed else normed.dealias + val r = MatchTypeTrace.record(toTrace.tryNormalize) if r.nonEmpty then r else foldOver(s, tp) tps.foldLeft("")(collectMatchTrace) diff --git a/tests/neg/i12049c.check b/tests/neg/i12049c.check new file mode 100644 index 000000000000..9738291ae240 --- /dev/null +++ b/tests/neg/i12049c.check @@ -0,0 +1,34 @@ +-- [E007] Type Mismatch Error: tests/neg/i12049c.scala:9:16 ------------------------------------------------------------ +9 |val x: String = ??? : M[B] // error + | ^^^^^^^^^^ + | Found: M[B] + | Required: String + | + | Note: a match type could not be fully reduced: + | + | trying to reduce M[B] + | failed since selector B + | does not match case A => Int + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case B => String + | + | longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg/i12049c.scala:12:17 ----------------------------------------------------------- +12 |val x2: String = ??? : MB // error + | ^^^^^^^^ + | Found: MB + | Required: String + | + | Note: a match type could not be fully reduced: + | + | trying to reduce M[B] + | failed since selector B + | does not match case A => Int + | and cannot be shown to be disjoint from it either. + | Therefore, reduction cannot advance to the remaining case + | + | case B => String + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg/i12049c.scala b/tests/neg/i12049c.scala new file mode 100644 index 000000000000..461feb0052d9 --- /dev/null +++ b/tests/neg/i12049c.scala @@ -0,0 +1,12 @@ + +trait A +trait B + +type M[X] = X match + case A => Int + case B => String + +val x: String = ??? : M[B] // error + +type MB = M[B] +val x2: String = ??? : MB // error