Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,31 @@ pub type Ixs = isize;
/// The `ArrayBase<S, D>` is parameterized by `S` for the data container and
/// `D` for the dimensionality.
///
/// A third parameter, `A`, names the element type and defaults to `S::Elem`,
/// so it can usually be left out. The exception is a struct of your own with
/// an `ArrayBase` field: the compiler cannot see through the projection
/// `S::Elem` when computing the struct's variance, so leaving `A` defaulted
/// makes the struct invariant over `S` and any lifetimes in it. Spell out `A`
/// to keep the field covariant (the type aliases below already do this):
///
/// ```
/// use ndarray::{ArrayBase, Ix1, RawData, ViewRepr};
///
/// struct Wrapper<A, S: RawData<Elem = A>>
/// {
/// data: ArrayBase<S, Ix1, A>,
/// }
///
/// // Compiles only because `Wrapper` is covariant over `S`.
/// fn shorten<'a: 'b, 'b>(w: Wrapper<f64, ViewRepr<&'a f64>>) -> Wrapper<f64, ViewRepr<&'b f64>>
/// {
/// w
/// }
/// #
/// # let a = ndarray::arr1(&[1., 2.]);
/// # assert_eq!(shorten(Wrapper { data: a.view() }).data[1], 2.);
/// ```
///
/// Type aliases [`Array`], [`ArcArray`], [`CowArray`], [`ArrayView`], and
/// [`ArrayViewMut`] refer to `ArrayBase` with different types for the data
/// container: arrays with different kinds of ownership or different kinds of array views.
Expand Down Expand Up @@ -1574,7 +1599,7 @@ pub struct RawRef<A, D>(LayoutRef<A, D>);
///
/// + [Constructor Methods for Owned Arrays](ArrayBase#constructor-methods-for-owned-arrays)
/// + [Methods For All Array Types](ArrayBase#methods-for-all-array-types)
pub type ArcArray<A, D> = ArrayBase<OwnedArcRepr<A>, D>;
pub type ArcArray<A, D> = ArrayBase<OwnedArcRepr<A>, D, A>;

/// An array that owns its data uniquely.
///
Expand All @@ -1597,7 +1622,7 @@ pub type ArcArray<A, D> = ArrayBase<OwnedArcRepr<A>, D>;
/// [`Array3`], ...,
/// [`ArrayD`],
/// and so on.
pub type Array<A, D> = ArrayBase<OwnedRepr<A>, D>;
pub type Array<A, D> = ArrayBase<OwnedRepr<A>, D, A>;

/// An array with copy-on-write behavior.
///
Expand All @@ -1615,7 +1640,7 @@ pub type Array<A, D> = ArrayBase<OwnedRepr<A>, D>;
/// See also [`ArcArray`], which also provides
/// copy-on-write behavior but has a reference-counted pointer to the data
/// instead of either a view or a uniquely owned copy.
pub type CowArray<'a, A, D> = ArrayBase<CowRepr<'a, A>, D>;
pub type CowArray<'a, A, D> = ArrayBase<CowRepr<'a, A>, D, A>;

/// A read-only array view.
///
Expand All @@ -1628,7 +1653,7 @@ pub type CowArray<'a, A, D> = ArrayBase<CowRepr<'a, A>, D>;
/// Array views have all the methods of an array (see [`ArrayBase`]).
///
/// See also [`ArrayViewMut`].
pub type ArrayView<'a, A, D> = ArrayBase<ViewRepr<&'a A>, D>;
pub type ArrayView<'a, A, D> = ArrayBase<ViewRepr<&'a A>, D, A>;

/// A read-write array view.
///
Expand All @@ -1641,7 +1666,7 @@ pub type ArrayView<'a, A, D> = ArrayBase<ViewRepr<&'a A>, D>;
/// Array views have all the methods of an array (see [`ArrayBase`]).
///
/// See also [`ArrayView`].
pub type ArrayViewMut<'a, A, D> = ArrayBase<ViewRepr<&'a mut A>, D>;
pub type ArrayViewMut<'a, A, D> = ArrayBase<ViewRepr<&'a mut A>, D, A>;

