Skip to content
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

Operators in patterns have incorrect priorities #48501

Open
petrochenkov opened this issue Feb 24, 2018 · 8 comments
Open

Operators in patterns have incorrect priorities #48501

petrochenkov opened this issue Feb 24, 2018 · 8 comments
Labels
A-grammar Area: The grammar of Rust A-parser Area: The parsing of Rust source code to an AST. A-patterns Relating to patterns and pattern matching C-enhancement Category: An issue proposing an enhancement or a PR with one. F-exclusive_range_pattern `#![feature(exclusive_range_pattern)]` F-half_open_range_patterns `#![feature(half_open_range_patterns)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@petrochenkov
Copy link
Contributor

petrochenkov commented Feb 24, 2018

(Or at least unnatural priorities.)

Binary range operators have higher priority than unary operators like & or box.

#![feature(exclusive_range_pattern)]

fn main() {
    // Interpreted as (&0) .. (10), ERROR mismatched types
    let x = &0 .. 10;

    match &0 {
        &0 .. 10 => {} // OK?!
        _ => {}
    }
}

We can change the priorities for all the unstable kinds of ranges and come up with some deprecation story for stable BEGIN ... END.

@petrochenkov petrochenkov added A-grammar Area: The grammar of Rust A-parser Area: The parsing of Rust source code to an AST. labels Feb 24, 2018
@BubbaSheen

This comment has been minimized.

@durka
Copy link
Contributor

durka commented Feb 25, 2018

This is weird. The behavior in expressions is the one I would expect. However, in patterns you aren't allowed to use parentheses for grouping (why not?) so there's no way to override the precedence.

@petrochenkov
Copy link
Contributor Author

However, in patterns you aren't allowed to use parentheses for grouping (why not?) so there's no way to override the precedence.

That's why I submitted #48500 before fixing this :)

@durka
Copy link
Contributor

durka commented Feb 27, 2018

Do you have any ideas for how to do that deprecation? If it's smooth enough we can stabilize ..= in patterns anyway and change them at the same time.

@petrochenkov
Copy link
Contributor Author

@durka

Do you have any ideas for how to do that deprecation?

Compatibility warning, as usual?
I plan to prepare the fix this weekend, so it shouldn't delay stabilization of ..= in patterns too much.

@jkordish jkordish added C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 25, 2018
@Centril Centril added the F-exclusive_range_pattern `#![feature(exclusive_range_pattern)]` label Dec 12, 2019
@Centril Centril added the F-half_open_range_patterns `#![feature(half_open_range_patterns)]` label Dec 12, 2019
@scottmcm
Copy link
Member

Nominating because of @workingjubilee's comment in #67264 (comment)

I would be happy to draft the PR to stabilize this but first I want to know if #48501 is something that needs action on it still.

@scottmcm scottmcm added T-lang Relevant to the language team, which will review and decide on the PR/issue. and removed I-nominated labels Oct 28, 2020
@workingjubilee
Copy link
Member

@rustbot claim

@workingjubilee
Copy link
Member

Whoops, wrong spot. @rustbot release-assignment

bors added a commit to rust-lang-ci/rust that referenced this issue Jul 11, 2021
…r=joshtriplett

Stabilize "RangeFrom" patterns in 1.55

Implements a partial stabilization of rust-lang#67264 and rust-lang#37854.
Reference PR: rust-lang/reference#900

# Stabilization Report

This stabilizes the `X..` pattern, shown as such, offering an exhaustive match for unsigned integers:
```rust
match x as u32 {
      0 => println!("zero!"),
      1.. => println!("positive number!"),
}
```

Currently if a Rust author wants to write such a match on an integer, they must use `1..={integer}::MAX` . By allowing a "RangeFrom" style pattern, this simplifies the match to not require the MAX path and thus not require specifically repeating the type inside the match, allowing for easier refactoring. This is particularly useful for instances like the above case, where different behavior on "0" vs. "1 or any positive number" is desired, and the actual MAX is unimportant.

Notably, this excepts slice patterns which include half-open ranges from stabilization, as the wisdom of those is still subject to some debate.

## Practical Applications

