I need help with a mysterious lifetime issue. The error that the compiler is reporting is as follows:
Compiling my-crate v0.6.0 (...path...)
error[E0515]: cannot return value referencing local variable `named_actor`
--> (path)/assertion.rs:90:17
|
88 | let summary = named_actor.to_summary();
| ----------- `named_actor` is borrowed here
89 |
90 | / IdentityAssertionReport {
91 | | signer_payload: SignerPayloadReport::from_signer_payload(&self.signer_payload),
92 | | named_actor: Some(summary),
93 | | }
| |_________________^ returns a value referencing data owned by the current function
For more information about this error, try `rustc --explain E0515`.
The definition of the trait containing to_summary
fn is here:
pub trait ToCredentialSummary {
fn to_summary(&self) -> impl Serialize + 'static;
}
I'm not aware of anything that ties the output of to_summary
to any ongoing lifetime of the type that implements ToCredentialSummary
, but the compiler seems to think there is one.
Can you help me understand this implied lifetime or – even better – explain how to write to_summary
to that the return type can outlive the implementation of ToCredentialSummary
?
(edited to remove indentation that made it harder to read …)
You want to clone any data in named_actor referenced in to_summary so the reference is not alive when you hand named_actor to IdentityAssertionReport.
-> impl
in traits -- and everywhere in edition 2024+ -- captures all borrows from the inputs. You can read more about it here. So you have to train your eyes to pick up on impl
in a return the same way they pick up on &
and '_
.
In a trait, you need a nightly feature for the ideal fix, unfortunately.
#![feature(precise_capturing_in_traits)]
pub trait ToCredentialSummary {
fn to_summary(&self) -> impl Serialize + use<Self>;
}
(Tracking issue.)
Another alternative is to use an associated type instead.
pub trait ToCredentialSummary {
type Summary: Serialize;
fn to_summary(&self) -> Self::Summary;
}
But that doesn't help if your type is unnameable unless you can type erase it (Box<dyn ..>
). And it makes for a lot more boilerplate on your side if you want it to be opaque like -> impl
is.
There's another feature that will help with that eventually.
#![feature(impl_trait_in_assoc_type)]
impl ToCredentialSummary for Something {
type Summary: impl Serialize;
fn to_summary(&self) -> Self::Summary { .. }
}
(Tracking issue, for type aliases generally, not just in traits. Edit: Also various discussions in this PR.)
1 Like
@quinedot been doing some reading since then and this looks like an accurate description of the problem space. I'm not able to use nightly features(*), so it looks like I'll be Box
ing the result instead. Thanks for the confirmation.
(*) This code will be going into a public crate and I can't impose a requirement on our users to build with nightly Rust.