-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Check type arguments for bad bounds #15571
Conversation
Fix ZIO tests that fail because of tightening of bounds checks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR LGTM, but the problem is unfortunately trickier. Take a look at this snippet:
trait Foo[X >: Any <: Nothing]
def andThenSub[A, B, C](f: A <:< B, g: B <:< C): A <:< C =
f.andThen(g)
@main def Test = (None: Option[Foo[?]]) match {
case _: Option[Foo[t]] =>
val unsound: Nothing = (5 : Any) : t
(unsound : Unit => Unit).apply(())
}
Since we can't prevent type arguments in general from having bad bounds, I'm wondering if we should disallow naming type arguments other than those at the "top level" of the pattern. I.e. Option[t]
would be allowed, Option[Foo[t]]
would be disallowed. WDYT, Martin?
Can't we instead either disallow trait Foo[X >: Any <: Nothing] or disallow pattern matching to discover a type variable with bad bounds? |
How would we handle classes like Perhaps we should only allow naming type arguments with bounds that are known to certainly be good? (Is that what you meant?) |
I think it would be really good if you (or somebody else) would figure out an answer to that. |
Could one say that a bound of scala> trait Bar[A, B, C >: A <: B]
// defined trait Bar could fail because That would leave this weird asymmetry though: scala> trait Bar[A <: B, B, C >: A <: B]
// defined trait Bar
scala> trait Bar[A, B >: A, C >: A <: B]
// defined trait Bar
scala> trait Bar[A <: B, B >: A, C >: A <: B]
-- [E140] Cyclic Error: --------------------------------------------------------
1 |trait Bar[A <: B, B >: A, C >: A <: B]
| ^
|illegal cyclic type reference: upper bound B of type A refers back to the type itself
1 error found |
OK, I can add it to the list of issues I'll take a look this summer, while we're working on the GADT issues together with Yichen. In the meantime, I think we should merge this PR anyway. |
Your intuition is good. Defining |
I found two more test cases: @main def Test4 =
type t >: Any <: Nothing
val unsound: Nothing = (5 : Any) : t
(unsound : Unit => Unit).apply(())
@main def Test5 =
type t >: Any <: Nothing
val unsound: List[Nothing] = List(5 : Any) : List[t]
(unsound.head : Unit => Unit).apply(()) Both compile, but should be rejected. I think it's the explicit usage of a type reference As @abgruszecki writes, in DOT we cannot express such references. We can only write |
Fixes #15569
Also: Check for good bounds before reporting other bounds violations
Fixes #15568