`ArrayView` should be covariant over lifetime
patengel opened this issue · comments
Take a look at the following example:
fn reference_covariant<'a>(x: &'static f64) -> &'a f64 {
x
}
fn arrayview_covariant<'a>(x: ArrayView1<'static, f64>) -> ArrayView1<'a, f64> {
x
}
The first compiles fine, the second one does not compile and give the following error message:
fn arrayview_covariant<'a>(x: ArrayView1<'static, f64>) -> ArrayView1<'a, f64> {
-- lifetime `'a` defined here
x
^ returning this value requires that `'a` must outlive `'static`
note: requirement occurs because of the type `ArrayBase<ViewRepr<&f64>, Dim<[usize; 1]>>`, which makes the generic argument `ViewRepr<&f64>` invariant
note: the struct `ArrayBase<S, D>` is invariant over the parameter `S`
The problem is caused by the usage of S::Elem
inside the definition of ArrayBase
.
I stumbled across this problem, since I used ArrayView
deep inside a data structure which should be covariant.
As a user of ndarray I would assume that ArrayView
s behave the same as Rust references, but I see fixing this bug is hard without interface changes.
Is there an easy work-around for such problems? I currently do not know of any...
Does the method reborrow help in your case? https://docs.rs/ndarray/latest/ndarray/type.ArrayView.html#method.reborrow
No sadly it does not. The functions in the code work on references to the complete data structure, and therefore using reborrow would require to duplicate the complete data structure.
Edit: After looking at it, this is probably related to #1341
I have minimized it to this snippet: If either the Drop
implementation is removed or ArrayBase does not have <S as MyTrait>::Elem
and S
as elements at the same time, the covariance works. Looks to me like a limitation of the Rust compiler
fn x<'s>(x: &'s ArrayBase<OwnedRepr<&'s str>>) {
()
}
pub struct ArrayBase<S>
where
S: MyTrait, {
pub data: S,
pub ptr: <S as MyTrait>::Elem,
}
trait MyTrait {
type Elem;
}
pub struct OwnedRepr<A>(A);
impl<A> Drop for OwnedRepr<A> {
fn drop(&mut self) {
todo!()
}
}
impl<T> MyTrait for OwnedRepr<T> {
type Elem = T;
}
fn main() {
let elem = "abc";
let data = OwnedRepr(elem);
let input = ArrayBase {
data,
ptr: elem
};
x(&input);
}