Lifetime error when making parameter generic - rust

I've reduced my problem to the following code:
struct Struct<'a, 'b, T> {
a: &'a T,
b: &'b T,
}
trait Trait<'a, 'b, T> {
fn a(&self) -> &'a T;
fn b(&self) -> &'b T;
}
impl<'a, 'b, T> Trait<'a, 'b, T> for Struct<'a, 'b, T> {
fn a(&self) -> &'a T {
self.a
}
fn b(&self) -> &'b T {
self.b
}
}
struct Confused<T> {
field: T,
}
impl<T> Confused<T> {
fn foo<'a, 'b>(&'a self, param: &Struct<'a, 'b, T>) -> &'a T {
param.b();
param.a()
}
fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T {
param.b();
param.a()
}
}
The function foo is okay, but when I replace the concrete type Struct<'a, 'b, T> with a generic type U: Trait<'a, 'b, T>, I get the following error:
error[E0309]: the parameter type `T` may not live long enough
--> src/lib.rs:31:15
|
24 | impl<T> Confused<T> {
| - help: consider adding an explicit lifetime bound `T: 'b`...
...
31 | param.b();
| ^
|
note: ...so that the reference type `&'b T` does not outlive the data it points at
--> src/lib.rs:31:15
|
31 | param.b();
| ^
The suggestion to add the bound T: 'b doesn't make sense to me, since 'b is a parameter to bar(). How can I fix bar() to accept any implementation of Trait<'a, 'b, T> as a parameter?

When you write a generic type such as:
struct Foo<'a, T> {
a: &'a T,
}
Rust automatically adds an implicit restriction of the type T: 'a, because your reference to T cannot live longer than T itself. This is automatic because your type would not work without it.
But when you do something like:
impl<T> Foo {
fn bar<'a, 'b>() -> &'a T {/*...*/}
}
there is an automatic T: 'a but not a T: 'b because there is no &'b T anywhere.
The solution is to add those constraints by yourself. In your code it would be something like this:
impl<T> Confused<T> {
fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T
where
T: 'b, //<--- here!
{
param.b();
param.a()
}
}

Related

When &self has different lifetime than the struct

On this example
use std::marker::PhantomData;
pub struct A<'a, T> {
elements: Vec<B<'a, T>>
}
pub struct B<'a, T> {
_phantom: PhantomData<&'a T>
}
impl<'a, T> A<'a, T> {
pub fn iter(& self) -> Iter<'a, T> {
Iter {
iter: self.elements.iter(),
}
}
}
pub struct Iter<'a, T> {
iter: std::slice::Iter<'a, B<'a, T>>,
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e246ef19b9ae5f1d405bde7c59d456d7
I get
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:14:24
|
14 | iter: self.elements.iter(),
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:12:17
//...
I know why this happens: the elements in self.elements lives as long as &self, so it cannot possibly create an Iter with lifetime a. The easy solution would be to do
pub fn iter(&'a self) -> Iter<'a, T> {
Iter {
iter: self.elements.iter(),
}
}
but then I'm forced to borrow the &self for its entire existence which leads me to other problems. Whatis the easiest solution here?
Your Iter implementation is over-constrained; you have two unrelated lifetimes that are required to be the same. You should separate them:
impl<'a, T> A<'a, T> {
pub fn iter(&self) -> Iter<'a, '_, T> {
Iter {
iter: self.elements.iter(),
}
}
}
pub struct Iter<'a, 'b, T> {
iter: std::slice::Iter<'b, B<'a, T>>,
}
That way, even if 'a is invariant, you don't run into issues with linking that lifetime to self. See it working on the playground (with additional tests).

Lifetime of self embedded in Self, not &'a self

Below I have
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
which shouldn't need &'a self because the 'a already comes from MyPolynomial<'a, T>. Also, I should pass &'a[T] in PolyIterator::new in the line
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
but I'm getting an error saying that it wants a &'a (dyn Mem<'a, T> + 'a) which I have no idea why.
pub trait Mem<'r, T>
{
fn as_life_ref(&'r self) -> &'r [T];
}
pub struct PolyIterator<'a, T> {
coefficients: &'a [T]
}
impl<'a, T> PolyIterator<'a, T> {
pub fn new(coefficients: &'a[T]) -> PolyIterator<'a, T> {
todo!()
}
}
pub struct MyPolynomial<'a, T> {
coefficients: Box<dyn Mem<'a, T> + 'a>,
}
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
PolyIterator<'a, T>,
(),
> {
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
todo!()
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c3e657136252b96cd5aca91efeaea56f
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:26:3
|
26 | &self
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:31:36
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/lib.rs:24:6
|
24 | impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
= note: expected `&'a (dyn Mem<'a, T> + 'a)`
found `&(dyn Mem<'a, T> + 'a)`
Your trait definition and implementation do not line up:
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(&self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
The trait has PolyIterator bound to self, while the implementation has it bound elsewhere, these are not compatible.
It should definitely be &'a self since the PolyIterator is derived from self.coefficients, but you should use a different lifetime 'b for MyPolynomial to avoid over-constraining:
impl<'a, 'b, T> AsPolyIterator<'a, T> for MyPolynomial<'b, T> where 'a: 'b {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
Mind the where 'a: 'b since that ensures the lifetime 'b is larger than 'a. See it working on the playground.

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

Wrong trait chosen based on type parameter

I have a binary trait Resolve.
pub trait Resolve<RHS = Self> {
type Output;
fn resolve(self, rhs: RHS) -> Self::Output;
}
I implemented the trait for something trivial where both arguments are taken by reference (self is &'a Foo and rhs is &'b Foo):
struct Foo;
impl <'a, 'b> Resolve<&'b Foo> for &'a Foo {
type Output = Foo;
fn resolve(self, rhs: &'b Foo) -> Self::Output {
unimplemented!()
}
}
If I now write
fn main() {
let a: &Foo = &Foo;
let b = Foo;
a.resolve(&b);
}
it will compile just fine, but if I try to implement it on my struct Signal, it will not work.
pub struct Signal<'a, T> {
ps: Vec<&'a T>,
}
impl<'a, T: Resolve<&'a T, Output = T> + 'a> Signal<'a, T> {
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:25:9
|
25 | a.resolve(b);
| ^ cannot move out of borrowed content
How do I get this example working? (playground)
The trait bound on foo only says that T implements Resolve, but you try to call .resolve() on a value of type &T.
To say, instead, that references to T must implement Resolve, you need a higher-ranked trait bound:
impl<'a, T> Signal<'a, T>
where
for<'b> &'b T: Resolve<&'a T, Output = T>,
{
pub fn foo(&mut self) { ... }
}
After thinking about this I came up with a simpler solution that does not rely on HRTB.
impl<'a, T> Signal<'a, T>
where
&'a T: Resolve<&'a T, Output = T> + 'a,
{
pub fn foo(&mut self) {
let a: &T = &self.ps[0];
let b = &self.ps[1];
a.resolve(b);
}
}
This does the same, namely describe, that &T implements Resolve, but without the need of HRTB.
You have to use the where clause for this, but apart from that this is a nice and easy solution.

How to work around a HRTB bug?

This snippet does not compile because of a compiler bug:
struct Theory<'a, T: 'a> {
left: &'a T,
}
pub struct Contain<'a, T: 'a, U>
where
&'a T: IntoIterator,
for<'x> <(&'a T) as IntoIterator>::Item: PartialEq<&'x U>,
{
theory: Theory<'a, T>,
right: U,
}
impl<'a, T: 'a, U> Drop for Contain<'a, T, U>
where
&'a T: IntoIterator,
for<'x> <(&'a T) as IntoIterator>::Item: PartialEq<&'x U>,
{
fn drop(&mut self) {
//TODO
}
}
fn main() {}
I need this because I must compare the iterator Items with U; but Item is a reference type, because I call into_iter() in a borrowed collection.
I then tried something like this to work around:
struct Theory<'a, T: 'a> {
left: &'a T,
}
pub struct Contain<'a, 'b: 'a, T: 'a, U: 'b>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<&'b U>,
{
theory: Theory<'a, T>,
right: U,
_marker: ::std::marker::PhantomData<&'b ()>,
}
impl<'a, 'b, T: 'a, U> Drop for Contain<'a, 'b, T, U>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<&'b U>,
{
fn drop(&mut self) {
for left in self.theory.left.into_iter() {
if left == &self.right {
return;
}
}
//handle case where all lefts are different of right
}
}
fn main() {}
But I got a:
cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:22:24
|
22 | if left == &self.right {
| ^^^^^^^^^^^
|
How can I iterate over left, then compare each elements with right?
You can simply require the trait bound PartialEq<B>. The methods eq and ne from the trait take all arguments by reference, so there is no reason why requiring PartialEq for a reference to a type.
So this works:
impl<'a, 'b, T: 'a, U> Drop for Contain<'a, 'b, T, U>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<U>, // <-- change 1
{
fn drop(&mut self) {
for left in self.theory.left.into_iter() {
if left == self.right { // <-- change 2
return;
}
}
//handle case where all lefts are different of right
}
}

Resources