Skip to content

Commit cc6edf4

Browse files
committed
Fix #9061: Treat type F <: [X] => G like type F[X] <: G.
1 parent 0540e5e commit cc6edf4

File tree

4 files changed

+33
-6
lines changed

4 files changed

+33
-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

+18-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,20 @@ class Namer { typer: Typer =>
9981002
}
9991003
sym.info = dummyInfo2
10001004

1005+
// If this type does not have type parameters itself, treat the parameters
1006+
// of a type lambda on the RHS as non-variant. E.g.
1007+
// type F <: [X] =>> G and type F[X] <: G
1008+
// are treated alike.
1009+
def addVariances(tp: Type): Type = tp match
1010+
case tp @ TypeBounds(lo, hi) =>
1011+
tp.derivedTypeBounds(addVariances(lo), addVariances(hi))
1012+
case tp: HKTypeLambda if tparamSyms.isEmpty && !tp.isDeclaredVarianceLambda =>
1013+
tp.withVariances(tp.paramNames.map(alwaysInvariant))
1014+
case _ =>
1015+
tp
1016+
10011017
val rhs1 = typedAheadType(rhs)
1002-
val rhsBodyType: TypeBounds = rhs1.tpe.toBounds
1018+
val rhsBodyType: TypeBounds = addVariances(rhs1.tpe).toBounds
10031019
val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType)
10041020

10051021
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

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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+
5+
@main def main = {
6+
val x = Covarify[Contra, Int](Contra[Int](_ + 5))
7+
val y: Covarify[Contra, Any] = x
8+
println(y.fa.f("abc"))
9+
}

0 commit comments

Comments
 (0)