Just another GAT + lifetimes problem
⚓ Rust 📅 2025-08-15 👤 surdeus 👁️ 10I've got into some weird GAT lifetimes error and hope someone can help me here.
At first some requirements:
Contextcomes from outside, I cannot control it and it can be non-'static.Contextdefines aNodewhich it can create.Contextlifetime is not bound toNodeand it can dropped at any time (or live longer).Nodehas a generic lifetime, so outside code can make them reference each other- this tree of
Nodereferences is always one-way (non-cyclic) and I can enforce it (not part of the example)
For this to work I need to return &'a Node<'a> (all nodes have the same lifetime and can reference each other).
But it fails to compile with some strange error related to Ctx not being alive long enough.
Even more strange is that it is related to lifetime I return &'a. If I remove it - everything works. But i can't make a references tree.
Everything works if I remove "G" from GAT (lifetime from Node) but I need that "G".
So the question is why on earth does this &'a bounds Ctx lifetime and how to fix it.
PS: I know about using indexes but it doesn't fit my design goal. I'd like to make everything work by using references and lifetimes only (no vec[index], Rc, Arc, etc.).
Code:
trait Context {
type Node<'a>;
fn new_node<'a>(&mut self) -> Self::Node<'a>;
}
struct Storage<'a> {
vec: Vec<NonNull<()>>,
phantom: PhantomData<&'a mut ()>,
}
impl<'a> Storage<'a> {
fn allocate<Ctx: Context>(
&mut self,
context: &mut Ctx,
// |---- removing this 'a "fixes" the problem
) -> &'a mut Ctx::Node<'a> {
// dummy placeholder implementation here
let mut ptr = NonNull::from_ref(Box::leak(Box::new(context.new_node())));
self.vec.push(ptr.cast());
unsafe { ptr.as_mut() }
}
}
fn new_node<Ctx>(context: &mut Ctx, storage: &mut Storage)
where
Ctx: Context,
{
storage.allocate(context); // error here
}
Error:
error[E0311]: the parameter type `Ctx` may not live long enough
|
141 | pub fn new_node<Ctx>(context: &mut Ctx, storage: &mut Storage)
| ------- the parameter type `Ctx` must be valid for the anonymous lifetime defined here...
...
145 | storage.allocate(context);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `Ctx` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
141 ~ pub fn new_node<'a, Ctx>(context: &mut Ctx, storage: &mut Storage<'a>)
142 | where
143 ~ Ctx: Context + 'a,
|
3 posts - 2 participants
🏷️ Rust_feed