Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport "Update unreducible match types error reporting" to LTS #21024

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Expand Down
61 changes: 4 additions & 57 deletions tests/neg-macros/toexproftuple.scala
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 1 addition & 1 deletion tests/neg/10349.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
3 changes: 2 additions & 1 deletion tests/neg/10747.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
76 changes: 52 additions & 24 deletions tests/neg/i12049.check
Original file line number Diff line number Diff line change
Expand Up @@ -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
| ^
Expand All @@ -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
| ^^^^^^^^^^^^^^^^^^^
Expand Down
8 changes: 4 additions & 4 deletions tests/neg/i13757-match-type-anykind.scala
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions tests/neg/i19949.scala
Original file line number Diff line number Diff line change
@@ -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
40 changes: 28 additions & 12 deletions tests/neg/matchtype-seq.check
Original file line number Diff line number Diff line change
@@ -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
| ^^
Expand Down
10 changes: 10 additions & 0 deletions tests/pos/i19950.scala
Original file line number Diff line number Diff line change
@@ -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(_ + _ + _)
2 changes: 1 addition & 1 deletion tests/neg/12974.scala → tests/warn/12974.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down