5
votes

In Scala 2.10.4 this compiles:

trait Foo[-U,T]{
  type Contra = U
}

but in 2.11.0 the same fails with:

contravariant type U occurs in invariant position in type U of type Contra trait Foo[-U,T] {type Contra = U}

Is there a workaround available? Trying to port over a Scala library to 2.11 and the contravariant type is required in order to get a boatload of implicit defs picked up by the compiler (i.e. making U invariant doesn't seem to be an option).

Thanks

2
Could you explain more about how you use the type member and contravariance to control implicit resolution? I'd be interested in hearing more about this, and maybe there is a workaround somewhere deeper in the problem.wingedsubmariner
Can you use type Contra >: U?n. 1.8e9-where's-my-share m.
@n.m. I cannot use Contra >: U as the instances that depend on U expect a U and not a supertype of U (i.e. when trying this approach compiler blows up saying that method X is not a member of Contra)virtualeyes
@wingedsubmariner U is required to be a contravariant type argument to Foo, but then U is a covariant type in implicit evidence used throughout the library. Basically Contra must equal exactly U within Foo, but be seen as contra/covariant everywhere else. The quick & dirty for 2.11 is @uncheckedVariancevirtualeyes
But you can pass some supertype of U to classes that extend Foo , which is exactly the same situation.n. 1.8e9-where's-my-share m.

2 Answers

4
votes

I can't imagine there being a work around available. The reason I say this is all about supporting path-dependent types:

 def foo[T <: Foo[A,B]](that: T): that.Contra

which places the Contra type in the wrong position. You can not return a contravariant type as a result of an operation. Perhaps the search and validation of these requires so much work that the compiler authors decided this small corner case created too much of a burden or it is a compiler bug that you've uncovered.

By the way, this is just wild speculation on my part. I'd have to read the compiler code to figure out which way is which.

4
votes

Apparently post-2.7 and pre-2.11 this was a bug in the type checker. Now the prevention of approach in OP is a feature, which is a good thing, kind of o_O

The workaround is to do as one did pre-2.11, the difference being that now you know you're on your own, vs. before where you thought the compiler had your back.

Ignorance is bliss, right?

The workaround:

import annotation.unchecked._
trait Foo[-U,T]{
  type Contra = (U @uncheckedVariance)
}