[Question]: E0716 - temporary value dropped while borrowed

Hello.
While working on something, I came across this problem:

    fn visit_arraynode(&mut self, node: Node, context: &mut Context, exprs: Vec<Node>) -> RTResult {
        let mut res = RTResult {exception: InterpreterException {failed: false, name: "".to_string(), msg: "".to_string(), ucmsg: "".to_string(), start: node.start.clone(), end: node.end.clone(), context: Some(context.clone())}, value: Type {value: Value::NullType, start: node.start.clone(), end: node.end.clone(), context: context.clone()}};
        let mut arraytype = None;
        let mut values = vec![];
        let mut expr: Type;

        for i in exprs {
            let expr = res.register(self.visit(i, context));

            if res.exception.failed {
                return res;
            }

            match arraytype {
                Some(_) => {},
                None    => {
                    arraytype = Some(expr.clone().gettype());
                }
            }

            values.push(expr.clone());
        }

        match arraytype {
            Some(arraytype) => {
                return res.success(Type {
                    value: Value::ArrayType(values.clone(), arraytype.to_string()),
                    start: node.start, end: node.end, context: context.clone()
                });
            },
            None => {
                let arraytype = Type {
                    value: Value::NullType,
                    start: node.clone().start, end: node.clone().end, context: context.clone()
                };
                return res.success(Type {
                    value: Value::ArrayType(values, arraytype.gettype().to_string()),
                    start: node.clone().start, end: node.clone().end, context: context.clone()
                });
            }
        }
    }

On the line arraytype = Some(expr.clone().gettype()); it complains that expr.clone() is dropped while borrowed. What does this mean and how can I fix it?

Here is the error:

error[E0716]: temporary value dropped while borrowed
   --> src/version/interpreter.rs:160:38
    |
160 |                     arraytype = Some(expr.clone().gettype());
    |                                      ^^^^^^^^^^^^           - temporary value is freed at the end of this statement
    |                                      |
    |                                      creates a temporary which is freed while still in use
...
167 |         match arraytype {
    |               --------- borrow later used here
    |
    = note: consider using a `let` binding to create a longer lived value

Turns out this works much better:

    fn visit_arraynode(&mut self, node: Node, context: &mut Context, exprs: Vec<Node>) -> RTResult {
        let mut res = RTResult {exception: InterpreterException {failed: false, name: "".to_string(), msg: "".to_string(), ucmsg: "".to_string(), start: node.start.clone(), end: node.end.clone(), context: Some(context.clone())}, value: Type {value: Value::NullType, start: node.start.clone(), end: node.end.clone(), context: context.clone()}};
        let mut values = vec![];

        for i in exprs {
            let expr = res.register(self.visit(i, context));

            if res.exception.failed {
                return res;
            }

            values.push(expr);
        }

        if values.len() > 0 {
            return res.success(Type {
                value: Value::ArrayType(values.clone(), values[0].gettype().to_string()),
                start: node.start, end: node.end, context: context.clone()
            });

        } else {
            let arraytype = Type {
                value: Value::NullType,
                start: node.clone().start, end: node.clone().end, context: context.clone()
            };
            return res.success(Type {
                value: Value::ArrayType(values, arraytype.gettype().to_string()),
                start: node.clone().start, end: node.clone().end, context: context.clone()
            });
        }
    }

The error is about result of expr.clone() not being stored anywhere. In a language with a garbage collector things are automatically stored for you and live for as long as they need. In Rust nothing is stored unless you store it yourself, and things live for as short as they're made to.

That means that in Rust variables are semantically meaningful.

foo.clone().gettype()

does a different thing than

let var = foo.clone();
var.gettype();

If a value is not saved in a variable, it will be destroyed on the next ;. So you're creating a clone and immediately getting rid of it. This makes arraytype refer to a ghost of a destroyed clone that went nowhere.

In fact, because you have a loop here, you can't even store that clone in a variable, because arraytype exists outside of the loop, so it can't rely on variables that exist only inside the loop.

You may need to make gettype an owning type that doesn't borrow from the expr, so that you can do expr.gettype() or expr.gettype().clone() to have a self-contained arraytype value that can exist even after its expr has been destroyed.

Wooh. I come from python. I didn't have to deal with these things.
Also, I tried this:

//Rust

let var = foo.clone();
var.gettype();

It didn't work.

I just figured out a workaround Here, which not only looks better, but actually works without the compiler saying no.

Thank you though.

1 Like