Compiler says match appears to be inexhaustive?

    while let Some(op) = ops.pop_front() {
        let lhs = match vals.pop_front().expect("No value remaining") {
            Value::Parsed(n) => n,
            Value::Unparsed(s) => s.parse::<i32>().unwrap_or(*self.variables.get(s).expect("Unrecognized variable"))
        };
        match op {
            "->" => {
                let rhs = vals.pop_front().unwrap();
                match rhs {
                    Value::Unparsed(s) => {
                        *self.variables.entry(s).or_default() = lhs;        
                    },
                    _ => unreachable!()
                }
            },
            op2 if matches!(op2,  "AND" | "OR" | "LSHIFT" | "RSHIFT") => {
                let rhs = match vals.pop_front().expect("No value remaining") {
                    Value::Parsed(n) => n,
                    Value::Unparsed(s) => s.parse::<i32>().unwrap_or(*self.variables.get(s).expect("Unrecognized variable"))
                };
                match op2 {
                    "AND" => vals.push_front(Value::Parsed(lhs & rhs)),
                    "OR" => vals.push_front(Value::Parsed(lhs | rhs)),
                    "LSHIFT" => vals.push_front(Value::Parsed(lhs << rhs)), 
                    "RSHIFT" => vals.push_front(Value::Parsed(lhs >> rhs)),
                    _ => unreachable!() // <-- Why should be any other case here?
                }
            }
            "NOT" => {
                let arg = vals.pop_front().unwrap();
                vals.push_front(Value::Parsed(match arg {
                    Value::Parsed(n) => !n,
                    Value::Unparsed(s) => !s.parse::<i32>().unwrap_or(*self.variables.get(s).expect("Unrecognized variable"))
                }));
            },
                _ => unreachable!()
        }

In the code above I had matched op2 against a known set of patterns, why do I need to specify an extra case?

The compiler isn't smart enough to see that an &str can only have a limited number of values at a certain point in the program. Exhaustiveness checking is only based on the type of the expression. An enum type can a finite number of values, but a type like &str has an unlimited number of values and cannot be matched exhaustively.

2 Likes

Adding to what @mbrubeck said, you're better served by an enum.

Also, why do you use op2 if matches!(op2, "AND" | "OR" | "LSHIFT" | "RSHIFT")? It's strange and the compiler also doesn't consider it in the exhaustiveness check. Just do "AND" | "OR" | "LSHIFT" | "RSHIFT".