-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Variance checking is inconsistent when using curried type operators #6369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The minimised version of this one looks funny. All the lines with type lambdas below fail: trait A[-X]
type A0[-X] = [_ >: X] => A[X]
type A1[-X] = [_[_ <: X]] => A[X]
type A2[-X] = [_[_[_ >: X]]] => A[X]
type A3[-X] = [_[_[_[_ <: X]]]] => A[X]
type A4[-X] = [_[_[_[_[_ >: X]]]]] => A[X]
type A5[-X] = [_[_[_[_[_[_ <: X]]]]]] => A[X]
trait B[+X]
type B0[+X] = [_ <: X] => B[X]
type B1[+X] = [_[_ >: X]] => B[X]
type B2[+X] = [_[_[_ <: X]]] => B[X]
type B3[+X] = [_[_[_[_ >: X]]]] => B[X]
type B4[+X] = [_[_[_[_[_ <: X]]]]] => B[X]
type B5[+X] = [_[_[_[_[_[_ >: X]]]]]] => B[X] All the code below succeeds: trait A[-X]
type A0[-X] = [_ <: X] => A[X]
type A1[-X] = [_[_ >: X]] => A[X]
type A2[-X] = [_[_[_ <: X]]] => A[X]
type A3[-X] = [_[_[_[_ >: X]]]] => A[X]
type A4[-X] = [_[_[_[_[_ <: X]]]]] => A[X]
type A5[-X] = [_[_[_[_[_[_ >: X]]]]]] => A[X]
trait B[+X]
type B0[+X] = [_ >: X] => B[X]
type B1[+X] = [_[_ <: X]] => B[X]
type B2[+X] = [_[_[_ >: X]]] => B[X]
type B3[+X] = [_[_[_[_ <: X]]]] => B[X]
type B4[+X] = [_[_[_[_[_ >: X]]]]] => B[X]
type B5[+X] = [_[_[_[_[_[_ <: X]]]]]] => B[X] |
I think this is not a bug. Further minimised: type Co0 = [+X] => [_ <: X] => Any
type Co1 = [+X, _ <: X] => Any
type Co2 = [+X, _ >: X <: X] => Any
type Co3 = [+X] => [_ >: X <: X] => Any
type Contra0 = [-X] => [_ >: X] => Any
type Contra1 = [-X, _ >: X] => Any
type Contra2 = [-X, _ >: X <: X] => Any
type Contra3 = [-X] => [_ >: X <: X] => Any Output: -- Error: ../issues/i6369/Sample.scala:1:13 ------------------------------------
1 |type Co0 = [+X] => [_ <: X] => Any
| ^^
|covariant type parameter X occurs in contravariant position in [_$1 <: X] => Any
-- Error: ../issues/i6369/Sample.scala:4:13 ------------------------------------
4 |type Co3 = [+X] => [_ >: X <: X] => Any
| ^^
|covariant type parameter X occurs in invariant position in [_$4 >: X <: X] => Any
-- Error: ../issues/i6369/Sample.scala:6:17 ------------------------------------
6 |type Contra0 = [-X] => [_ >: X] => Any
| ^^
|contravariant type parameter X occurs in covariant position in [_$5 >: X] => Any
-- Error: ../issues/i6369/Sample.scala:9:17 ------------------------------------
9 |type Contra3 = [-X] => [_ >: X <: X] => Any
| ^^
|contravariant type parameter X occurs in invariant position in [_$8 >: X <: X] => Any The complaints are about the occurrence of the argument to the type lambda in the type bounds of the argument to the curried lambda. It makes sense for the compiler to enforce variance checks in a curried lambda scenario since one may, e.g., call type F = [+X] => [_ <: X] => Any
type C1 = F[Any ] //= [_ <: Any ] => Any
type C2 = F[Nothing] //= [_ <: Nothing] => Any Above, C1[String] - ok
C2[String] – not ok Variance checks do not need to be enforced with non-curried lambdas since AFAIK there is no mechanics to provide arguments partially: type Co1 = [+X, _ <: X] => Any Above, we can't construct a type without providing both arguments. Hence the compiler does not need to make judgements about the subtyping of The above reasoning, however, has an implication that curried lambdas are not equivalent to non-curried lambdas when variance comes into play. I'm not sure whether this is wrong or plausible, probably a theoretical input is needed here. Also I'm not sure how this reasoning plays with:
@sstucki can you please elaborate? Regarding my previous post, the type F[-X]
type G[+X] = F[F[X↓]↑]↓ When |
That's not how subtyping works. The rule of thumb is that, if type LowerBounded[X >: Any] = X
type Test1 = LowerBounded[Any] // OK
type Test2 = LowerBounded[Int] // fails The actual rule for comparing type functions is that Here's an analogy from mathematics. Consider the two functions There is a related discussion about this in #6320 – you may wanna have a look at that.
This may well be the reason why variance checks are not implemented for uncurried functions in the compiler, but it doesn't change the rules of subtyping, which should be the same for curried and uncurried definitions. Even if there is no special syntax for partial type application, I can partially apply a type explicitly via a type lambda type Co1 = [+X, _ <: X] => Any
type Co1Any[Y <: Any] = Co1[Any, Y]
type Co1Nothing[Y <: Nothing] = Co1[Any, Nothing] And because these are all constant functions,
In a nutshell, As in Scala, there is no syntax in F-<: for partially applying
and show that
Let me know if that answers your question. |
Thanks for the detailed explanations! So basically the type lambdas are compared by their output ranges, point-wise, and not by their input domains? Hence if the input domain of one lambda includes the input domain of another lambda, this won't influence the subtyping of the two lambdas, since we are comparing only their output ranges and only for the inputs they both can accept? Hence, do you think we should not perform the variance checking for the type bounds of the arguments to type lambdas? Since the bounds do not participate in the subtyping rules for the type lambdas? |
@anatoliykmetyuk: sorry for the late reply.
Correct. This is how it should be IMO, but AFAIK, it's not what's currently implemented. See #6320 for a related discussion.
The honest answer is: I don't know. We're lacking a full theory of variance checking in the presence of lambdas with type bounds (it has not yet been developed). IMO, it probably does not make sense to try and fix this issue until we have such a theory. If you want to attempt a fix anyway, then my current best guess is that variance checking is probably not needed in arguments to type lambdas. But again, that's just a guess (based on the intuition given above). |
We don't allow curried variance annotations anymore. |
Dotty reports errors for some of the curried type operators defined below, but not for their uncurried versions.
I think this is a variant of #6320 but this time triggered by variance annotations instead of bounds. Similar issues were already discussed in #1252.
I'm pretty sure that the errors are false positives (the uncurried versions are safe, and so are the curried ones). The problem is that we still lack a full theory of dependent higher-order subtyping with variances annotations, so it's difficult to know for sure.
For the first case (
AllCurried
), I'm convinced there should not be an error though. That case is simply an encoding of bounded universal quantification and we know that the specified variances are sound (from the corresponding typing rule of full F<:) .The text was updated successfully, but these errors were encountered: