How can I get impl Trait to use the appropriate lifetime for a mutable reference to a value with another lifetime in it? - rust

I have a struct with a lifetime:
struct HasLifetime<'a>( /* ... */ );
There is there is an implementation of the trait Foo:
impl<'a, 'b: 'a> Foo for &'a mut HasLifetime<'b> { }
I want to implement the following function:
fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut Lifetime<'b>) -> impl Foo {
bar
}
This won't compile because the returned impl is only valid for 'a. However, specifying impl Foo + 'a results in:
error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> src/main.rs:7:60
|
7 | fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut HasLifetime<'b>) -> impl Trait + 'a {
| ^^^^^^^^^^^^^^^
|
note: hidden type `&'a mut HasLifetime<'b>` captures the lifetime 'b as defined on the function body at 7:1
--> src/main.rs:7:1
|
7 | fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut HasLifetime<'b>) -> impl Trait + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The seemingly equivalent function with a boxed trait object compiles:
fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut Lifetime<'b>) -> Box<Foo + 'a> {
Box::new(bar)
}
How can I define bar_to_foo with impl Trait?
Playground link

You need to indicate that the returned value is built upon multiple lifetimes. However, you can't use multiple lifetime bounds with impl Trait, and attempting to do so doesn't have a useful error message.
There's a trick you can use that involves creating a dummy trait that has a lifetime parameter:
trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}
fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut HasLifetime<'b>) -> impl Trait + Captures<'b> + 'a {
bar
}
Thankfully, this only occurs when the "hidden" lifetime is invariant, which occurs because the reference is mutable.

Related

Rust move an `impl Trait` into an owned `Box<dyn Trait>` without adding lifetime bound [duplicate]

This question already has answers here:
The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
(2 answers)
Closed last month.
Here, the compiler complains that impl Foo may not live long enough:
struct VecWrapper(Vec<Box<dyn Foo>>);
impl VecWrapper {
fn push(&mut self, item: impl Foo) {
self.0.push(Box::new(item))
}
}
trait Foo {}
This is not what I expect, because item should be moved into the Box. The compiler recommends adding a static lifetime:
|
4 | fn push(&mut self, item: impl Foo + 'static) {
| +++++++++
In my case, item and VecWrapper are created at runtime for error handling, so I would like to avoid using lifetimes here.
Your trait can be implemented by something like struct Bar<'a, T>(&'a T);, if you pass a value of this type to your function, your struct would not sufficiently reflect the lifetime 'a imposed by &'a T.
You can add a lifetime to VecWrapper and put that lifetime on impl Foo if you don't want to restrict VecWrapper to owned types. Adding a 'static bound to impl Foo would limit VecWrapper to owned types.
struct VecWrapper<'a>(Vec<Box<dyn Foo + 'a>>);
impl<'a> VecWrapper<'a> {
fn push(&mut self, item: impl Foo + 'a) {
self.0.push(Box::new(item))
}
}
trait Foo {}
struct Bar<'a, T>(&'a T);
impl<'a, T> Foo for Bar<'a, T> {
}
fn foo() {
let s = String::new();
VecWrapper(vec![]).push(Bar(&s));
}

Why Rust complains about lifetime of types in functions that don't use instances of these types?

