diff --git a/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala b/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala index a52c6e0a7c3e..8e7ab5045d1f 100644 --- a/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala +++ b/compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala @@ -78,7 +78,7 @@ object MatchTypeTrace: */ def recurseWith(scrut: Type)(op: => Type)(using Context): Type = ctx.property(MatchTrace) match - case Some(trace) => + case Some(trace) if !trace.entries.contains(TryReduce(scrut)) => val prev = trace.entries trace.entries = TryReduce(scrut) :: prev val res = op diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index b7b4379b0a83..7ec89427e84c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -3231,8 +3231,12 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) { case MatchResult.Reduced(tp) => tp case Nil => - val casesText = MatchTypeTrace.noMatchesText(scrut, cases) - throw TypeError(em"Match type reduction $casesText") + /* TODO warn ? then re-enable warn/12974.scala:26 + val noCasesText = MatchTypeTrace.noMatchesText(scrut, cases) + report.warning(reporting.MatchTypeNoCases(noCasesText), pos = ???) + */ + MatchTypeTrace.noMatches(scrut, cases) + NoType inFrozenConstraint { // Empty types break the basic assumption that if a scrutinee and a diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index cfda041745e4..c7291273369d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -637,6 +637,7 @@ trait ImplicitRunInfo: traverseChildren(t) case t => traverseChildren(t) + traverse(t.normalized) catch case ex: Throwable => handleRecursive("collectParts of", t.show, ex) def apply(tp: Type): collection.Set[Type] = diff --git a/tests/neg-macros/toexproftuple.scala b/tests/neg-macros/toexproftuple.scala index 20ae2f08ff8d..f33bfd5f6dfb 100644 --- a/tests/neg-macros/toexproftuple.scala +++ b/tests/neg-macros/toexproftuple.scala @@ -1,63 +1,10 @@ -import scala.quoted._, scala.deriving.* // error -// ^ -// Match type reduction failed since selector ((2 : Int), quoted.Expr[(3 : Int)]) -// matches none of the cases -// -// case quoted.Expr[x] *: t => x *: scala.Tuple.InverseMap[t, quoted.Expr] -// case EmptyTuple => EmptyTuple - -inline def mcr: Any = ${mcrImpl} // error -// ^ -// Match type reduction failed since selector ((2 : Int), quoted.Expr[(3 : Int)]) -// matches none of the cases -// -// case quoted.Expr[x] *: t => x *: scala.Tuple.InverseMap[t, quoted.Expr] -// case EmptyTuple => EmptyTuple - -def mcrImpl(using ctx: Quotes): Expr[Any] = { // error // error - //^ - // Match type reduction failed since selector ((2 : Int), quoted.Expr[(3 : Int)]) - // matches none of the cases - // - // case quoted.Expr[x] *: t => x *: scala.Tuple.InverseMap[t, quoted.Expr] - // case EmptyTuple => EmptyTuple - - // ^ - // Match type reduction failed since selector ((2 : Int), quoted.Expr[(3 : Int)]) - // matches none of the cases - // - // case quoted.Expr[x] *: t => x *: scala.Tuple.InverseMap[t, quoted.Expr] - // case EmptyTuple => EmptyTuple +import scala.quoted._, scala.deriving.* +inline def mcr: Any = ${mcrImpl} +def mcrImpl(using ctx: Quotes): Expr[Any] = { val tpl: (Expr[1], Expr[2], Expr[3]) = ('{1}, '{2}, '{3}) '{val res: (1, 3, 3) = ${Expr.ofTuple(tpl)}; res} // error - // ^^^^^^^^^^^^^^^^^ - // Found: quoted.Expr[(1 : Int) *: (2 : Int) *: (3 : Int) *: EmptyTuple] - // Required: quoted.Expr[((1 : Int), (3 : Int), (3 : Int))] val tpl2: (Expr[1], 2, Expr[3]) = ('{1}, 2, '{3}) - '{val res = ${Expr.ofTuple(tpl2)}; res} // error // error // error // error - // ^ - // Cannot prove that (quoted.Expr[(1 : Int)], (2 : Int), quoted.Expr[(3 : Int)]) =:= scala.Tuple.Map[ - // scala.Tuple.InverseMap[ - // (quoted.Expr[(1 : Int)], (2 : Int), quoted.Expr[(3 : Int)]) - // , quoted.Expr] - // , quoted.Expr]. - - // ^ - // Match type reduction failed since selector ((2 : Int), quoted.Expr[(3 : Int)]) - // matches none of the cases - // - // case quoted.Expr[x] *: t => x *: scala.Tuple.InverseMap[t, quoted.Expr] - // case EmptyTuple => EmptyTuple - - // ^ - // Cyclic reference involving val res - - // ^ - // Match type reduction failed since selector ((2 : Int), quoted.Expr[(3 : Int)]) - // matches none of the cases - // - // case quoted.Expr[x] *: t => x *: scala.Tuple.InverseMap[t, quoted.Expr] - // case EmptyTuple => EmptyTuple + '{val res = ${Expr.ofTuple(tpl2)}; res} // error } diff --git a/tests/neg/10349.scala b/tests/neg/10349.scala index 4ea683f6a8fb..b591c1a79abb 100644 --- a/tests/neg/10349.scala +++ b/tests/neg/10349.scala @@ -4,7 +4,7 @@ object Firsts: case Map[_, v] => First[Option[v]] def first[X](x: X): First[X] = x match - case x: Map[_, _] => first(x.values.headOption) // error + case x: Map[_, _] => first(x.values.headOption) @main def runFirsts2(): Unit = diff --git a/tests/neg/10747.scala b/tests/neg/10747.scala index a299f2a6590c..5275ebc84121 100644 --- a/tests/neg/10747.scala +++ b/tests/neg/10747.scala @@ -2,4 +2,5 @@ type Foo[A] = A match { case Int => String } -type B = Foo[Boolean] // error +type B = Foo[Boolean] +val _: B = "hello" // error diff --git a/tests/neg/i12049.check b/tests/neg/i12049.check index 11c648e35a57..e0c2d498f119 100644 --- a/tests/neg/i12049.check +++ b/tests/neg/i12049.check @@ -15,22 +15,39 @@ | case B => String | | longer explanation available when compiling with `-explain` --- Error: tests/neg/i12049.scala:14:23 --------------------------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/i12049.scala:14:17 ------------------------------------------------------------ 14 |val y3: String = ??? : Last[Int *: Int *: Boolean *: String *: EmptyTuple] // error - | ^ - | Match type reduction failed since selector EmptyTuple.type - | matches none of the cases + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | Found: Last[EmptyTuple] + | Required: String | - | case _ *: _ *: t => Last[t] - | case t *: EmptyTuple => t --- Error: tests/neg/i12049.scala:22:26 --------------------------------------------------------------------------------- + | 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` +-- [E007] Type Mismatch Error: tests/neg/i12049.scala:22:20 ------------------------------------------------------------ 22 |val z3: (A, B, A) = ??? : Reverse[(A, B, A)] // error - | ^ - | Match type reduction failed since selector A *: EmptyTuple.type - | matches none of the cases + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | Found: Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)] + | Required: (A, B, A) + | + | Note: a match type could not be fully reduced: + | + | trying to reduce Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)] + | trying to reduce Reverse[A *: EmptyTuple.type] + | failed since selector A *: EmptyTuple.type + | matches none of the cases | - | case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)] - | case EmptyTuple => EmptyTuple + | case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)] + | case EmptyTuple => EmptyTuple + | + | longer explanation available when compiling with `-explain` -- [E172] Type Error: tests/neg/i12049.scala:24:20 --------------------------------------------------------------------- 24 |val _ = summon[M[B]] // error | ^ @@ -45,22 +62,33 @@ | Therefore, reduction cannot advance to the remaining case | | case B => String --- Error: tests/neg/i12049.scala:25:26 --------------------------------------------------------------------------------- +-- [E172] Type Error: tests/neg/i12049.scala:25:78 --------------------------------------------------------------------- 25 |val _ = summon[String =:= Last[Int *: Int *: Boolean *: String *: EmptyTuple]] // error - | ^ - | Match type reduction failed since selector EmptyTuple.type - | matches none of the cases + | ^ + | Cannot prove that String =:= Last[EmptyTuple]. + | + | 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 --- Error: tests/neg/i12049.scala:26:29 --------------------------------------------------------------------------------- + | case _ *: _ *: t => Last[t] + | case t *: EmptyTuple => t +-- [E172] Type Error: tests/neg/i12049.scala:26:48 --------------------------------------------------------------------- 26 |val _ = summon[(A, B, A) =:= Reverse[(A, B, A)]] // error - | ^ - | Match type reduction failed since selector A *: EmptyTuple.type - | matches none of the cases + | ^ + | Cannot prove that (A, B, A) =:= Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)]. + | + | Note: a match type could not be fully reduced: + | + | trying to reduce Tuple.Concat[Reverse[A *: EmptyTuple.type], (B, A)] + | trying to reduce Reverse[A *: EmptyTuple.type] + | failed since selector A *: EmptyTuple.type + | matches none of the cases | - | case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)] - | case EmptyTuple => EmptyTuple + | case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)] + | case EmptyTuple => EmptyTuple -- [E008] Not Found Error: tests/neg/i12049.scala:28:21 ---------------------------------------------------------------- 28 |val _ = (??? : M[B]).length // error | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/neg/i13757-match-type-anykind.scala b/tests/neg/i13757-match-type-anykind.scala index d8273e546dab..a80e8b2b289b 100644 --- a/tests/neg/i13757-match-type-anykind.scala +++ b/tests/neg/i13757-match-type-anykind.scala @@ -1,16 +1,16 @@ object Test: - type AnyKindMatchType1[X <: AnyKind] = X match // error: the scrutinee of a match type cannot be higher-kinded // error + type AnyKindMatchType1[X <: AnyKind] = X match // error: the scrutinee of a match type cannot be higher-kinded case Option[a] => Int type AnyKindMatchType2[X <: AnyKind] = X match // error: the scrutinee of a match type cannot be higher-kinded case Option => Int // error: Missing type parameter for Option - type AnyKindMatchType3[X <: AnyKind] = X match // error: the scrutinee of a match type cannot be higher-kinded // error + type AnyKindMatchType3[X <: AnyKind] = X match // error: the scrutinee of a match type cannot be higher-kinded case _ => Int - type AnyKindMatchType4[X <: Option] = X match // error // error: the scrutinee of a match type cannot be higher-kinded // error + type AnyKindMatchType4[X <: Option] = X match // error // error: the scrutinee of a match type cannot be higher-kinded case _ => Int - type AnyKindMatchType5[X[_]] = X match // error: the scrutinee of a match type cannot be higher-kinded // error + type AnyKindMatchType5[X[_]] = X match // error: the scrutinee of a match type cannot be higher-kinded case _ => Int end Test diff --git a/tests/neg/i19949.scala b/tests/neg/i19949.scala new file mode 100644 index 000000000000..96a22e42e079 --- /dev/null +++ b/tests/neg/i19949.scala @@ -0,0 +1,9 @@ + +trait T[N]: + type M = N match + case 0 => Any + +val t: T[Double] = new T[Double] {} +val x: t.M = "hello" // error + +val z: T[Double]#M = "hello" // error diff --git a/tests/neg/matchtype-seq.check b/tests/neg/matchtype-seq.check index 9c37fc08c4df..3344a9562809 100644 --- a/tests/neg/matchtype-seq.check +++ b/tests/neg/matchtype-seq.check @@ -1,19 +1,35 @@ --- Error: tests/neg/matchtype-seq.scala:9:11 --------------------------------------------------------------------------- +-- [E007] Type Mismatch Error: tests/neg/matchtype-seq.scala:9:18 ------------------------------------------------------ 9 | identity[T1[3]]("") // error - | ^ - | Match type reduction failed since selector (3 : Int) - | matches none of the cases + | ^^ + | Found: ("" : String) + | Required: Test.T1[(3 : Int)] | - | case (1 : Int) => Int - | case (2 : Int) => String --- Error: tests/neg/matchtype-seq.scala:10:11 -------------------------------------------------------------------------- + | Note: a match type could not be fully reduced: + | + | trying to reduce Test.T1[(3 : Int)] + | failed since selector (3 : Int) + | matches none of the cases + | + | case (1 : Int) => Int + | case (2 : Int) => String + | + | longer explanation available when compiling with `-explain` +-- [E007] Type Mismatch Error: tests/neg/matchtype-seq.scala:10:18 ----------------------------------------------------- 10 | identity[T1[3]](1) // error - | ^ - | Match type reduction failed since selector (3 : Int) - | matches none of the cases + | ^ + | Found: (1 : Int) + | Required: Test.T1[(3 : Int)] | - | case (1 : Int) => Int - | case (2 : Int) => String + | Note: a match type could not be fully reduced: + | + | trying to reduce Test.T1[(3 : Int)] + | failed since selector (3 : Int) + | matches none of the cases + | + | case (1 : Int) => Int + | case (2 : Int) => String + | + | longer explanation available when compiling with `-explain` -- [E007] Type Mismatch Error: tests/neg/matchtype-seq.scala:11:20 ----------------------------------------------------- 11 | identity[T1[Int]]("") // error | ^^ diff --git a/tests/pos/i19950.scala b/tests/pos/i19950.scala new file mode 100644 index 000000000000..349140f43ff5 --- /dev/null +++ b/tests/pos/i19950.scala @@ -0,0 +1,10 @@ + +trait Apply[F[_]]: + extension [T <: NonEmptyTuple](tuple: T)(using toMap: Tuple.IsMappedBy[F][T]) + def mapN[B](f: Tuple.InverseMap[T, F] => B): F[B] = ??? + +given Apply[Option] = ??? +given Apply[List] = ??? +given Apply[util.Try] = ??? + +@main def Repro = (Option(1), Option(2), Option(3)).mapN(_ + _ + _) \ No newline at end of file diff --git a/tests/neg/12974.scala b/tests/warn/12974.scala similarity index 94% rename from tests/neg/12974.scala rename to tests/warn/12974.scala index 90edcc916471..45029602296f 100644 --- a/tests/neg/12974.scala +++ b/tests/warn/12974.scala @@ -23,7 +23,7 @@ object RecMap { def main(args: Array[String]) = import Record._ - val foo: Any = Rec.empty.fetch("foo") // error + val foo: Any = Rec.empty.fetch("foo") // TODO // ^ // Match type reduction failed since selector EmptyTuple.type // matches none of the cases