diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index af495ee1cacc..582c41a2a950 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -579,10 +579,15 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w val saved = comparedTypeLambdas comparedTypeLambdas += tp1 comparedTypeLambdas += tp2 - try - variancesConform(tp1.typeParams, tp2.typeParams) && - boundsOK && - isSubType(tp1.resType, tp2.resType.subst(tp2, tp1)) + val variancesOK = + variancesConform(tp1.typeParams, tp2.typeParams) + || { // if tp1 is of the form [X] =>> C[X] where `C` is co- or contra-variant + // assume the variance of `C` for `tp1` instead. Fixes #7648. + tp1 match + case EtaExpansion(tycon1) => variancesConform(tycon1.typeParams, tp2.typeParams) + case _ => false + } + try variancesOK && boundsOK && isSubType(tp1.resType, tp2.resType.subst(tp2, tp1)) finally comparedTypeLambdas = saved case _ => val tparams1 = tp1.typeParams diff --git a/tests/neg/tcpoly_typealias.scala b/tests/neg/tcpoly_typealias.scala index 6c7f80cc0bdf..02861199a40a 100644 --- a/tests/neg/tcpoly_typealias.scala +++ b/tests/neg/tcpoly_typealias.scala @@ -34,7 +34,7 @@ trait BOk4 extends A3 { // does type alias signature (not considering RHS) correspond to abstract type member in super class // does RHS correspond to the type alias sig trait BInv extends A{ - type m[x] = FooCov[x] // error: invariant x in alias def + type m[x] = FooCov[x] // was an error: invariant x in alias def, now ok, since `FooCov` is covariant } trait BCon extends A{ diff --git a/tests/pos/i7648.scala b/tests/pos/i7648.scala new file mode 100644 index 000000000000..13dd1376c9e5 --- /dev/null +++ b/tests/pos/i7648.scala @@ -0,0 +1,18 @@ +package i7648 + +class IO[+A] + +trait Functor[F[_]] +trait Monad[F[_]] extends Functor[F] + +class Stream[+F[_], +A] { + def take[F1[x] >: F[x]](n: Int)(implicit f: Functor[F1]): Stream[F1, A] = { + this + } +} + +object Test with + + implicit val ioMonad: Monad[IO] = null + + val x = new Stream[IO, Int].take[IO](10)