Skip to content

Variance does not play well with pattern matching #22993

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
TomasMikula opened this issue Apr 12, 2025 · 10 comments
Open

Variance does not play well with pattern matching #22993

TomasMikula opened this issue Apr 12, 2025 · 10 comments
Labels
area:pattern-matching area:variance Issues related to covariance & contravariance. itype:bug

Comments

@TomasMikula
Copy link
Contributor

TomasMikula commented Apr 12, 2025

Compiler version

3.6.4

(Works in 3.3.5) It does not, in fact, work in 3.3.5. Scastie just did not report any error.

Minimized code

sealed trait Foo[+T]
class Bar[+T] extends Foo[T]

def downcast[T](foo: Foo[T]): Bar[T] =
  foo match
    case b: Bar[t] => 
      summon[t <:< T]
      b

(snippet has been editted to make Bar covariant)
https://scastie.scala-lang.org/EYEO0tDKSNqUJd4ypwRnKA
https://scastie.scala-lang.org/emJhbNmrQd2WYQEdjBzwow

Output

-- [E172] Type Error: test.scala:7:21 ------------------------------------------
7 |      summon[t <:< T]
  |                     ^
  |                     Cannot prove that t <:< T.
-- [E007] Type Mismatch Error: test.scala:8:6 ----------------------------------
8 |      b
  |      ^
  |      Found:    (b : Foo[T] & Bar[t])
  |      Required: Bar[T]
  |
  | longer explanation available when compiling with `-explain`
2 errors found

Expectation

Should typecheck, as it does with Scala 3.3.5.

@TomasMikula TomasMikula added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Apr 12, 2025
@som-snytt
Copy link
Contributor

final class Bar[+T] extends Foo[T]

Observing that this compiles. Both final and + are needed.

@TomasMikula
Copy link
Contributor Author

Well, a minimized example does not capture the real use case. 🤷‍♂ In reality, I need Bar to have subclasses, i.e. cannot be final.

@sjrd
Copy link
Member

sjrd commented Apr 13, 2025

See https://contributors.scala-lang.org/t/avoid-overly-conservative-warnings-about-type-testability-in-exhaustive-matches/7083 . Allowing to return b would be unsound.

Admittedly t <:< T should be true regardless. But even if that is true, you still don't have Bar[t] <: Bar[T].

@TomasMikula
Copy link
Contributor Author

TomasMikula commented Apr 13, 2025

@sjrd Then making Bar covariant should fix that, right? (I actually removed covariance as part of minimization, my mistake 🤦 .)

Here's an updated snippet with Bar covariant in T: https://scastie.scala-lang.org/emJhbNmrQd2WYQEdjBzwow
Going to update the description as well.

@sjrd
Copy link
Member

sjrd commented Apr 13, 2025

With covariance you can write case b: Bar[T] =>, with the uppercase T, and then you don't even need the type variable t anymore.

@TomasMikula
Copy link
Contributor Author

TomasMikula commented Apr 13, 2025

That works as a workaround, thanks. (UPDATE: not that great actually—see my next comment.)

In general, I avoid using patterns like that (i.e. using a specific type like T above), as one cannot tell, by just looking at the syntactic structure of the pattern, whether it is an (uncheckable) type test or just inevitable consequence of other things.

@TomasMikula
Copy link
Contributor Author

TomasMikula commented Apr 13, 2025

@sjrd I have just tried to apply the workaround in my original case and it triggers a "the type test [...] cannot be checked at runtime" warning:

Image

(I have changed lowercase f to uppercase F.)

The definitions are

sealed trait Motif[+F[_], T]
sealed trait Object[+F[_], Ps] extends Motif[F, Obj[Ps]]

@Gedochao Gedochao added area:variance Issues related to covariance & contravariance. and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Apr 14, 2025
@Gedochao
Copy link
Contributor

(Works in 3.3.5)

@TomasMikula wait, does it?
I'm still getting the error with 3.3.5:

-- [E172] Type Error:~/compiler-repro/repro.scala:9:21 
9 |      summon[t <:< T]
  |                     ^
  |                     Cannot prove that t <:< T.
-- [E007] Type Mismatch Error: ~/compiler-repro/repro.scala:10:6 
10 |      b
   |      ^
   |      Found:    (b : Foo[T] & Bar[t])
   |      Required: Bar[T]
   |
   | longer explanation available when compiling with `-explain`
2 errors found

@TomasMikula
Copy link
Contributor Author

TomasMikula commented Apr 14, 2025

@Gedochao You are right, it doesn't 🤦‍♂ I only tried 3.3.5 in Scastie, which does not show any error, so I assumed it compiled, but probably something in Scastie just crashes fatally without showing any error 🤷‍♂

https://scastie.scala-lang.org/EuXvO2P8SDy4cjUgtyo4BA

@TomasMikula TomasMikula changed the title [Regression] Variance does not play well with pattern matching Variance does not play well with pattern matching Apr 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:pattern-matching area:variance Issues related to covariance & contravariance. itype:bug
Projects
None yet
Development

No branches or pull requests

4 participants