I am trying to implement an Iterator::chain()-like operation for a GATified lending iterator:
#![feature(generic_associated_types)]
pub trait LendingIterator {
type Item<'a> where Self: 'a;
fn next(&mut self) -> Option<Self::Item<'_>>;
}
To do this, similarly to the normal Iterator::chain(), I need a struct Chain that contains the two chained iterators and impl's LendingIterator.
The problem I have is I need to specify the iterator types A and B having matching Item generic associated types, so I tried this:
pub struct Chain<A, B> {
a: Option<A>,
b: Option<B>,
}
impl<A, B> LendingIterator for Chain<A, B>
where
A: LendingIterator,
B: for<'a> LendingIterator<Item<'a>=A::Item<'a>>
{
type Item<'a> where Self: 'a = A::Item<'a>;
fn next(&mut self) -> Option<Self::Item<'_>> {
todo!()
}
}
But I get:
error[E0311]: the parameter type `B` may not live long enough
--> src\lib.rs:63:12
|
63 | impl<A, B> LendingIterator for Chain<A, B> where A: LendingIterator, B: for<'a> LendingIterator<Item<'a>=A::Item<'a>> {
| - ^^^^^^^^^^^^^^^ ...so that the type `B` will meet its required lifetime bounds...
| |
| help: consider adding an explicit lifetime bound...: `B: 'a`
|
note: ...that is required by this bound
| ^^^^ ...so that the type `B` will meet its required lifetime bounds
Of course the compiler's suggestions don't seem to work.
How can I add the constraint that B does have a long enough lifetime?
Turns out this is a bug in rust's GAT implementation. See this:
https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/.E2.9C.94.20GAT.20LendingIterator.3A.3Achain.20Issue
https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Understanding.20the.20motivations.20for.20GATs/near/269863728
Related
Compilation of this snippet:
trait Base {
type T;
fn get_p(&self) -> &Self::T;
}
trait OnBase: Base {
fn get_a(&self) -> &A;
}
impl<S, T> OnBase for S
where
S: Base<T = dyn OnBase<T = T>>,
{
fn get_a(&self) -> &A {
self.get_p().get_a()
}
}
struct A {}
Fails with:
error[E0311]: the parameter type `T` may not live long enough
--> src/blanket_with_ref.rs:17:9
|
17 | self.get_p().get_a()
| ^^^^^^^^^^^^
|
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
--> src/blanket_with_ref.rs:16:14
|
16 | fn get_a(&self) -> &A {
| ^^^^^
note: ...so that the type `T` will meet its required lifetime bounds
--> src/blanket_with_ref.rs:17:9
|
17 | self.get_p().get_a()
| ^^^^^^^^^^^^
help: consider adding an explicit lifetime bound...
|
14 | impl <S, T: 'a> OnBase for S where S:Base<T=dyn OnBase<T=T>> {
| ++++
I vaguely comprehend that I must somehow tell it that lifetimes of Base and OnBase should be same but even if I add 'a to all traits and refrences it keeps failing.
Is it possible to somehow make it compile?
P.S. - it works if get_a returns plain A.
pps - in the real app it should be a kind of a strategy delegating to whatever impl it encapsulates
playground
This is probably what you actually want, instead of T = dyn OnBase<T = T>:
trait Base {
type T;
fn get_p(&self) -> &Self::T;
}
trait OnBase: Base {
fn get_a(&self) -> &A;
}
impl<S> OnBase for S
where
S: Base,
<S as Base>::T: OnBase,
{
fn get_a(&self) -> &A {
self.get_p().get_a()
}
}
struct A;
I'm not sure what purpose OnBase: Base serves, though. If OnBase is already Base, then why do any of this? And what should it return in get_p? With the current layout, it's really easy to get caught up in an infinite get_a recursion.
tl;dr:
Is there any way to remove the lifetime declaration from ObjectInner and move it to the foo method?
trait ObjectTrait {
type Input;
fn foo(&mut self, input: &mut Self::Input);
}
struct ObjectInner<'a> {
phantom: PhantomData<&'a ()>,
}
impl<'a> ObjectTrait for ObjectInner<'a>
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
Suppose I have the following trait definition (with an associated type Input):
trait ObjectTrait {
type Input;
fn foo(&mut self, input: &mut Self::Input);
}
I'm interested in implementing this trait for an object such that the type used for Input could potentially take a lifetime.
impl ObjectTrait for ObjectInner
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
This won't compile since lifetime 'a hasn't been defined. It makes sense, and it provides two suggestions:
error[E0261]: use of undeclared lifetime name `'a`
--> src/main.rs:13:22
|
13 | type Input = Mut<'a>;
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
13 | type Input<'a> = Mut<'a>;
| ++++
help: consider introducing lifetime `'a` here
|
11 | impl<'a> ObjectTrait for ObjectInner
| ++++
Define the lifetime either in the type or in the impl.
Defining them on the type is out of the question since this requires changing the trait definition, which doesn't make sense for users of the trait without use for this lifetime.
Defining it on the impl makes more sense, and if done naively:
impl<'a> ObjectTrait for ObjectInner
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
I get the following error/help message:
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:15:6
|
15 | impl<'a> ObjectTrait for ObjectInner
| ^^ unconstrained lifetime parameter
I need to put a constraint on the lifetime. The only way I know how to do it is by extending the ObjectInner to have the following definition:
struct ObjectInner<'a> {
phantom: PhantomData<&'a ()>,
}
impl<'a> ObjectTrait for ObjectInner<'a>
{
type Input = Mut<'a>;
fn foo(&mut self, _input: &mut Self::Input) {}
}
This already works and is the best solution I've found so far.
I wonder if there is a way to move this constraint outside of the struct definition to the declaration of the foo method. I feel this should be possible, given that if I wouldn't be implementing a trait, I could make this with:
impl ObjectInner {
fn bar<'a>(&mut self, input: &mut Mut<'a>) {}
}
I have a struct (DataSource) that holds some data (&[u8]), and a custom iterator that iterates over it.
struct DataSource<'a> {
data: &'a Vec<u8>,
}
struct MyIterator<'a> {
source: DataSource<'a>,
}
impl<'a> Iterator for MyIterator<'a> {
type Item = &'a u8;
fn next(&mut self) -> Option<Self::Item> {
let ret = &self.source.data[0];
Some(ret)
}
}
Notice a few important things here:
The Item of the iterator has a lifetime. This is only possible because the lifetime is already used by one of the struct's fields - source
The compiler is smart enough to detect that since Items lifetime is 'a, the lifetime of ret must also be 'a.
Now, due to my use-case, I would like to add the following features:
DataSource should also be able to own data.
data is not Clone.
My initial solution was to replalce data: &'a [u8] with data: D where D: Borrow<[u8]>:
struct DataHolder<D: Borrow<[u8]>> {
data: D,
}
struct MyIterator<D: Borrow<[u8]>> {
holder: DataHolder<D>,
}
impl<D: Borrow<[u8]>> Iterator for MyIterator<D> {
type Item = &u8;
fn next(&mut self) -> Option<Self::Item> {
Some(&self.holder.data.borrow()[0])
}
}
I thought this would work since due to blanket implementations both &[u8] and [u8] implement Borrow<[u8]>. However this doesn't compile. The iterator's item is &u8 so it requires an explicit lifetime. MyIterator doesn't have any lifetimes to reference so writing type Item = &'a u8 would result in an undeclared lifetime.
My next solution was to add phantom data and reference the lifetime through that:
struct DataHolder<'a, D: Borrow<[u8]>, T: 'a> {
data: D,
p: PhantomData<&'a T>,
}
struct MyIterator<'a, D: Borrow<[u8]>, T: 'a> {
holder: DataHolder<'a, D, T>,
}
impl<'a, D: Borrow<[u8]>, T> Iterator for MyIterator<'a, D, T> {
type Item = &'a u8;
fn next(&mut self) -> Option<Self::Item> {
Some(&self.holder.data.borrow()[0])
}
}
Which produces the following error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src\bin\main7c.rs:16:26
|
16 | Some(&self.holder.data.borrow()[0])
| ^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src\bin\main7c.rs:15:10
|
15 | fn next(&mut self) -> Option<Self::Item> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src\bin\main7c.rs:16:9
|
16 | Some(&self.holder.data.borrow()[0])
| ^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src\bin\main7c.rs:12:6
|
12 | impl<'a, D: Borrow<[u8]>, T> Iterator for MyIterator<'a, D, T> {
| ^^
note: ...so that the types are compatible
--> src\bin\main7c.rs:15:43
|
15 | fn next(&mut self) -> Option<Self::Item> {
| ______________________________________________^
16 | | Some(&self.holder.data.borrow()[0])
17 | | }
| |_____^
= note: expected `<MyIterator<'a, D, T> as Iterator>`
found `<MyIterator<'_, D, T> as Iterator>`
The compiler can't infer that the lifetime of the returned value must be 'a like in the first example. I could solve this giving up on implementing Iterator but that would defeat the whole point of using an iterator.
impl<'a, D: Borrow<[u8]>, T> MyIterator<'a, D, T> {
fn next(&'a mut self) -> Option<&'a u8> {
Some(&self.holder.data.borrow()[0])
}
}
Is there a way of solving this without giving up on the Iterator trait?
Is there a way of solving this without giving up on the Iterator trait?
No. Suppose D is Vec<u8>. What would be the lifetime 'a?
When it was already a reference, we could just reuse its lifetime. This is because, assuming data is &'a T, &self.data[0] where self is &'b mut self can be seen as (pseudo-Rust):
let slice_data_pointer: &'a u8 = (*self.data);
slice_data_pointer
That is, we just copy the reference.
But when data is owned, there is no reference to be copied. The only source of truth is self.data itself - and self.data is borrowed only for the lifetime of self. So you need the yielded values of iterator to depend on next()'s self. This is the classic lending/streaming iterator, and it:
Doesn't exist in the standard library.
Requires Generic Associated Types (which is part of the reason it is not in the standard library).
Allows only one yielded value to exist at any time - they can't coexist, because they all borrow mutably from self with different lifetimes. In other words, it cannot implement operations like collect().
However, we can learn from the way the actual Vec impls Iterator. Specifically, it doesn't - and so do owned values in general - they implement IntoIterator instead for a reference to them, potentially with an iter() method.
I have some types like this, where they each have a lifetime parameter.
use std::marker::PhantomData;
use std::ops::Index;
pub struct Foo<'ctx> {
bars: Vec<Bar<'ctx>>,
phantom: PhantomData<&'ctx ()>,
}
impl Foo<'_> {
pub fn get_bar(&self, index: usize) -> Option<&Bar> {
self.bars.get(index)
}
}
pub struct Bar<'ctx> {
// pretend we are using a context here
phantom: PhantomData<&'ctx ()>,
}
I'd like to implement Index for Foo, but the compiler doesn't like it:
impl <'ctx> Index<usize> for Foo<'ctx> {
type Output = Bar<'ctx>;
fn index(&self, _index: usize) -> &Self::Output {
self.get_bar(_index).unwrap()
}
}
I get this error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/ir/foo.rs:24:14
|
24 | self.get_bar(_index).unwrap()
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/ir/foo.rs:23:14
|
23 | fn index(&self, _index: usize) -> &Self::Output {
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/ir/foo.rs:24:9
|
24 | self.get_bar(_index).unwrap()
| ^^^^
note: but, the lifetime must be valid for the lifetime `'ctx` as defined here...
--> src/ir/foo.rs:20:7
|
20 | impl <'ctx> Index<usize> for Foo<'ctx> {
| ^^^^
note: ...so that the types are compatible
--> src/ir/foo.rs:23:53
|
23 | fn index(&self, _index: usize) -> &Self::Output {
| _____________________________________________________^
24 | | self.get_bar(_index).unwrap()
25 | | }
| |_____^
= note: expected `<Foo<'ctx> as Index<usize>>`
found `<Foo<'_> as Index<usize>>`
(I see a few similar questions on SO but they all seem to differ in the particulars, namely that the Output type has a lifetime parameter).
This is due to that the rust compiler cannot infer proper lifetimes when there are multiple elided lifetimes. The rust compiler can only take the omitted lifetimes as a same lifetime '_.
The inferred signature of the function get_bar is actually:
pub fn get_bar<'_>(self: &'_ Foo<'_>, index: usize) -> Option<&'_ Bar<'_>>
Note that all '_ refer to the same lifetime, this is obviously not what we need, because we don't have to keep borrowing the value of some Bar during the whole lifetime of 'ctx.
And, the inferred signature of the function index is:
fn index<'_>(self: &'_ Foo<'ctx>, _index: usize) -> &'_ Bar<'ctx>
Which is more generic than the signature of get_bar because it allows the lifetime argument of '_ to be shorter than 'ctx, therefore you cannot call get_bar within the body of index
To make it work, you have to specify an explicit 'ctx, because the elided lifetime '_ has to be the lifetime of the borrowed self.
impl<'ctx> Foo<'ctx> {
pub fn get_bar(&self, index: usize) -> Option<&Bar<'ctx>> {
self.bars.get(index)
}
}
And the signature of get_bar now turns to be:
pub fn get_bar<'_>(self: &'_ Foo<'ctx>, index: usize) -> Option<&'_ Bar<'ctx>>
Then the lifetimes in index could match the lifetimes in get_bar
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.