Skip to content

Commit 7ab7b0f

Browse files
committed
Report a compile error on illegal match types.
The error can be silenced with `-source:3.3`. In that case, illegal match types are reduced using the legacy matching algorithm, as before.
1 parent 97725d7 commit 7ab7b0f

19 files changed

+139
-5
lines changed

compiler/src/dotty/tools/dotc/core/MatchTypeTrace.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,9 @@ object MatchTypeTrace:
125125
|
126126
| ${casesText(cases)}"""
127127

128+
def illegalPatternText(scrut: Type, cas: MatchTypeCaseSpec.LegacyPatMat)(using Context): String =
129+
i"""The match type contains an illegal case:
130+
| ${caseText(cas)}
131+
|(this error can be ignored for now with `-source:3.3`)"""
132+
128133
end MatchTypeTrace

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import TypeOps.refineUsingParent
1010
import collection.mutable
1111
import util.{Stats, NoSourcePosition, EqHashMap}
1212
import config.Config
13-
import config.Feature.migrateTo3
13+
import config.Feature.{migrateTo3, sourceVersion}
1414
import config.Printers.{subtyping, gadts, matchTypes, noPrinter}
15+
import config.SourceVersion
1516
import TypeErasure.{erasedLub, erasedGlb}
1617
import TypeApplications.*
1718
import Variances.{Variance, variancesConform}
@@ -3467,6 +3468,9 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
34673468
MatchResult.Stuck
34683469

34693470
def recur(remaining: List[MatchTypeCaseSpec]): Type = remaining match
3471+
case (cas: MatchTypeCaseSpec.LegacyPatMat) :: _ if sourceVersion.isAtLeast(SourceVersion.`3.4`) =>
3472+
val errorText = MatchTypeTrace.illegalPatternText(scrut, cas)
3473+
ErrorType(reporting.MatchTypeLegacyPattern(errorText))
34703474
case cas :: remaining1 =>
34713475
matchCase(cas) match
34723476
case MatchResult.Disjoint =>

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
204204
case VarArgsParamCannotBeGivenID // errorNumber: 188
205205
case ExtractorNotFoundID // errorNumber: 189
206206
case PureUnitExpressionID // errorNumber: 190
207+
case MatchTypeLegacyPatternID // errorNumber: 191
207208

208209
def errorNumber = ordinal - 1
209210

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,6 +3073,10 @@ class MatchTypeScrutineeCannotBeHigherKinded(tp: Type)(using Context)
30733073
def msg(using Context) = i"the scrutinee of a match type cannot be higher-kinded"
30743074
def explain(using Context) = ""
30753075

3076+
class MatchTypeLegacyPattern(errorText: String)(using Context) extends TypeMsg(MatchTypeLegacyPatternID):
3077+
def msg(using Context) = errorText
3078+
def explain(using Context) = ""
3079+
30763080
class ClosureCannotHaveInternalParameterDependencies(mt: Type)(using Context)
30773081
extends TypeMsg(ClosureCannotHaveInternalParameterDependenciesID):
30783082
def msg(using Context) =

tests/neg/6570.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
object Base {
24
trait Trait1
35
trait Trait2

tests/neg/illegal-match-types.check

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
-- [E191] Type Error: tests/neg/illegal-match-types.scala:7:23 ---------------------------------------------------------
2+
7 |type InvNesting[X] = X match // error
3+
| ^
4+
| The match type contains an illegal case:
5+
| case Inv[Cov[t]] => t
6+
| (this error can be ignored for now with `-source:3.3`)
7+
8 | case Inv[Cov[t]] => t
8+
-- [E191] Type Error: tests/neg/illegal-match-types.scala:10:26 --------------------------------------------------------
9+
10 |type ContraNesting[X] = X match // error
10+
| ^
11+
| The match type contains an illegal case:
12+
| case Contra[Cov[t]] => t
13+
| (this error can be ignored for now with `-source:3.3`)
14+
11 | case Contra[Cov[t]] => t
15+
-- [E191] Type Error: tests/neg/illegal-match-types.scala:15:22 --------------------------------------------------------
16+
15 |type AndTypeMT[X] = X match // error
17+
| ^
18+
| The match type contains an illegal case:
19+
| case t & Seq[Any] => t
20+
| (this error can be ignored for now with `-source:3.3`)
21+
16 | case t & Seq[Any] => t
22+
-- [E191] Type Error: tests/neg/illegal-match-types.scala:22:33 --------------------------------------------------------
23+
22 |type TypeAliasWithBoundMT[X] = X match // error
24+
| ^
25+
| The match type contains an illegal case:
26+
| case IsSeq[t] => t
27+
| (this error can be ignored for now with `-source:3.3`)
28+
23 | case IsSeq[t] => t
29+
-- [E191] Type Error: tests/neg/illegal-match-types.scala:29:34 --------------------------------------------------------
30+
29 |type TypeMemberExtractorMT[X] = X match // error
31+
| ^
32+
| The match type contains an illegal case:
33+
| case TypeMemberAux[t] => t
34+
| (this error can be ignored for now with `-source:3.3`)
35+
30 | case TypeMemberAux[t] => t
36+
-- [E191] Type Error: tests/neg/illegal-match-types.scala:40:35 --------------------------------------------------------
37+
40 |type TypeMemberExtractorMT2[X] = X match // error
38+
| ^
39+
| The match type contains an illegal case:
40+
| case TypeMemberAux2[t] => t
41+
| (this error can be ignored for now with `-source:3.3`)
42+
41 | case TypeMemberAux2[t] => t

tests/neg/illegal-match-types.scala

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
class Inv[T]
2+
class Cov[+T]
3+
class Contra[-T]
4+
5+
// Nesting captures in non-covariant position
6+
7+
type InvNesting[X] = X match // error
8+
case Inv[Cov[t]] => t
9+
10+
type ContraNesting[X] = X match // error
11+
case Contra[Cov[t]] => t
12+
13+
// Intersection type to type-test and capture at the same time
14+
15+
type AndTypeMT[X] = X match // error
16+
case t & Seq[Any] => t
17+
18+
// Poly type alias with a bound to type-test and capture at the same time
19+
20+
type IsSeq[X <: Seq[Any]] = X
21+
22+
type TypeAliasWithBoundMT[X] = X match // error
23+
case IsSeq[t] => t
24+
25+
// Poly type alias with an unknown type member refinement
26+
27+
type TypeMemberAux[X] = { type TypeMember = X }
28+
29+
type TypeMemberExtractorMT[X] = X match // error
30+
case TypeMemberAux[t] => t
31+
32+
// Poly type alias with a refined member of stronger bounds than in the parent
33+
34+
class Base {
35+
type TypeMember
36+
}
37+
38+
type TypeMemberAux2[X <: Seq[Any]] = Base { type TypeMember = X }
39+
40+
type TypeMemberExtractorMT2[X] = X match // error
41+
case TypeMemberAux2[t] => t
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
trait Monoidal {
2+
type to[_] <: Tuple
3+
}
4+
5+
object eithers extends Monoidal {
6+
class Wrap[T]
7+
8+
type to[t] <: Tuple = Wrap[t] match {
9+
case Wrap[Nothing] => EmptyTuple
10+
case Wrap[other] => other match
11+
case Either[hd, tl] => hd *: to[tl]
12+
}
13+
}

tests/pos/10747-shapeless-min.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
trait Monoidal {
24
type to[_] <: Tuple
35
}

tests/pos/8647.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
final class Two[A, B]()
24

35
final class Blaaa

tests/pos/9757.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
type RemoveFrom[R, A] = R match {
24
case A & newType => newType
35
}

tests/pos/i10242.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// https://github.com/lampepfl/dotty/issues/10242
1+
//> using options -source:3.3
2+
3+
// https://github.com/lampepfl/dotty/issues/10242
24
type Foo[A, B <: A] = A
35

46
type Bar[A] = A match {

tests/pos/i15155.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
import scala.reflect.ClassTag
24
// https://github.com/json4s/json4s/blob/355d8751391773e0d79d04402a4f9fb7bfc684ec/ext/src/main/scala-3/org/json4s/ext/package.scala#L4-L8
35
type Aux[A] = { type Value = A }
@@ -8,4 +10,4 @@ type EnumValue[A <: Enumeration] = A match {
810
// https://github.com/json4s/json4s/blob/355d8751391773e0d79d04402a4f9fb7bfc684ec/ext/src/main/scala/org/json4s/ext/EnumSerializer.scala#L25-L26
911
class EnumSerializer[E <: Enumeration: ClassTag](enumeration: E) {
1012
val EnumerationClass = classOf[EnumValue[E]]
11-
}
13+
}

tests/pos/i16408.min1.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
object Helpers:
24
type NodeFun[R] = Matchable // compiles without [R] parameter
35

tests/pos/i16408.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
import scala.util.Try
24

35
trait RDF:

tests/pos/i16706.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
import scala.deriving.Mirror
24
import scala.reflect.ClassTag
35

@@ -14,4 +16,4 @@ transparent inline given derived[A](
1416
sealed trait Foo
1517
case class FooA(a: Int) extends Foo
1618

17-
val instance = derived[Foo] // error
19+
val instance = derived[Foo] // error

tests/pos/i17395.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
trait TC[T]
24

35
object TC {

tests/pos/i5625b.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
object Test {
24

35
type AV[t <: AnyVal] = t
@@ -13,4 +15,4 @@ object Test {
1315
summon[LeafElem[Array[Int]] =:= Int]
1416
summon[LeafElem[Iterable[Int]] =:= Int]
1517
summon[LeafElem[Int] =:= Int]
16-
}
18+
}

tests/run-macros/tasty-simplified/quoted_2.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//> using options -source:3.3
2+
13
import Macros.simplified
24

35
object Test {

0 commit comments

Comments
 (0)