Skip to content

Commit 722d4cb

Browse files
committed
Make sure in CI that we do not unexpectedly fall back on legacy match type reduction.
We introduce a new flag `-Yno-legacy-match-types`, which forbids the reduction of "legacy" match types. Like `-Yno-deep-subtypes`, it is meant to be used in our CI. With it, we check that we do not unexpectedly fall back on legacy match types in tests for which the specced match types are enough. Later, we should consider integrating that behavior with the source level so that it reaches users.
1 parent b72458d commit 722d4cb

21 files changed

+119
-4
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ private sealed trait YSettings:
347347
val YprintPos: Setting[Boolean] = BooleanSetting("-Yprint-pos", "Show tree positions.")
348348
val YprintPosSyms: Setting[Boolean] = BooleanSetting("-Yprint-pos-syms", "Show symbol definitions positions.")
349349
val YnoDeepSubtypes: Setting[Boolean] = BooleanSetting("-Yno-deep-subtypes", "Throw an exception on deep subtyping call stacks.")
350+
val YnoLegacyMatchTypes: Setting[Boolean] = BooleanSetting("-Yno-legacy-match-types", "Refuse to reduce match types with legacy/unspecified patterns")
350351
val YnoPatmatOpt: Setting[Boolean] = BooleanSetting("-Yno-patmat-opt", "Disable all pattern matching optimizations.")
351352
val YplainPrinter: Setting[Boolean] = BooleanSetting("-Yplain-printer", "Pretty-print using a plain printer.")
352353
val YprintSyms: Setting[Boolean] = BooleanSetting("-Yprint-syms", "When printing trees print info in symbols instead of corresponding info in trees.")

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

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

128+
def legacyPatternText(scrut: Type, cas: MatchTypeCaseSpec.LegacyPatMat)(using Context): String =
129+
i"""Illegal match type because it contains the legacy, unspecifed case
130+
| ${caseText(cas)}"""
131+
128132
end MatchTypeTrace

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,6 +3425,9 @@ class TrackingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
34253425
MatchResult.Stuck
34263426

34273427
def recur(remaining: List[MatchTypeCaseSpec]): Type = remaining match
3428+
case (cas: MatchTypeCaseSpec.LegacyPatMat) :: _ if ctx.settings.YnoLegacyMatchTypes.value =>
3429+
val errorText = MatchTypeTrace.legacyPatternText(scrut, cas)
3430+
ErrorType(reporting.MatchTypeLegacyPattern(errorText))
34283431
case cas :: remaining1 =>
34293432
matchCase(cas) match
34303433
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
@@ -202,6 +202,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
202202
case ImplausiblePatternWarningID // erorNumber: 186
203203
case SynchronizedCallOnBoxedClassID // errorNumber: 187
204204
case VarArgsParamCannotBeGivenID // erorNumber: 188
205+
case MatchTypeLegacyPatternID // errorNumber: 189
205206

206207
def errorNumber = ordinal - 1
207208

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

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

3027+
class MatchTypeLegacyPattern(errorText: String)(using Context) extends TypeMsg(MatchTypeLegacyPatternID):
3028+
def msg(using Context) = errorText
3029+
def explain(using Context) = ""
3030+
30273031
class ClosureCannotHaveInternalParameterDependencies(mt: Type)(using Context)
30283032
extends TypeMsg(ClosureCannotHaveInternalParameterDependenciesID):
30293033
def msg(using Context) =

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ object TestConfiguration {
1919
val checkOptions = Array(
2020
// "-Yscala2-unpickler", s"${Properties.scalaLibrary}",
2121
"-Yno-deep-subtypes",
22+
"-Yno-legacy-match-types",
2223
"-Yno-double-bindings",
2324
"-Yforce-sbt-phases",
2425
"-Xsemanticdb",

tests/neg/6570.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// scalac: -Yno-legacy-match-types:false
2+
13
object Base {
24
trait Trait1
35
trait Trait2

tests/neg/legacy-match-types.check

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- [E189] Type Error: tests/neg/legacy-match-types.scala:7:23 ----------------------------------------------------------
2+
7 |type InvNesting[X] = X match // error
3+
| ^
4+
| Illegal match type because it contains the legacy, unspecifed case
5+
| case Inv[Cov[t]] => t
6+
8 | case Inv[Cov[t]] => t
7+
-- [E189] Type Error: tests/neg/legacy-match-types.scala:10:26 ---------------------------------------------------------
8+
10 |type ContraNesting[X] = X match // error
9+
| ^
10+
| Illegal match type because it contains the legacy, unspecifed case
11+
| case Contra[Cov[t]] => t
12+
11 | case Contra[Cov[t]] => t
13+
-- [E189] Type Error: tests/neg/legacy-match-types.scala:15:22 ---------------------------------------------------------
14+
15 |type AndTypeMT[X] = X match // error
15+
| ^
16+
| Illegal match type because it contains the legacy, unspecifed case
17+
| case t & Seq[Any] => t
18+
16 | case t & Seq[Any] => t
19+
-- [E189] Type Error: tests/neg/legacy-match-types.scala:22:33 ---------------------------------------------------------
20+
22 |type TypeAliasWithBoundMT[X] = X match // error
21+
| ^
22+
| Illegal match type because it contains the legacy, unspecifed case
23+
| case IsSeq[t] => t
24+
23 | case IsSeq[t] => t
25+
-- [E189] Type Error: tests/neg/legacy-match-types.scala:33:34 ---------------------------------------------------------
26+
33 |type TypeMemberExtractorMT[X] = X match // error
27+
| ^
28+
| Illegal match type because it contains the legacy, unspecifed case
29+
| case TypeMemberAux[t] => t
30+
34 | case TypeMemberAux[t] => t

tests/neg/legacy-match-types.scala

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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 a type member refinement to extract the type member
26+
27+
class Base {
28+
type TypeMember
29+
}
30+
31+
type TypeMemberAux[X] = Base { type TypeMember = X }
32+
33+
type TypeMemberExtractorMT[X] = X match // error
34+
case TypeMemberAux[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+
}

0 commit comments

Comments
 (0)