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..e34ecd563f99 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -65,10 +65,11 @@ 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 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) /** 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 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