Rust requires lifetimes for types that don't have instances:
use futures::future::BoxFuture;
struct A{
}
impl A{
async fn send_and_expect<T>(&mut self, unauthorized_retry: i32) -> std::result::Result<(),()>{
Err(())
}
fn send_and_expect_wrapper<'a, T>(&'a mut self, unauthorized_retry: i32)
-> BoxFuture<'a, std::result::Result<(),()>> {
Box::pin(self.send_and_expect::<T>(unauthorized_retry))
}
}
Error:
Standard Error
Compiling playground v0.0.1 (/playground)
error[E0309]: the parameter type `T` may not live long enough
--> src/lib.rs:15:9
|
13 | fn send_and_expect_wrapper<'a, T>(&'a mut self, unauthorized_retry: i32)
| - help: consider adding an explicit lifetime bound...: `T: 'a`
14 | -> BoxFuture<'a, std::result::Result<(),()>> {
15 | Box::pin(self.send_and_expect::<T>(unauthorized_retry))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `impl futures::Future` will meet its required lifetime bounds
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
I have to do fn send_and_expect_wrapper<'a, T>(&'a mut self, unauthorized_retry: i32)
Is there a reason? I never use an instance of T so there are no concerns about lifetime.
The type check does checking on types. From its point of view, a value only does propagating it's type and triggering actions on the type (such as coercing). And in your example T is involved into unsized coercion with : 'a bound. Why? See how BoxFuture is declared
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a, Global>>;
Desugared and extremely minimized example would be like:
pub trait Future {}
struct Closure<'a, T> {
receiver: &'a mut (),
params: std::marker::PhantomData<T>,
}
impl<'a, T> Future for Closure<'a, T> {}
fn foo<'a, T>() {
let x: *mut Closure<'a, T>;
let coerced: *mut (dyn Future + 'a) = x;
}
This gives the same error[E0309].
The point is in a type checking rule: U = dyn _ + 'a implies U: 'a. Or simply (dyn _ + 'a): 'a
Applying this to our example (U = Closure<'a, T>) we get Closure<'a, T>: 'a which implies the same bound should hold on the substitutions, i.e. 'a: 'a and T: 'a. But our environment (the foo fn signature) tells nothing about the T: 'a requirement, hence the error.

Lifetime collision when bounding reference of a trait as IntoIterator

I tried to implement some graph algorithms on generic graphs. For that, I defined two graph traits which would return either a generic trait (having set-operations) SetGraph or an IntoIterator used to iterate over the nodes NeighborhoodIteratorGraph.
pub trait NeighborhoodIteratorGraph<'a> {
//which into_iterator do we have?
type IntoIter: 'a + std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter;
}
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&'a self, index: usize) -> &'a Self::S;
}
Because one is usually able to iterate over sets, I also implemented NeighborhoodIteratorGraph for all SetGraph which are able to iterate over their sets.
impl<'a, G> NeighborhoodIteratorGraph<'a> for G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter {
self.get_neighborhood(index)
}
}
I needed to add a lifetime to NeighborrhoodIteratorGraph otherwise the compiler would tell me my implementation would have an unbounded lifetime.
However I quicky run into problems with these lifetimes and I get an error for the following code:
struct Foo<'a, G: NeighborhoodIteratorGraph<'a>> {
graph: G,
//otherwise we get an error because 'a wouldn't be used
_marker: std::marker::PhantomData<&'a G>,
}
impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
It seems that the PhantomData field is more a hack and I can't find a way in which I get a set refernce which can be seen as a IntoIterator object.
Here is the Rust Playground of the problem.
Full error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 34:5...
--> src/lib.rs:34:5
|
34 | / pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
35 | | where
36 | | I: std::iter::IntoIterator<Item = usize>,
| |_________________________________________________^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:38:21
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 33:6...
--> src/lib.rs:33:6
|
33 | impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `&'a G`
found `&G`
What you want is a workaround for the lack of generic associated types, which are currently very unstable. Something Like
pub trait NeighborhoodIteratorGraph {
type IntoIter<'a>: std::iter::IntoIterator<Item = usize> + 'a;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter<'b>;
}
would serve you perfectly if they were stable.
The first thing I did is remove the lifetime bound on NeighborhoodIteratorGraph and add it to the return type:
pub trait NeighborhoodIteratorGraph {
type IntoIter: std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b;
}
I then removed unnecessary lifetime annotations from SetGraph:
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&self, index: usize) -> &Self::S;
}
I then changed the blanket impl's signature to match the modified traits, and changed the impl from G to &'a G to properly constrain the lifetime 'a:
impl<'a, G> NeighborhoodIteratorGraph for &'a G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b,
{
self.get_neighborhood(index)
}
}
Because of those changes I was able to simplify Foo and its impl:
struct Foo<G: NeighborhoodIteratorGraph> {
graph: G,
}
impl<G: NeighborhoodIteratorGraph> Foo<G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
Leaving the compiler output with nothing but dead code warnings. Playground link

