Is early returning mut references passed as an argument supposed to work?

⚓ Rust    📅 2026-05-30    👤 surdeus    👁️ 1      

surdeus

Hello!

For some context, I'm currently building a diagnostic result type DiagnosticResult<OkType, Message, WarnType> with Ok/Warn/Err states and I've wanted to have two comparable APIs: chaining and collection. For the collection API, I represent it by storing a &mut Collector as the Message type.

Maybe my design is flawed in the first place (and I'm open to critique/suggestions there), but in particular I may have hit a borrow checker limitation:

Since I want this to work in stable Rust if possible, I have a custom Try-like macro defined as follows:

#[macro_export]
macro_rules! diag_try {
    ($expr:expr) => {
        match $expr {
            $crate::DiagnosticResult::Ok(value) => value,
            $crate::DiagnosticResult::Warn(value, message) => {
                return $crate::DiagnosticResult::Warn(value.into(), message.into());
            }
            $crate::DiagnosticResult::Err(message) => {
                return $crate::DiagnosticResult::Err(message.into());
            }
        }
    };
}

and on this code snippet:

fn sample(&self) -> DiagnosticResult<(), &mut Collector, ()> {
   let ok_ret = diag_try!(self.some_fallible_call().collect_into(&mut self.diag));

   self.diag.add_message(Warn::Blah {value: ok_ret});
}

This works fine for the chaining API, but the collector API fails because when Message is &mut Collector, claiming it cannot borrow *self as mutable more than once at a time, and returning this value requires that self.diag is borrowed for '1.

As far as I understand, this happens because the lifetime of the &mut self.diag in the diag_try! line above unintentionally covers the rest of the function as well, whereas it's strictly only supposed to be until the return call. I've also seen mentions about how Polonius is designed to handle these scenarios as well. Would I be correct in my assumption?

Thanks in advance!

5 posts - 3 participants

Read full topic

🏷️ Rust_feed