Just another GAT + lifetimes problem

⚓ Rust    📅 2025-08-15    👤 surdeus    👁️ 4      

surdeus

I've got into some weird GAT lifetimes error and hope someone can help me here.

At first some requirements:

  • Context comes from outside, I cannot control it and it can be non-'static.
  • Context defines a Node which it can create.
  • Context lifetime is not bound to Node and it can dropped at any time (or live longer).
  • Node has a generic lifetime, so outside code can make them reference each other
  • this tree of Node references 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

Read full topic

🏷️ Rust_feed