Skip to content

Commit cbd52f1

Browse files
authored
Merge pull request #9084 from dotty-staging/fix-#9061
Fix #9061: Treat `type F <: [X] => G` like `type F[X] <: G`.
2 parents aff000e + 769e108 commit cbd52f1

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,6 @@ object Variances {
156156
if (v > 0) "+"
157157
else if (v < 0) "-"
158158
else ""
159+
160+
val alwaysInvariant: Any => Invariant.type = Function.const(Invariant)
159161
}

compiler/src/dotty/tools/dotc/typer/Namer.scala

+20-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import util.Spans._
1515
import util.Property
1616
import collection.mutable
1717
import tpd.ListOfTreeDecorator
18+
import Variances.alwaysInvariant
1819
import config.{Config, Feature}
1920
import config.Printers.typr
2021
import Annotations._
@@ -968,7 +969,10 @@ class Namer { typer: Typer =>
968969
override final def typeSig(sym: Symbol): Type =
969970
val tparamSyms = completerTypeParams(sym)(ictx)
970971
given ctx as Context = nestedCtx
971-
def abstracted(tp: TypeBounds): TypeBounds = HKTypeLambda.boundsFromParams(tparamSyms, tp)
972+
973+
def abstracted(tp: TypeBounds): TypeBounds =
974+
HKTypeLambda.boundsFromParams(tparamSyms, tp)
975+
972976
val dummyInfo1 = abstracted(TypeBounds.empty)
973977
sym.info = dummyInfo1
974978
sym.setFlag(Provisional)
@@ -998,8 +1002,22 @@ class Namer { typer: Typer =>
9981002
}
9991003
sym.info = dummyInfo2
10001004

1005+
// Treat the parameters of an upper type lambda bound on the RHS as non-variant.
1006+
// E.g. type F <: [X] =>> G and type F[X] <: G
1007+
// are treated alike.
1008+
def addVariances(tp: Type): Type = tp match
1009+
case tp: TypeBounds =>
1010+
def recur(tp: Type): Type = tp match
1011+
case tp: HKTypeLambda if !tp.isDeclaredVarianceLambda =>
1012+
tp.withVariances(tp.paramNames.map(alwaysInvariant))
1013+
.derivedLambdaType(resType = recur(tp.resType))
1014+
case tp => tp
1015+
tp.derivedTypeBounds(tp.lo, recur(tp.hi))
1016+
case _ =>
1017+
tp
1018+
10011019
val rhs1 = typedAheadType(rhs)
1002-
val rhsBodyType: TypeBounds = rhs1.tpe.toBounds
1020+
val rhsBodyType: TypeBounds = addVariances(rhs1.tpe).toBounds
10031021
val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType)
10041022

10051023
def opaqueToBounds(info: Type): Type =

compiler/src/dotty/tools/dotc/util/common.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import core.Types.WildcardType
66
/** Common values hoisted out for performance */
77
object common {
88

9-
val alwaysTrue: Any => Boolean = Function.const(true) _
10-
val alwaysFalse: Any => Boolean = Function.const(false) _
11-
val alwaysZero: Any => Int = Function.const(0) _
12-
val alwaysWildcardType: Any => WildcardType.type = Function.const(WildcardType) _
9+
val alwaysTrue: Any => Boolean = Function.const(true)
10+
val alwaysFalse: Any => Boolean = Function.const(false)
11+
val alwaysZero: Any => Int = Function.const(0)
12+
val alwaysWildcardType: Any => WildcardType.type = Function.const(WildcardType)
1313
}

tests/neg/i9061.scala

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
case class Contra[-A](f: A => Int)
2+
3+
case class Covarify[+F <: ([A] =>> Any), +A](fa: F[A]) // error: covariant type A occurs in invariant position in type F[A] of value fa
4+
case class Covarify2[+F[+X] <: ([A] =>> Any), +A](fa: F[Int][A]) // error: covariant type A occurs in invariant position in type F[A] of value fa
5+
case class Covarify3[+F <: [X] =>> [A] =>> Any, +A](fa: F[Int][A]) // error: covariant type A occurs in invariant position in type F[A] of value fa
6+
7+
@main def main = {
8+
val x = Covarify[Contra, Int](Contra[Int](_ + 5))
9+
val y: Covarify[Contra, Any] = x
10+
println(y.fa.f("abc"))
11+
}

0 commit comments

Comments
 (0)