# Cannot widen a HKT parameter with covariant type parameters #11789

Open
opened this issue Oct 31, 2019 · 4 comments
Labels

### neko-kai commented Oct 31, 2019

 Example: ```case class Holder[F[+_, +_]](v: F[Int, Int]) { def asWiden[F2[+x, +y] >: F[x, y]]: F2[Int, Int] = v } object example extends App { println(Holder[Right](Right(5)).asWiden[Either]) }``` Produces error: ``````Error:(4, 16) covariant type x occurs in contravariant position in type [+x, +y] >: F[x,y] of type F2 def asWiden[F2[+x, +y] >: F[x, y]]: F2[Int, Int] = v ^ `````` Expected it to succeed, as the expression does not appear unsound! Writing it as `F2[+x, +y] >: F[_, _]` passes the variance checker, but the expression using the function fails to typecheck: ```Error:(7, 99) type arguments [Either] do not conform to method asWiden's type parameter bounds [F2[+x, +y] >: Right[_, _]] def res0 = Holder[Right](Right(5)).asWiden[Either] ^``` Scala version 2.13.1

### joroKr21 commented Nov 2, 2019

 As all things variance it works when you flip it 😄 ```class Holder[F[-_]] { type G[+x] >: F[x] }``` How could `F[-x]` ever be a subtype of `G[+x]`? Btw minimization: ```class Holder[F[+_]] { type G[+x] >: F[x] }```

### joroKr21 commented Nov 2, 2019

 I guess the difference with dotty is the direct encoding of higher kinds / type lambdas. In Scala we have `PolyType`s with `TypeBounds` as the result type. And in general we flip the variance for lower bounds. This feels hacky but solves this one example. Not sure if sound though: ```--- a/src/reflect/scala/reflect/internal/Variances.scala +++ b/src/reflect/scala/reflect/internal/Variances.scala @@ -125,6 +125,7 @@ trait Variances { def apply(tp: Type): Type = { tp match { case _ if isUncheckedVariance(tp) => + case PolyType(_, TypeBounds(lo, hi)) => this(lo); this(hi) case _ if resultTypeOnly(tp) => this(tp.resultType) case TypeRef(_, sym, _) if shouldDealias(sym) => this(tp.normalize) case TypeRef(_, sym, _) if !sym.variance.isInvariant => checkVarianceOfSymbol(sym) ; tp.mapOver(this)```

### joroKr21 commented Nov 2, 2019

 So in general it's correct to not flip the variance when checking the poly type parameters but the problem is that there are many things (side effects) happening at once and I don't know how to special case it.

### joroKr21 commented Nov 10, 2019

 More weirdness (I don't even know what is supposed to be correct): ```scala> trait Foo[+A] { def foo: { type T <: A } } trait Foo scala> trait Foo[+A] { def foo: { type T >: A } } ^ error: covariant type A occurs in contravariant position in type >: A of type T ^ error: covariant type A occurs in contravariant position in type => AnyRef{type T >: A} of method foo scala> trait Foo[+A] { def foo(x: { type T <: A }): Unit } ^ error: covariant type A occurs in contravariant position in type AnyRef{type T <: A} of value x scala> trait Foo[+A] { def foo(x: { type T >: A }): Unit } ^ error: covariant type A occurs in contravariant position in type >: A of type T scala> trait Foo[+A, x <: { type T <: A }] trait Foo scala> trait Foo[+A, x <: { type T >: A }] ^ error: covariant type A occurs in contravariant position in type <: AnyRef{type T >: A} of type x scala> trait Foo[+A, x <: { type T[_ <: A] }] trait Foo scala> trait Foo[+A, x <: { type T[_ >: A] }] trait Foo```