Repository: rust-ndarray/ndarray (rust)

Issue:
`ArrayView` should be covariant over lifetime
Take a look at the following example:
```rust
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...

Pull request:
Uses a simple fix to enable arraybase to be covariant.
See rust-lang/rust#115799 and rust-lang/rust#57440 for more details. Closes #1332

Patch:
diff --git a/src/lib.rs b/src/lib.rs
index f0b64028..9ba3b672 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1282,15 +1282,15 @@ pub type Ixs = isize;
 // may change in the future.
 //
 // [`.offset()`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset-1
-pub struct ArrayBase<S, D>
-where S: RawData
+pub struct ArrayBase<S, D, A = <S as RawData>::Elem>
+where S: RawData<Elem = A>
 {
     /// Data buffer / ownership information. (If owned, contains the data
     /// buffer; if borrowed, contains the lifetime and mutability.)
     data: S,
     /// A non-null pointer into the buffer held by `data`; may point anywhere
     /// in its range. If `S: Data`, this pointer must be aligned.
-    ptr: std::ptr::NonNull<S::Elem>,
+    ptr: std::ptr::NonNull<A>,
     /// The lengths of the axes.
     dim: D,
     /// The element count stride per axis. To be parsed as `isize`.


Test patch:
diff --git a/tests/variance.rs b/tests/variance.rs
new file mode 100644
index 00000000..e72805ff
--- /dev/null
+++ b/tests/variance.rs
@@ -0,0 +1,14 @@
+use ndarray::{Array1, ArrayView1};
+
+fn arrayview_covariant<'a: 'b, 'b>(x: ArrayView1<'a, f64>) -> ArrayView1<'b, f64>
+{
+    x
+}
+
+#[test]
+fn test_covariance()
+{
+    let x = Array1::zeros(2);
+    let shorter_view = arrayview_covariant(x.view());
+    assert_eq!(shorter_view[0], 0.0);
+}