Skip to content

Compiler rejects cast in match arm #11791

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

Closed
bnoordhuis opened this issue Jan 25, 2014 · 7 comments
Closed

Compiler rejects cast in match arm #11791

bnoordhuis opened this issue Jan 25, 2014 · 7 comments

Comments

@bnoordhuis
Copy link
Contributor

At commit a5ab960. I would expect the following to work:

fn main() {
    match -1 as u32 {
        -1 as u32 => None,
        val => Some(val),
    };
}

But the compiler rejects it with the following error:

$ rustc t.rs
t.rs:3:12: 3:14 error: expected `=>` but found `as`
t.rs:3         -1 as u32  => None,
@huonw
Copy link
Member

huonw commented Jan 25, 2014

This is working as designed: we used to allow arbitrary constant expressions in patterns, but this was removed in db0693a .

There are (at least) two options:

  • just write -1 instead of -1 as u32 (note that -1 is actually a valid u32 literal, despite being "negative")
  • define a static like static ERROR_VAL: u32 = -1; and use ERROR_VAL as the pattern

@huonw huonw closed this as completed Jan 25, 2014
@bnoordhuis
Copy link
Contributor Author

Thanks for the suggestion. I tried something like that actually but it doesn't seem to work for all types. Here's an example:

fn main() {
    use std::libc::c_void;
    static ICONV_ERROR: *c_void = -1 as *c_void;
    match -1 as *c_void {
        ICONV_ERROR => None,
        val => Some(val),
    };
}
$ cat t.rs
t.rs:3:35: 3:48 error: Can't cast this type
t.rs:3     static ICONV_ERROR: *c_void = -1 as *c_void;

It's kind of strange because std::libc uses the same pattern.

Do you know what the rationale for commit db0693a was? It doesn't seem like an improvement from my point of view as a user.

@huonw
Copy link
Member

huonw commented Jan 25, 2014

Ah, looks like we don't support casts to raw pointers in const-expressions (yet). In this case you may be reduced to just using if pointer == -1 as *c_void { None } else { Some(pointer) }, unfortunately.

I don't remember the exact context, and, as you can see, the commit message is rather terse (as is the pull request: #6417). However, I believe it was simplifying the language and making the pattern grammar more sensible (previously, it wasn't clear if 1 | 2 was matching 3 (i.e. bitwise or of 1 and 2) or matching 1 or 2; now it can only be the latter). I could be incorrect.

@bnoordhuis
Copy link
Contributor Author

Thanks, that makes sense. The asymmetry between match predicates and normal expressions is somewhat displeasing but I can see the point of removing ambiguity from the language.

(EDIT: Though in the case of casts there is never any ambiguity, I think? Or is there?)

@Cxarli
Copy link

Cxarli commented Dec 30, 2019

Sorry for necroposting but this was the first issue I found when googling for "Rust cast in match arm".

Something like

const TEN: u32 = 10;

fn main() {
    let x: u64 = 20;

    match x {
        TEN as u64 => { /* ... */ },
        _          => { /* ... */ },
    }
}

still doesn't compile on rustc 1.40.0. However, I've found the following workaround which I wanted to share with anyone from the future who comes here by googling like me:

const TEN: u32 = 10;

fn main() {
    let x: u64 = 20;

    match x {
        a if a == TEN as u64 => { /* ... */ },
        _                    => { /* ... */ },
    }
}

If you move the cast to inside the if expression it's all fine.

(of course here it'd be trivial to match x as u32 or const TEN: u64 but imagine that's unwanted for the sake of the example)

@blagowtf
Copy link

blagowtf commented May 5, 2023

Hello, just passing by to say i was bitten by this when trying to write code like the following:

enum XX {
  A = 0,
  B = 1,
  C = 2,
}
let x: u64 = ...;
match x {
   XX::A as u64 => XX::A,
  XX::B as u64 => XX::B,
   XX::C as u64 => XX::C,
  _=> panic!()
}

I can hardcode the values but it would have been great to use the cast values in the pattern.

@twvd
Copy link

twvd commented Aug 20, 2023

I also just ran into this, when trying to match an i32 against byte literals. Would be very nice if this could be reconsidered..

flip1995 pushed a commit to flip1995/rust that referenced this issue Nov 16, 2023
Implement new lint `iter_over_hash_type`

Implements and fixes rust-lang/rust-clippy#11788

This PR adds a new *restriction* lint `iter_over_hash_type` which prevents `Hash`-types (that is, `HashSet` and `HashMap`) from being used as the iterator in `for` loops.

The justification for this is because in `Hash`-based types, the ordering of items is not guaranteed and may vary between executions of the same program on the same hardware. In addition, it reduces readability due to the unclear iteration order.

The implementation of this lint also ensures the following:
- Calls to `HashMap::keys`, `HashMap::values`, and `HashSet::iter` are also denied when used in `for` loops,
- When this expression is used in procedural macros, it is not linted/denied.

changelog: add new `iter_over_hash_type` lint to prevent unordered iterations through hashed data structures
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

5 participants