-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Tracking issue for illegal_floating_point_literal_pattern
compatibility lint
#41620
Comments
Adds a compatibility lint to disallow floating point literals in patterns like in match. See the tracking issue rust-lang#41620.
…omatsakis Implement the illegal_floating_point_literal_pattern compat lint Adds a future-compatibility lint for the [breaking-change] introduced by issue rust-lang#41620 . cc issue rust-lang#41255 .
RFC 1445 is about |
This is a breaking change (rejecting previously-accepted programs) but as far as I can tell this one is not part of an accepted RFC. |
Is this a duplicate of #36890? |
Hmm a quick glance over the RFC seemed to confirm this.
No, its separate. There are two separate lints. This one is about literals, the one tracked in that issue is about constants. I have opened the PR #41293 after finding out about #41255. |
From my perspective, primitive literals (as opposed to destructuring struct literals) are a kind of constant. The same questions raised by consts in that RFC are raised by primitive literals. |
Yet the example given in #36890 uses literals.
Given that we have a language keyword named |
The example quoted in the tracking issue you linked never was implemented that way. I have asked about whether to create a separate lint or add the check to the existing one, and it was decided to create a separate lint. I guess the example should be removed from that issue's description. |
I would definitely say that the RFC was intended to apply equally to all constants, whether they are literals or not. Clearly there is room for other opinions (since @SimonSapin read it differently). Personally, I am on the fence here. I somewhat agree with @SimonSapin that the number of regressions here feels too high. Part of the reason that I agree to go with a warning was to highlight this question so that we can have a wider discussion with more of the people who are affected. For clarity, floating point literals at present match the same way as I take the following as a given (I'm curious if others disagree):
This seems to imply that if we don't make things a hard error, we can't have floating point NLC that use a purely structural match. They would always match with This may or may not affect plans around constant generics. It's not obvious to me that dynamic In other words, I see a few options:
I am not sure whether an RFC ought to be required, whichever path we chose, but since there seems to be disagreement, it seems plausible to open an RFC amendment to finalize the decision. |
@nikomatsakis I don't think this needs to be entangled with const generics, we just need to transition to a solution for that as well as whatever we decide for match. Just renaming the attribute is probably fine. I do feel that literals and consts should behave the same, but I don't have a strong opinion about how they ought to behave. Really whatever decision seems fine if it applies to both. |
Let me unpack this a bit to be sure I understand. You're saying:
Right? (That said, it's not entirely clear to me why const generics would even need an attribute at all; I guess it depends a lot on how we wind up defining equality. My expectation was that equality would be based more on where in the source the expression arose (i.e., we would treat constant expressions as kind of "uninterpreted functions") -- and we'd always be assuming that said functions are deterministic (because of the limits we place on const fns), and hence we consider two constant expressions "equal" if they are the same function applied to equal inputs, where this bottoms out with simple integers and other builtins. But I guess eventually we might want to extend that notion of structural equality to other kinds of expressions and types, and maybe we want some opt-in around that, unsure.) |
@nikomatsakis the issue here isn't with unevaluable const expressions but with floating point numbers and other types for which equality is not reflexive because of how that would impact unification. We don't need an attribute but it does seem that we do need const values to have a guaranteed reflexive definition of equality (which is why just using |
I might be missing something here, but I see this also applies to ranges, ie.
gives warning: floating-point literals cannot be used in patterns. Is this intentional? I feel like this is a pretty common pattern. |
Yeah, I gotta ask, how am I supposed to do clean pattern matching with floating point ranges. I know floating points are hard, but isn't there a way to make this work in ranges? Example (real) code that gives a warning now: /// Calculates the UTM zone this longitude falls in
/// Handles exceptions for Norway / Svalbard
/// For a visual representation: https://upload.wikimedia.org/wikipedia/commons/a/a5/UTM-Zone.svg
///
/// Inputs: Longitude, in degrees
/// Latitude, in degrees
///
/// Returns: UTM Zone
///
#[allow(non_snake_case)]
pub fn get_utm_zone(lon: f64, lat: f64) -> u8 {
let mut zone = ((lon + 180.0) / 6.0).floor() as u8 + 1;
match lat {
56.0..64.0 => {
/* Zone V, Norway */
match lon {
3.0..6.0 => {
zone += 1;
}
_ => {}
}
}
72.0..84.0 => {
/* Zone X, Svalbard */
match lon {
6.0..9.0 => {
zone -= 1;
}
9.0..12.0 => {
zone += 1;
}
18.0..21.0 => {
zone -= 1;
}
21.0..24.0 => {
zone += 1;
}
30.0..33.0 => {
zone -= 1;
}
33.0..36.0 => {
zone += 1;
}
_ => {}
}
}
_ => {}
}
zone
} How should I write this instead? Why is it that I can do comparisons of floats in if statements, but not pattern matching in range statements? I would have to write |
Yes, there has been some back and forth on whether we ought to apply the same thing to floating points. |
It would be very unfortunate if floating point ranges were disallowed by this. I don't see any problems with this particular pattern. |
I was caught by this as well. My case is: let fudge_factor = match magic_value {
0. ... 0.8 => 9.,
0. ... 1.0 => 6.,
0. ... 1.2 => 4.,
0. ... 2.5 => 3.67,
_ => 3.0,
}; To work around float comparison woes I'm using a hack of starting every range with I don't particularly like the current hacky/unclear/error-prone way of matching non-overlapping ranges of numbers, but I'd rather have something working until Rust gets a better replacement. |
I probably missed it above, but does anyone have a simple concrete example of how a |
I just had this example: I have I wanted to write (maybe controversial style, but I like it) // if is calc() is out of range
if !matches!(calc(), None | Some(0.0..=1.0) { ... } I had to write (I dont demorgan when checking for intervals) if let Some(c) = calc() {
if !(0 <= c && c <= 1) {...}
} Sure, there can be some issues about exhaustiveness or gaps or reflexivity, but these well-behaved ranges are quite nice. The inverse is even more convoluted. Am I missing something?? // calc() is missing or in range
if calc().map(|c| 0 <= c && c <= 1).unwrap_or(true) {...}
// or:
let is_ok = if let Some(c) = calc() { 0 <= c && c <= 1 } else { true };
if is_ok {...}
// float patterns:
if matches!(calc(), None | Some(0.0..=1.0)) { ... } |
FWIW #84045 (which wanted to turn this into a hard error) got rejected by the lang team. So it seems like the "future compatibility" status of this lint is not accurate -- this will not be made a hard error. We might want a lint that specifically warns about NaNs and +/- 0 in patterns because they don't behave like a bit-wise equality test, but that's quite different from what this lint currently does. |
Ah, good call out @RalfJung, we should probably change the status to jjust a lint? |
Yes, and adjust the wording and name. But also, why would we lint against |
IMO we should just entirely remove the lint, without replacement. |
…error in a long run' said by rust developers in this address : rust-lang/rust#41620
So how do we move this forward? Being stuck in a state of limbo is worse than either outcome. |
There's a design meeting this week where the lang team will look at this issue and the surrounding issues related to pattern matching. |
What was the outcome? |
Unfortunately we didn't even get to floats, we were mainly discussing consts in patterns in general. Here is something of a summary. |
Has there been any discussion since? |
Yes: rust-lang/rfcs#3535 |
make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error. This is part of implementing rust-lang/rfcs#3535. Closes rust-lang#41620 by removing the lint. rust-lang/reference#1456 updates the reference to match.
make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error. This is part of implementing rust-lang/rfcs#3535. Closes rust-lang#41620 by removing the lint. rust-lang/reference#1456 updates the reference to match.
make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error. This is part of implementing rust-lang/rfcs#3535. Closes rust-lang#41620 by removing the lint. rust-lang/reference#1456 updates the reference to match.
make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error. This is part of implementing rust-lang/rfcs#3535. Closes rust-lang#41620 by removing the lint. rust-lang/reference#1456 updates the reference to match.
Rollup merge of rust-lang#116284 - RalfJung:no-nan-match, r=cjgillot make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error. This is part of implementing rust-lang/rfcs#3535. Closes rust-lang#41620 by removing the lint. rust-lang/reference#1456 updates the reference to match.
make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern These arms would never be hit anyway, so the pattern makes little sense. We have had a future-compat lint against float matches in general for a *long* time, so I hope we can get away with immediately making this a hard error. This is part of implementing rust-lang/rfcs#3535. Closes rust-lang/rust#41620 by removing the lint. rust-lang/reference#1456 updates the reference to match.
The use of literal pattern matching on floating points has been deprecated. It currently produces a warning, but will eventually cause a compilation error. See: rust-lang/rust#41620
This is a tracking issue for the compatibility lint disallowing floating point literals in patterns.
The corresponding RFC is RFC 1445. Originally, #36890 was the only tracking issue for floats in patterns, but after it was found out that the implementation of that lint doesn't cover literals (issue #41255), another lint and tracking issue were required.
The goal of this lint is to make code like this a hard error:
The text was updated successfully, but these errors were encountered: