Skip to content

Commit 59054b0

Browse files
committed
Fix variance for match types in type maps and type accumulators
1 parent 75481ef commit 59054b0

File tree

5 files changed

+71
-8
lines changed

5 files changed

+71
-8
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,12 @@ class Definitions {
943943
case _ =>
944944
None
945945
}
946+
def isInstance(tp: Type)(implicit ctx: Context): Boolean = tp match {
947+
case AppliedType(tycon: TypeRef, _) =>
948+
tycon.name == tpnme.MatchCase && // necessary pre-filter to avoid forcing symbols
949+
tycon.isRef(MatchCaseClass)
950+
case _ => false
951+
}
946952
}
947953

948954
/** An extractor for multi-dimensional arrays.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ object StdNames {
337337
val Literal: N = "Literal"
338338
val LiteralAnnotArg: N = "LiteralAnnotArg"
339339
val longHash: N = "longHash"
340+
val MatchCase: N = "MatchCase"
340341
val Modifiers: N = "Modifiers"
341342
val NestedAnnotArg: N = "NestedAnnotArg"
342343
val NoFlags: N = "NoFlags"

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4417,10 +4417,12 @@ object Types {
44174417

44184418
case tp: LambdaType =>
44194419
def mapOverLambda = {
4420-
variance = -variance
4420+
val restpe = tp.resultType
4421+
val saved = variance
4422+
variance = if (defn.MatchCase.isInstance(restpe)) 0 else -variance
44214423
val ptypes1 = tp.paramInfos.mapConserve(this).asInstanceOf[List[tp.PInfo]]
4422-
variance = -variance
4423-
derivedLambdaType(tp)(ptypes1, this(tp.resultType))
4424+
variance = saved
4425+
derivedLambdaType(tp)(ptypes1, this(restpe))
44244426
}
44254427
mapOverLambda
44264428

@@ -4440,7 +4442,9 @@ object Types {
44404442
derivedOrType(tp, this(tp.tp1), this(tp.tp2))
44414443

44424444
case tp: MatchType =>
4443-
derivedMatchType(tp, this(tp.bound), this(tp.scrutinee), tp.cases.mapConserve(this))
4445+
val bound1 = this(tp.bound)
4446+
val scrut1 = atVariance(0)(this(tp.scrutinee))
4447+
derivedMatchType(tp, bound1, scrut1, tp.cases.mapConserve(this))
44444448

44454449
case tp: SkolemType =>
44464450
derivedSkolemType(tp, this(tp.info))
@@ -4804,10 +4808,12 @@ object Types {
48044808
case _: BoundType | _: ThisType => x
48054809

48064810
case tp: LambdaType =>
4807-
variance = -variance
4811+
val restpe = tp.resultType
4812+
val saved = variance
4813+
variance = if (defn.MatchCase.isInstance(restpe)) 0 else -variance
48084814
val y = foldOver(x, tp.paramInfos)
4809-
variance = -variance
4810-
this(y, tp.resultType)
4815+
variance = saved
4816+
this(y, restpe)
48114817

48124818
case tp: TermRef =>
48134819
if (stopAtStatic && tp.currentSymbol.isStatic || (tp.prefix `eq` NoPrefix)) x
@@ -4835,7 +4841,9 @@ object Types {
48354841
this(this(x, tp.tp1), tp.tp2)
48364842

48374843
case tp: MatchType =>
4838-
foldOver(this(this(x, tp.bound), tp.scrutinee), tp.cases)
4844+
val x1 = this(x, tp.bound)
4845+
val x2 = atVariance(0)(this(x1, tp.scrutinee))
4846+
foldOver(x2, tp.cases)
48394847

48404848
case AnnotatedType(underlying, annot) =>
48414849
this(applyToAnnot(x, annot), underlying)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package scala.internal
2+
3+
/** A type constructor for a case in a match type.
4+
*/
5+
final abstract class MatchCase[Pat, +Body]

tests/neg/i6047.scala

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
type Id[+X] = X match { // error: covariant type X appears in nonvariant position
2+
case Int => Int
3+
case String => String
4+
}
5+
type T1[+X, Y] = Y match { // error: covariant type X appears in nonvariant position
6+
case List[X] => Int
7+
case _ => String
8+
}
9+
type T2[+X, Y] = Y match { // error: covariant type X appears in nonvariant position
10+
case List[_ >: X] => Int
11+
case _ => String
12+
}
13+
type T3[+X, Y] = Y match { // error: covariant type X appears in nonvariant position
14+
case List[_ <: X] => Int
15+
case _ => String
16+
}
17+
type Id2[-X] = X match { // error: contravariant type X appears in nonvariant position
18+
case Int => Int
19+
case String => String
20+
}
21+
type T4[+X, Y] = Y match { // error: contravariant type X appears in nonvariant position
22+
case List[X] => Int
23+
case _ => String
24+
}
25+
type T5[+X, Y] = Y match { // error: contravariant type X appears in nonvariant position
26+
case List[_ >: X] => Int
27+
case _ => String
28+
}
29+
type T6[+X, Y] = Y match { // error: contravariant type X appears in nonvariant position
30+
case List[_ <: X] => Int
31+
case _ => String
32+
}
33+
type T7[-X, Y] = Y match { // error: contravariant type X appears in covariant position
34+
case List[_] => X
35+
case _ => String
36+
}
37+
38+
class C[+X] {
39+
type Id = X match {
40+
case Int => Int
41+
case String => String
42+
}
43+
}

0 commit comments

Comments
 (0)