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

allow slice patterns to match non-fixed/generic length arrays #3675

Open
Skgland opened this issue Jul 31, 2024 · 6 comments
Open

allow slice patterns to match non-fixed/generic length arrays #3675

Skgland opened this issue Jul 31, 2024 · 6 comments

Comments

@Skgland
Copy link

Skgland commented Jul 31, 2024

Currently slice patterns can match fixed sized arrays and dynamic sized slices. It would be useful in code over generic length array to also be able to match on dynamic sized/non-fixed length/generic length arrays.

fn example<const N: usize>(arr: /* &[u8; N] | &mut [u8; N] | */ [u8; N]) {
    match arr {
        [] => {
            println!("None");
        }
        [_] => {
            println!("Some");
        }
        [_,_,_rest@..] => {
            println!("Many");
        }
    }
}

play-ground

Currently this results in E7030 and E0308

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:14:9
   |
14 |         [] => {
   |         ^^ expected `0`, found `N`
   |
   = note: expected array `[u8; 0]`
              found array `[u8; N]`

error[E0308]: mismatched types
  --> src/main.rs:17:9
   |
17 |         [_] => {
   |         ^^^ expected `1`, found `N`
   |
   = note: expected array `[u8; 1]`
              found array `[u8; N]`

error[E0730]: cannot pattern-match on an array without a fixed length
  --> src/main.rs:20:9
   |
20 |         [_,_,..] => {
   |         ^^^^^^^^

Some errors have detailed explanations: E0308, E0730.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to 3 previous errors

For arrays behind references one can mostly workaround this by turning the array reference into a slice reference.

fn example<const N: usize>(arr: /*  &mut [u8; N] | */ &[u8; N]) {
   let slice : &[_] = arr;
    match slice {
        [] => {
            println!("None");
        }
        [_] => {
            println!("Some");
        }
        [_,_,_rest@..] => {
            println!("Many");
        }
    }
}

But this leaves out the owned case and for arrays I would expect sub-array patterns to be arrays rather than slices, i.e. for input type &[u8;N] the type of _rest for the first example would be &[u8;N - 2] rather than &[u8].

For exhaustiveness checking generic arrays would be treated like slices i.e. all lengths (0..=usize::MAX) needs to be covered.

@Skgland
Copy link
Author

Skgland commented Aug 1, 2024

@kennytm you reacted with the confused emoji, could you elaborate what confuses you?

@kennytm
Copy link
Member

kennytm commented Aug 1, 2024

@Skgland do you have any concrete example that actually needing the type of rest to be known as [u8; N-2]?

@fmease
Copy link
Member

fmease commented Aug 1, 2024

I find this feature request not unreasonable. However, this is pretty much blocked on GCE (generic_const_exprs) as such a match introduces values of type [$T; N - $M].

@Skgland
Copy link
Author

Skgland commented Aug 1, 2024

Skgland do you have any concrete example that actually needing the type of rest to be known as [u8; N-2]?

All of them would have been replaced with workarounds by now, so no I don't.
Though I don't think I ever required to bind the rest on a pattern match on owned array of generic length.
But I have run into the general problem of wanting to match a generic length array a couple of times,
which is why I searched for an existing Issue/PR, found none and opened this.

I included it even though I don't have a specific use case because leaving out sub-array patterns seamed to leave the feature incomplete.
Given that it already works like that for arrays of known size playground that appears to be the reasonable choice for the type.

I find this feature request not unreasonable. However, this is pretty much blocked on GCE (generic_const_exprs) as such a match introduces values of type [$T; N - $M].

Could an initial implementation disallow binding the sub-array i.e. .. is allowed but var@.. isn't. Would that even help?
So that only sub-array bindings are blocked on GCE, while destructing the array as a whole isn't.

@kennytm
Copy link
Member

kennytm commented Aug 1, 2024

Suppose this RFC is accepted, will the following still result in E0527/E0528? Or those will be demoted to "unreachable pattern" warnings?

fn main() {
    match [1] {
        [] => unreachable!(),
        [_] => println!("ok"),
        [_, _, ..] => unreachable!(),
    }
}

@Skgland
Copy link
Author

Skgland commented Aug 1, 2024

I don't think there would ever be a reason to manually write those, but I could see it making writing a macro easier/possible by turning those cases from errors to warnings. Maybe a specialized deny by default lint would make sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants