0
votes

I have the following code which compiles fine

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    Const(i32),
    Neg(Box<Expression>),
    Add(Box<Expression>, Box<Expression>),
}

fn simplify(expr: &Expression) -> Expression {
    match expr {
        Expression::Neg(x) => match **x {
            Expression::Const(n) => Expression::Const(-n),
            _ => expr.clone() 
        },  

        // GIVES ERROR
        // Expression::Add(x, y) => match (**x, **y) {
        //     (Expression::Const(n), Expression::Const(m)) => Expression::Const(n + m),
        //     _ => expr.clone() 
        // },
    
    
        Expression::Add(x, y) => match **x {
            Expression::Const(n) => match **y {
                Expression::Const(m) => Expression::Const(n + m), 
                _ => expr.clone() 
            }   
            _ => expr.clone() 
        }   


        _ => expr.clone() 
    }   
}

But if I replace the Expression::Add arm with the commented out version, I get the following compiler error

error[E0507]: cannot move out of `**x` which is behind a shared reference
  --> src/lib.rs:21:41
   |
21 |         Expression::Add(x, y) => match (**x, **y) {
   |                                         ^^^ move occurs because `**x` has type `Expression`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `**y` which is behind a shared reference
  --> src/lib.rs:21:46
   |
21 |         Expression::Add(x, y) => match (**x, **y) {
   |                                              ^^^ move occurs because `**y` has type `Expression`, which does not implement the `Copy` trait

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

Is there a reason we may match against the lone **x but not in a tuple like (**x, **y)? Is the former actually being converted or hiding some syntactic sugar? Is there a simpler way of writing this Add arm than with the two nested matches?

EDIT: I also see that there is a ref keyword, which is supposed to address something like this, but changing my tuple match expression to (ref **x, ref **y) gives a syntax error (error: expected expression, found keyword ref).