Cannot infer an appropriate lifetime for lifetime parameter

I am new to Rust, I am having some problem with lifetime,
File github link

Code

    fn visit_function(&mut self, expr: &Function) -> Result<Rc<Value>, ExprError> {
        let name = &expr.name.lexeme;
        let function = TullyCallable { declaration: expr };
        self.globals
            .define(name, Rc::new(Value::Function(Rc::new(function))));
        Ok(Rc::clone(&self.constants.nil))
    }
pub trait Callable {
    fn arity(&self) -> usize;
    fn call(
        &self,
        evaluator: &mut Evaluator,
        arguments: Vec<Rc<Value>>,
    ) -> Result<Rc<Value>, ExprError>;
    fn to_string(&self) -> String;
}

pub struct TullyCallable<'a> {
    declaration: &'a Function<'a>,
}

impl<'a> Callable for TullyCallable<'a> {
    fn arity(&self) -> usize {
        self.declaration.params.len()
    }

    fn call(
        &self,
        evaluator: &mut Evaluator,
        arguments: Vec<Rc<Value>>,
    ) -> Result<Rc<Value>, ExprError> {
        evaluator.globals.new_env();
        for (i, param) in self.declaration.params.iter().enumerate() {
            evaluator
                .globals
                .define(&param.lexeme, Rc::clone(&arguments[i]));
            evaluator.execute_block(&self.declaration.body.statements, false)?;
        }
        evaluator.globals.delete_recent();
        return Ok(Rc::clone(&evaluator.constants.nil));
    }

    fn to_string(&self) -> String {
        format!("<fn {}>", self.declaration.name.lexeme)
    }
}


#[derive(Clone)]
pub enum Value {
    Boolean(bool),
    Float(f64),
    String(String),
    Function(Rc<dyn Callable>),
    Nil,
}

Error

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
   --> src/evaluator/evaluator.rs:334:24
    |
334 |         let function = TullyCallable { declaration: expr };
    |                        ^^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the method body at 332:5...
   --> src/evaluator/evaluator.rs:332:5
    |
332 | /     fn visit_function(&mut self, expr: &Function) -> Result<Rc<Value>, ExprError> {
333 | |         let name = &expr.name.lexeme;
334 | |         let function = TullyCallable { declaration: expr };
335 | |         self.globals
336 | |             .define(name, Rc::new(Value::Function(Rc::new(function))));
337 | |         Ok(Rc::clone(&self.constants.nil))
338 | |     }
    | |_____^
note: ...so that the expression is assignable
   --> src/evaluator/evaluator.rs:334:53
    |
334 |         let function = TullyCallable { declaration: expr };
    |                                                     ^^^^
    = note: expected  `&parser::expr::Function<'_>`
               found  `&parser::expr::Function<'_>`
    = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
   --> src/evaluator/evaluator.rs:336:51
    |
336 |             .define(name, Rc::new(Value::Function(Rc::new(function))));
    |                                                   ^^^^^^^^^^^^^^^^^
    = note: expected  `std::rc::Rc<(dyn evaluator::callable::Callable + 'static)>`
               found  `std::rc::Rc<dyn evaluator::callable::Callable>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `tully`.

To learn more, run the command again with --verbose.
``

+ 'static requirement means "no temporary references allowed". It is automatically added to Rc, Box. You can override it explicitly by allowing a temporary lifetime:

fn f<'a>(expr: &'a Function) -> Result<Rc<Value + 'a>, …>

Alternatively, forbid Function to have temporary references inside either by using something like:

declaration: Function,
declaration: Function<'static>,
declaration: Box<Function<'static>>,

@kornel I am getting another error

changes

    fn visit_function<'a>(&mut self, expr: &'a Function) -> Result<Rc<Value + 'a>, ExprError> {
        let name = &expr.name.lexeme;
        let function = TullyCallable { declaration: expr };
        self.globals
            .define(name, Rc::new(Value::Function(Rc::new(function))));
        Ok(Rc::clone(&self.constants.nil))
    }

Error

error[E0404]: expected trait, found enum `Value`
   --> src/evaluator/evaluator.rs:332:71
    |
332 |     fn visit_function<'a>(&mut self, expr: &'a Function) -> Result<Rc<Value + 'a>, ExprError> {
    |                                                                       ^^^^^ not a trait

warning: trait objects without an explicit `dyn` are deprecated
   --> src/evaluator/evaluator.rs:332:71
    |
332 |     fn visit_function<'a>(&mut self, expr: &'a Function) -> Result<Rc<Value + 'a>, ExprError> {
    |                                                                       ^^^^^^^^^^ help: use `dyn`: `dyn Value + 'a`
    |
    = note: `#[warn(bare_trait_objects)]` on by default

error: aborting due to previous error

For more information about this error, try `rustc --explain E0404`.
error: could not compile `tully`.

To learn more, run the command again with --verbose.

thanks for replying :slight_smile:

Ah, I mixed things up. Because it creates a Value, the lifetime has to be on the value:

    Function(Rc<dyn Callable>),

needs to be Value<'a> with:

    Function(Rc<dyn Callable + 'a>),

once there is a temporary scope-limited reference in some data structure, the annotations will spread like a virus to everything that touches it. This is because forgetting the type is anchored to some temporary scoped value is unsafe, and all the code and all the datatypes have to carry that lifetime annotation to prevent unrestricted usage of the borrowed type.

So if you can, consider the alternative of not holding a temporary reference to a function, but instead owning it, so that it can be freely passed around without "infecting" the program with lifetime annotations.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.