Is it possible for a struct to have a reference to a trait object that has generic methods, without making the struct itself generic?

Is it possible for a struct to have a reference to a trait object that has generic methods, without making the struct itself generic?
trait Foo {
fn generic_method<T>(&self) {}
}
struct MyFoo {}
impl Foo for MyFoo {}
struct Bar<'a> {
my_foo: &'a mut (Foo + 'a),
}
impl<'a> Bar<'a> {
fn new(my_foo: &'a mut Foo) -> Self {
Self { my_foo }
}
}
This code gives me the error:
error[E0038]: the trait `Foo` cannot be made into an object
--> src/main.rs:9:5
|
9 | my_foo: &'a mut (Foo + 'a),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= note: method `generic_method` has generic type parameters
error[E0038]: the trait `Foo` cannot be made into an object
--> src/main.rs:13:5
|
13 | fn new(my_foo: &'a mut Foo) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= note: method `generic_method` has generic type parameters
It is not possible because all the possible instantiations of generic_method are not known beforehand, so there is no way that the compiler could generate a proper vtable for generic_method.
As you mentioned, you can make the struct generic instead:
struct Bar<'a, T: Foo + 'a> {
my_foo: &'a mut T
}
impl<'a, T: Foo> Bar<'a, T> {
fn new(my_foo: &'a mut T) -> Self {
Self {my_foo}
}
}

Storing a closure with lifetimes in a struct

I'm trying to store closures in a Vec that is part of a struct. The closure is a factory function which receives 2 references as arguments and produces a trait object which stores the references the closure receives as arguments.
Because of that, the produced trait object has a lifetime that must not exceed the lifetime of the references. Also component_registrations will be accessed from multiple threads and is therefore wrapped in an Arc<Mutex>.
I tried implementing it but the compiler says that the generic parameter F of the register_component function doesn't satisfy the trait bound used in component_registrations.
This is the relevant part of the code:
use std::sync::Mutex;
use std::sync::Arc;
pub mod gl {
pub struct Gl();
}
pub struct ComponentRegistry<'a> {
gl: &'a gl::Gl
}
pub trait Component<'a> {
}
pub struct Application {
component_registrations: Arc<Mutex<Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b>> + Send + 'static>>>>
}
impl Application {
pub fn new() -> Application {
Application {
component_registrations: Arc::new(Mutex::new(vec![]))
}
}
pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
self.component_registrations.lock().unwrap().push(Box::new(register));
}
}
error[E0277]: the trait bound `for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not satisfied
--> src/main.rs:27:59
|
27 | self.component_registrations.lock().unwrap().push(Box::new(register));
| ^^^^^^^^^^^^^^^^^^ the trait `for<'b> std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not implemented for `F`
|
= help: consider adding a `where for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` bound
= note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`
error[E0271]: type mismatch resolving `for<'b> <F as std::ops::FnOnce<(&'b ComponentRegistry<'b>, &'b gl::Gl)>>::Output == std::boxed::Box<Component<'b>>`
--> src/main.rs:27:59
|
27 | self.component_registrations.lock().unwrap().push(Box::new(register));
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
|
note: concrete lifetime that was found is the lifetime 'a as defined on the method body at 26:5
--> src/main.rs:26:5
|
26 | / pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
27 | | self.component_registrations.lock().unwrap().push(Box::new(register));
28 | | }
| |_____^
= note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`
If you use a higher ranked lifetime when you define your component_registrations struct field, you should use a higher ranked lifetime for F as well.
Also, if you say Box<Component<'b>>, it really means Box<Component<'b> + 'static> (so the trait object can contain only owned data). What you really need is Box<Component<'b> + 'b>, which means it is a trait object that implements Component<'b> and it can also contain borrowed data which live at least as long as 'b.
The relevant part is
pub struct Application {
component_registrations: Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static>>
}
impl Application {
pub fn register_component<F>(&mut self, register: F) where F: for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static {
self.component_registrations.push(Box::new(register));
}
}
You can see the full example. Note, that I removed the Arc and Mutex types from your example since they were not relevant.

Resources