/// A read-only array view without a lifetime.
///
Expand All @@ -1664,7 +1689,7 @@ pub type ArrayViewMut<'a, A, D> = ArrayBase<ViewRepr<&'a mut A>, D>;
///
/// You can't use this type with an arbitrary raw pointer; see
/// [`from_shape_ptr`](#method.from_shape_ptr) for details.
pub type RawArrayView<A, D> = ArrayBase<RawViewRepr<*const A>, D>;
pub type RawArrayView<A, D> = ArrayBase<RawViewRepr<*const A>, D, A>;

/// A mutable array view without a lifetime.
///
Expand All @@ -1687,7 +1712,7 @@ pub type RawArrayView<A, D> = ArrayBase<RawViewRepr<*const A>, D>;
///
/// You can't use this type with an arbitrary raw pointer; see
/// [`from_shape_ptr`](#method.from_shape_ptr) for details.
pub type RawArrayViewMut<A, D> = ArrayBase<RawViewRepr<*mut A>, D>;
pub type RawArrayViewMut<A, D> = ArrayBase<RawViewRepr<*mut A>, D, A>;

pub use data_repr::OwnedRepr;

Expand Down
79 changes: 78 additions & 1 deletion tests/variance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ndarray::{Array1, ArrayView1};
use ndarray::{arr1, ArcArray1, Array1, ArrayView1, ArrayViewMut1, CowArray, Ix1, RawArrayView};

fn arrayview_covariant<'a: 'b, 'b>(x: ArrayView1<'a, f64>) -> ArrayView1<'b, f64>
{
Expand All @@ -12,3 +12,80 @@ fn test_covariance()
let shorter_view = arrayview_covariant(x.view());
assert_eq!(shorter_view[0], 0.0);
}

// The aliases must stay covariant when used as struct fields (#1610). Struct
// variance is computed from field types without normalizing projections, so an
// alias that leaves `A` to its `<S as RawData>::Elem` default would make the
// containing struct invariant (rust-lang/rust#115799).
//
// Each `shorten_*` function compiles only if the struct is covariant.
// `RawArrayViewMut` is omitted: like `*mut T`, it is correctly invariant.

struct HoldsView<'a>(ArrayView1<'a, f64>);

fn shorten_view<'a: 'b, 'b>(x: HoldsView<'a>) -> HoldsView<'b>
{
x
}

struct HoldsViewMut<'a>(ArrayViewMut1<'a, f64>);

fn shorten_view_mut<'a: 'b, 'b>(x: HoldsViewMut<'a>) -> HoldsViewMut<'b>
{
x
}

struct HoldsCow<'a>(CowArray<'a, f64, Ix1>);

fn shorten_cow<'a: 'b, 'b>(x: HoldsCow<'a>) -> HoldsCow<'b>
{
x
}

struct HoldsViewOfRefs<'a>(ArrayView1<'a, &'a str>);

fn shorten_view_of_refs<'a: 'b, 'b>(x: HoldsViewOfRefs<'a>) -> HoldsViewOfRefs<'b>
{
x
}

struct HoldsArray<T>(Array1<T>);

fn shorten_array<'a: 'b, 'b>(x: HoldsArray<&'a str>) -> HoldsArray<&'b str>
{
x
}

struct HoldsArcArray<T>(ArcArray1<T>);

fn shorten_arc_array<'a: 'b, 'b>(x: HoldsArcArray<&'a str>) -> HoldsArcArray<&'b str>
{
x
}

struct HoldsRawView<T>(RawArrayView<T, Ix1>);

fn shorten_raw_view<'a: 'b, 'b>(x: HoldsRawView<&'a str>) -> HoldsRawView<&'b str>
{
x
}

#[test]
fn test_covariance_in_struct()
{
let mut a = arr1(&[1., 2.]);
assert_eq!(shorten_view(HoldsView(a.view())).0[0], 1.);
assert_eq!(shorten_cow(HoldsCow(CowArray::from(a.view()))).0[1], 2.);
{
let HoldsViewMut(mut v) = shorten_view_mut(HoldsViewMut(a.view_mut()));
v[0] = 3.;
}
assert_eq!(a[0], 3.);

let s = String::from("hello");
let strs = arr1(&[s.as_str()]);
assert_eq!(shorten_view_of_refs(HoldsViewOfRefs(strs.view())).0[0], "hello");
assert_eq!(shorten_array(HoldsArray(strs.clone())).0[0], "hello");
assert_eq!(shorten_arc_array(HoldsArcArray(strs.clone().into_shared())).0[0], "hello");
assert_eq!(shorten_raw_view(HoldsRawView(strs.raw_view())).0.len(), 1);
}