cognitive-engineering-lab / rust-book

The Rust Programming Language: Experimental Edition
https://rust-book.cs.brown.edu
Other
503 stars 82 forks source link

Section 18.3- Misleading phrasing says the opposite of what is true #162

Closed Tomer-Eliahu closed 3 months ago

Tomer-Eliahu commented 5 months ago

In the Extra Conditionals with Match Guards section, it says regarding match guards:

"The downside of this additional expressiveness is that the compiler doesn't try to check for exhaustiveness when match guard expressions are involved".

However, this phrasing is misleading- it makes you believe that Rust will no longer insist that match expressions are exhaustive when you use a match guard.
So you would expect the following code to compile, but it does not:

  fn main() {

            let a = 0;

            let b = 0;

            //Rust still gives us a complier error telling us :
            //error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` not covered
            //if we remove the match guard of if b==0 the code complies
            match a{
                i32::MIN..=-1 if b==0 => println!("negative"),
                0..=i32::MAX => println!("zero or positive")
            }

        }

In reality, match arms with guards don't count towards exhaustivity.

This is because Because the Rust compiler cannot take guard expressions into account when determining if a match is exhaustive. As soon as you have a guard, it assumes that guard could fail (I got this from this post on stack overflow).

So the following code will not compile even though all patterns are covered and Rust will give you a false positive non-exhaustive patterns error:

        fn main() {
            let number: i32 = 4;

            match number {
                i if i == 0 => println!("Zero"),
                i if i > 0 => println!("Greater than zero"),
                i if i < 0 => println!("less than zero"),
                //_ => println!("Should never happen."),
                // ^ uncomment to fix compilation
            }
        }

you get the following error message (note the line in bold):

error[E0004]: non-exhaustive patterns: _ not covered --> src/main.rs:4:19 4 match number { ^^^^^^ pattern _ not covered
= note: the matched value is of type i32 = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown 7 ~ i if i < 0 => println!("less than zero"), 8 ~ _ => todo!(),

For more information about this error, try rustc --explain E0004.

I think it is important to fix this phrasing in the book to make it clear that: Rust will sometimes tell you a match is non-exhaustive when in reality it is, but will never tell you a match is exhaustive when it isn't.

It is my understanding that matches are always exhaustive. if I am missing something please let me know.

willcrichton commented 3 months ago

Great suggestion, I'll modify this wording.