Instances of this specific usage have appeared in the compiler:
https://github.com/rust-lang/rust/blob/16143d10679537d3fde4247e15334e78ad9d55b9/compiler/rustc_middle/src/ty/inhabitedness/mod.rs#L219
https://github.com/rust-lang/rust/blob/673d0db5e393e9c64897005b470bfeb6d5aec61b/compiler/rustc_ty_utils/src/ty.rs#L524

And I have noticed there are also a handful of "in the wild" users who have deployed it to similar effect, especially in the case of rejecting any value of a certain number or greater. It simply makes it much more ergonomic to write an irrefutable match, as done in Katholieke Universiteit Leuven's [SCALE and MAMBA project](https://github.com/KULeuven-COSIC/SCALE-MAMBA/blob/05e5db00d553573534258585651c525d0da5f83f/WebAssembly/scale_std/src/fixed_point.rs#L685-L695).

## Tests
There were already many tests in [src/test/ui/half-open-range/patterns](https://github.com/rust-lang/rust/tree/90a2e5e3fe59a254d4d707aa291517b3791ea5a6/src/test/ui/half-open-range-patterns), as well as [generic pattern tests that test the `exclusive_range_pattern` feature](https://github.com/rust-lang/rust/blob/673d0db5e393e9c64897005b470bfeb6d5aec61b/src/test/ui/pattern/usefulness/integer-ranges/reachability.rs), many dating back to the feature's introduction and remaining standing to this day. However, this stabilization comes with some additional tests to explore the... sometimes interesting behavior of interactions with other patterns. e.g. There is, at least, a mild diagnostic improvement in some edge cases, because before now, the pattern `0..=(5+1)` encounters the `half_open_range_patterns` feature gate and can thus emit the request to enable the feature flag, while also emitting the "inclusive range with no end" diagnostic. There is no intent to allow an `X..=` pattern that I am aware of, so removing the flag request is a strict improvement. The arrival of the `J | K` "or" pattern also enables some odd formations.

Some of the behavior tested for here is derived from experiments in this [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=58777b3c715c85165ac4a70d93efeefc) example, linked at rust-lang#67264 (comment), which may be useful to reference to observe the current behavior more closely.

In addition tests constituting an explanation of the "slicing range patterns" syntax issue are included in this PR.

## Desiderata

The exclusive range patterns and half-open range patterns are fairly strongly requested by many authors, as they make some patterns much more natural to write, but there is disagreement regarding the "closed" exclusive range pattern or the "RangeTo" pattern, especially where it creates "off by one" gaps in the presence of a "catch-all" wildcard case. Also, there are obviously no range analyses in place that will force diagnostics for e.g. highly overlapping matches. I believe these should be warned on, ideally, and I think it would be reasonable to consider such a blocker to stabilizing this feature, but there is no technical issue with the feature as-is from the purely syntactic perspective as such overlapping or missed matches can already be generated today with such a catch-all case. And part of the "point" of the feature, at least from my view, is to make it easier to omit wildcard matches: a pattern with such an "open" match produces an irrefutable match and does not need the wild card case, making it easier to benefit from exhaustiveness checking.

## History

- Implemented:
  - Partially via exclusive ranges: rust-lang#35712
  - Fully with half-open ranges: rust-lang#67258
- Unresolved Questions:
  - The precedence concerns of rust-lang#48501 were considered as likely requiring adjustment but probably wanting a uniform consistent change across all pattern styles, given rust-lang#67264 (comment), but it is still unknown what changes might be desired
  - How we want to handle slice patterns in ranges seems to be an open question still, as witnessed in the discussion of this PR!

I checked but I couldn't actually find an RFC for this, and given "approved provisionally by lang team without an RFC", I believe this might require an RFC before it can land? Unsure of procedure here, on account of this being stabilizing a subset of a feature of syntax.

r? `@scottmcm`
@jonas-schievink jonas-schievink added the A-patterns Relating to patterns and pattern matching label Jul 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-grammar Area: The grammar of Rust A-parser Area: The parsing of Rust source code to an AST. A-patterns Relating to patterns and pattern matching C-enhancement Category: An issue proposing an enhancement or a PR with one. F-exclusive_range_pattern `#![feature(exclusive_range_pattern)]` F-half_open_range_patterns `#![feature(half_open_range_patterns)]` T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

8 participants