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

0 commit comments

Comments
 (0)