Skip to content

Partial application of bounded type operator fails bounds check #9695

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

Open
sstucki opened this issue Sep 1, 2020 · 3 comments
Open

Partial application of bounded type operator fails bounds check #9695

sstucki opened this issue Sep 1, 2020 · 3 comments
Labels
area:typer backlog No work planned on this by the core team for the time being. help wanted itype:bug

Comments

@sstucki
Copy link
Contributor

sstucki commented Sep 1, 2020

There seems to be some inconsistency between curried and uncurried type operators. This means that partially applying certain operators fails.

Minimized code

object Test {
  type Foo[+A, +B <: A] = B               // uncurried -> OK
  type Bar[+A] = [B <: A] =>> Foo[A, B]   // curried   -> fails
}

Output

-- Error: CurryingOps.scala:3:12 -----------------------------------------------
3 |  type Bar[+A] = [B <: A] =>> Foo[A, B]   // curried   -> fails
  |           ^^
  |covariant type parameter A occurs in contravariant position in [B <: A] =>> Test.Foo[A, B]
1 error found

Expectation

I'd expect the two versions to behave the same. The definition of Foo is correct, IMO. The type A does not appear in a contravariant position inside the definition/body of Foo — in fact it doesn't appear at all. It does appear in a bound in the signature of Foo but that shouldn't matter (the signature is not part of the definition). That means that the error in Bar is probably a false negative. I'm not sure why the bounds of type lambdas are considered in variance checking.

This may or may not be related to #6320 and #6499.

Tagging @Blaisorblade and @smarter since the example resulted from a discussion we had about variance checking.

@anatoliykmetyuk
Copy link
Contributor

anatoliykmetyuk commented Apr 12, 2021

I do not think the error is related to Foo. You can minimise it to:

type Bar[+A] = [B <: A] =>> Int

Fails with the following error:

-- Error: /Users/kmetiuk/Projects/scala3/playground/iwip/Bad.scala:1:10 --------                                                                      
1 |type Bar[+A] = [B <: A] =>> Int
  |         ^^
  |covariant type parameter A occurs in contravariant position in [B <: A] =>> Int
1 error found

Also in the neg tests, there is a code that specifically tests for such a variance failure:

https://github.com/lampepfl/dotty/blob/85a03eebe0fc4b11e0f7f8c1f121cc583b0927de/tests/neg/i6047.scala#L9-L12

The variance of A is set when checking variances for type Bar[+A] = [B <: A] =>> Foo[A, B], specifically when looking into the bounds B <: A:
https://github.com/lampepfl/dotty/blob/85a03eebe0fc4b11e0f7f8c1f121cc583b0927de/compiler/src/dotty/tools/dotc/core/Types.scala#L5665-L5672

The compiler thinks A must be contravariante because it appears in that bound.

The above code is executed from:
https://github.com/lampepfl/dotty/blob/85a03eebe0fc4b11e0f7f8c1f121cc583b0927de/compiler/src/dotty/tools/dotc/typer/VarianceChecker.scala#L51-L61

(line 59)

Theoretically you can insert there:

case t@TypeBounds(_, _) =>
  x

Before case _ => . But then, the neg test referenced above fails. So in solving this issue, we probably need to consider the behavior of that test.

@sstucki
Copy link
Contributor Author

sstucki commented Apr 12, 2021

I do not think the error is related to Foo. You can minimise it to:

type Bar[+A] = [B <: A] =>> Int

I might be missing something, but I never claimed that there's anything wrong with Foo. On the contrary, I think the behavior of the type checker w.r.t. Foo is correct. What I'm saying is that Bar is the same as Foo, except that Bar is curried, but Foo isn't. (So I think Bar should be accepted too.)

It could be that currying type operators with variance annotations like this should be forbidden, but I'm not sure that's the case. If it's not, then the two should behave the same.

@sstucki
Copy link
Contributor Author

sstucki commented Apr 12, 2021

I see now that my original code snippet uses Foo in the definition of Bar. Maybe that caused the confusion. To be clear, the error is the same with the following definition:

object Test {
  type Foo[+A, +B <: A] = B             // uncurried -> OK
  type Bar[+A] = [B <: A] =>> B         // curried   -> fails
}

where it should now be visually obvious that Foo and Bar compute the same type, but Bar is curried whereas Foo is not. Yet, only one definition is accepted.

@odersky odersky added the backlog No work planned on this by the core team for the time being. label Apr 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:typer backlog No work planned on this by the core team for the time being. help wanted itype:bug
Projects
None yet
Development

No branches or pull requests

4 participants