diff options
Diffstat (limited to '')
64 files changed, 1811 insertions, 0 deletions
diff --git a/src/test/ui/variance-intersection-of-ref-and-opt-ref.rs b/src/test/ui/variance-intersection-of-ref-and-opt-ref.rs new file mode 100644 index 000000000..74707a98d --- /dev/null +++ b/src/test/ui/variance-intersection-of-ref-and-opt-ref.rs @@ -0,0 +1,25 @@ +// run-pass +// Elaborated version of the opening example from RFC 738. This failed +// to compile before variance because invariance of `Option` prevented +// us from approximating the lifetimes of `field1` and `field2` to a +// common intersection. + +#![allow(dead_code)] + +struct List<'l> { + field1: &'l i32, + field2: Option<&'l i32>, +} + +fn foo(field1: &i32, field2: Option<&i32>) -> i32 { + let list = List { field1: field1, field2: field2 }; + *list.field1 + list.field2.cloned().unwrap_or(0) +} + +fn main() { + let x = 22; + let y = Some(3); + let z = None; + assert_eq!(foo(&x, y.as_ref()), 25); + assert_eq!(foo(&x, z.as_ref()), 22); +} diff --git a/src/test/ui/variance-iterators-in-libcore.rs b/src/test/ui/variance-iterators-in-libcore.rs new file mode 100644 index 000000000..a542e44d5 --- /dev/null +++ b/src/test/ui/variance-iterators-in-libcore.rs @@ -0,0 +1,10 @@ +// run-pass + +#![allow(dead_code)] + +use std::iter::{Fuse, Zip}; + +fn fuse_covariant<'a, I>(iter: Fuse<&'static I>) -> Fuse<&'a I> { iter } +fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter } + +fn main() { } diff --git a/src/test/ui/variance/variance-associated-consts.rs b/src/test/ui/variance/variance-associated-consts.rs new file mode 100644 index 000000000..da55bc962 --- /dev/null +++ b/src/test/ui/variance/variance-associated-consts.rs @@ -0,0 +1,17 @@ +// Test that the variance computation considers types that +// appear in const expressions to be invariant. + +#![feature(rustc_attrs)] +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Trait { + const Const: usize; +} + +#[rustc_variance] +struct Foo<T: Trait> { //~ ERROR [o] + field: [u8; <T as Trait>::Const] +} + +fn main() { } diff --git a/src/test/ui/variance/variance-associated-consts.stderr b/src/test/ui/variance/variance-associated-consts.stderr new file mode 100644 index 000000000..219f5bca9 --- /dev/null +++ b/src/test/ui/variance/variance-associated-consts.stderr @@ -0,0 +1,8 @@ +error[E0208]: [o] + --> $DIR/variance-associated-consts.rs:13:1 + | +LL | struct Foo<T: Trait> { + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-associated-types.rs b/src/test/ui/variance/variance-associated-types.rs new file mode 100644 index 000000000..1165fb53c --- /dev/null +++ b/src/test/ui/variance/variance-associated-types.rs @@ -0,0 +1,22 @@ +// Test that the variance computation considers types/regions that +// appear in projections to be invariant. + +#![feature(rustc_attrs)] + +trait Trait<'a> { + type Type; + + fn method(&'a self) { } +} + +#[rustc_variance] +struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +] + field: (T, &'a ()) +} + +#[rustc_variance] +struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o] + field: <T as Trait<'a>>::Type +} + +fn main() { } diff --git a/src/test/ui/variance/variance-associated-types.stderr b/src/test/ui/variance/variance-associated-types.stderr new file mode 100644 index 000000000..94f770eda --- /dev/null +++ b/src/test/ui/variance/variance-associated-types.stderr @@ -0,0 +1,14 @@ +error[E0208]: [-, +] + --> $DIR/variance-associated-types.rs:13:1 + | +LL | struct Foo<'a, T : Trait<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o, o] + --> $DIR/variance-associated-types.rs:18:1 + | +LL | struct Bar<'a, T : Trait<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-associated-types2.rs b/src/test/ui/variance/variance-associated-types2.rs new file mode 100644 index 000000000..e487eefea --- /dev/null +++ b/src/test/ui/variance/variance-associated-types2.rs @@ -0,0 +1,17 @@ +// Test that dyn Foo<Bar = T> is invariant with respect to T. +// Failure to enforce invariance here can be weaponized, see #71550 for details. + +trait Foo { + type Bar; +} + +fn make() -> Box<dyn Foo<Bar = &'static u32>> { + panic!() +} + +fn take<'a>(_: &'a u32) { + let _: Box<dyn Foo<Bar = &'a u32>> = make(); + //~^ ERROR lifetime may not live long enough +} + +fn main() {} diff --git a/src/test/ui/variance/variance-associated-types2.stderr b/src/test/ui/variance/variance-associated-types2.stderr new file mode 100644 index 000000000..35871c123 --- /dev/null +++ b/src/test/ui/variance/variance-associated-types2.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/variance-associated-types2.rs:13:12 + | +LL | fn take<'a>(_: &'a u32) { + | -- lifetime `'a` defined here +LL | let _: Box<dyn Foo<Bar = &'a u32>> = make(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-btree-invariant-types.rs b/src/test/ui/variance/variance-btree-invariant-types.rs new file mode 100644 index 000000000..09c93d001 --- /dev/null +++ b/src/test/ui/variance/variance-btree-invariant-types.rs @@ -0,0 +1,80 @@ +use std::collections::btree_map::{IterMut, OccupiedEntry, RangeMut, VacantEntry}; + +fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> { + v + //~^ lifetime may not live long enough +} +fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> { + v + //~^ lifetime may not live long enough +} +fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> { + v + //~^ lifetime may not live long enough +} +fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> { + v + //~^ lifetime may not live long enough +} + +fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a, &'new (), ()> { + v + //~^ lifetime may not live long enough +} +fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a, (), &'new ()> { + v + //~^ lifetime may not live long enough +} +fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a, &'static (), ()> { + v + //~^ lifetime may not live long enough +} +fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a, (), &'static ()> { + v + //~^ lifetime may not live long enough +} + +fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) + -> OccupiedEntry<'a, &'new (), ()> { + v + //~^ lifetime may not live long enough +} +fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) + -> OccupiedEntry<'a, (), &'new ()> { + v + //~^ lifetime may not live long enough +} +fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) + -> OccupiedEntry<'a, &'static (), ()> { + v + //~^ lifetime may not live long enough +} +fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) + -> OccupiedEntry<'a, (), &'static ()> { + v + //~^ lifetime may not live long enough +} + +fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) + -> VacantEntry<'a, &'new (), ()> { + v + //~^ lifetime may not live long enough +} +fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) + -> VacantEntry<'a, (), &'new ()> { + v + //~^ lifetime may not live long enough +} +fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) + -> VacantEntry<'a, &'static (), ()> { + v + //~^ lifetime may not live long enough +} +fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) + -> VacantEntry<'a, (), &'static ()> { + v + //~^ lifetime may not live long enough +} + + +fn main() { } diff --git a/src/test/ui/variance/variance-btree-invariant-types.stderr b/src/test/ui/variance/variance-btree-invariant-types.stderr new file mode 100644 index 000000000..6f7910021 --- /dev/null +++ b/src/test/ui/variance/variance-btree-invariant-types.stderr @@ -0,0 +1,202 @@ +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:4:5 + | +LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, &'new (), ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:8:5 + | +LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, (), &'new ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:12:5 + | +LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, &'static (), ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:16:5 + | +LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, (), &'static ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::IterMut<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `std::collections::btree_map::IterMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:21:5 + | +LL | fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a, &'new (), ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `RangeMut<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:25:5 + | +LL | fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a, (), &'new ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `RangeMut<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:29:5 + | +LL | fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a, &'static (), ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `RangeMut<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:33:5 + | +LL | fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a, (), &'static ()> { + | ---- lifetime `'new` defined here +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `RangeMut<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `RangeMut<'a, K, V>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:39:5 + | +LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, &'new (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:44:5 + | +LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, (), &'new ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:49:5 + | +LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, &'static (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:54:5 + | +LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) + | ---- lifetime `'new` defined here +LL | -> OccupiedEntry<'a, (), &'static ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::OccupiedEntry<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `std::collections::btree_map::OccupiedEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:60:5 + | +LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, &'new (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:65:5 + | +LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, (), &'new ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:70:5 + | +LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, &'static (), ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, &(), ()>`, which makes the generic argument `&()` invariant + = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-btree-invariant-types.rs:75:5 + | +LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) + | ---- lifetime `'new` defined here +LL | -> VacantEntry<'a, (), &'static ()> { +LL | v + | ^ returning this value requires that `'new` must outlive `'static` + | + = note: requirement occurs because of the type `std::collections::btree_map::VacantEntry<'_, (), &()>`, which makes the generic argument `()` invariant + = note: the struct `std::collections::btree_map::VacantEntry<'a, K, V, A>` is invariant over the parameter `K` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to 16 previous errors + diff --git a/src/test/ui/variance/variance-cell-is-invariant.rs b/src/test/ui/variance/variance-cell-is-invariant.rs new file mode 100644 index 000000000..62ce4f91f --- /dev/null +++ b/src/test/ui/variance/variance-cell-is-invariant.rs @@ -0,0 +1,19 @@ +// Test that Cell is considered invariant with respect to its +// type. + +use std::cell::Cell; + +struct Foo<'a> { + x: Cell<Option<&'a isize>>, +} + +fn use_<'short,'long>(c: Foo<'short>, + s: &'short isize, + l: &'long isize, + _where:Option<&'short &'long ()>) { + let _: Foo<'long> = c; + //~^ ERROR lifetime may not live long enough +} + +fn main() { +} diff --git a/src/test/ui/variance/variance-cell-is-invariant.stderr b/src/test/ui/variance/variance-cell-is-invariant.stderr new file mode 100644 index 000000000..ab5435d16 --- /dev/null +++ b/src/test/ui/variance/variance-cell-is-invariant.stderr @@ -0,0 +1,18 @@ +error: lifetime may not live long enough + --> $DIR/variance-cell-is-invariant.rs:14:12 + | +LL | fn use_<'short,'long>(c: Foo<'short>, + | ------ ----- lifetime `'long` defined here + | | + | lifetime `'short` defined here +... +LL | let _: Foo<'long> = c; + | ^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` + | + = help: consider adding the following bound: `'short: 'long` + = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Foo<'a>` is invariant over the parameter `'a` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-contravariant-arg-object.rs b/src/test/ui/variance/variance-contravariant-arg-object.rs new file mode 100644 index 000000000..701fcaf69 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-arg-object.rs @@ -0,0 +1,27 @@ +#![allow(dead_code)] + +// Test that even when `T` is only used in contravariant position, it +// is treated as invariant. + +trait Get<T> : 'static { + fn get(&self, t: T); +} + +fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) + -> Box<dyn Get<&'min i32>> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + -> Box<dyn Get<&'max i32>> + where 'max : 'min +{ + // Previously OK: + v + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/variance/variance-contravariant-arg-object.stderr b/src/test/ui/variance/variance-contravariant-arg-object.stderr new file mode 100644 index 000000000..ab28315e1 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-arg-object.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-object.rs:14:5 + | +LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-object.rs:23:5 + | +LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.rs b/src/test/ui/variance/variance-contravariant-arg-trait-match.rs new file mode 100644 index 000000000..e0b280105 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] + +// Test that even when `T` is only used in contravariant position, it +// is treated as invariant. + +trait Get<T> { + fn get(&self, t: T); +} + +fn get_min_from_max<'min, 'max, G>() + where 'max : 'min, G : Get<&'max i32> +{ + impls_get::<G,&'min i32>() + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max, G>() + where 'max : 'min, G : Get<&'min i32> +{ + // Previously OK, but now an error because traits are invariant: + + impls_get::<G,&'max i32>() + //~^ ERROR lifetime may not live long enough +} + +fn impls_get<G,T>() where G : Get<T> { } + +fn main() { } diff --git a/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr new file mode 100644 index 000000000..df9d93907 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-arg-trait-match.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-trait-match.rs:13:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<G,&'min i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-contravariant-arg-trait-match.rs:22:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<G,&'max i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.rs b/src/test/ui/variance/variance-contravariant-self-trait-match.rs new file mode 100644 index 000000000..8a10554f3 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-self-trait-match.rs @@ -0,0 +1,29 @@ +#![allow(dead_code)] + +// Test that even when `Self` is only used in contravariant position, it +// is treated as invariant. + +trait Get { + fn get(&self); +} + +fn get_min_from_max<'min, 'max, G>() + where 'max : 'min, G : 'max, &'max G : Get +{ + impls_get::<&'min G>(); + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max, G>() + where 'max : 'min, G : 'max, &'min G : Get +{ + // Previously OK, but now error because traits are invariant with + // respect to all inputs. + + impls_get::<&'max G>(); + //~^ ERROR lifetime may not live long enough +} + +fn impls_get<G>() where G : Get { } + +fn main() { } diff --git a/src/test/ui/variance/variance-contravariant-self-trait-match.stderr b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr new file mode 100644 index 000000000..bfea1b1b3 --- /dev/null +++ b/src/test/ui/variance/variance-contravariant-self-trait-match.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-contravariant-self-trait-match.rs:13:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'min G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-contravariant-self-trait-match.rs:23:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'max G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-covariant-arg-object.rs b/src/test/ui/variance/variance-covariant-arg-object.rs new file mode 100644 index 000000000..89cf3117a --- /dev/null +++ b/src/test/ui/variance/variance-covariant-arg-object.rs @@ -0,0 +1,27 @@ +#![allow(dead_code)] + +// Test that even when `T` is only used in covariant position, it +// is treated as invariant. + +trait Get<T> : 'static { + fn get(&self) -> T; +} + +fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) + -> Box<dyn Get<&'min i32>> + where 'max : 'min +{ + // Previously OK, now an error as traits are invariant. + v + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + -> Box<dyn Get<&'max i32>> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/variance/variance-covariant-arg-object.stderr b/src/test/ui/variance/variance-covariant-arg-object.stderr new file mode 100644 index 000000000..51f8cb3ec --- /dev/null +++ b/src/test/ui/variance/variance-covariant-arg-object.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-object.rs:15:5 + | +LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-object.rs:23:5 + | +LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.rs b/src/test/ui/variance/variance-covariant-arg-trait-match.rs new file mode 100644 index 000000000..68dd449d5 --- /dev/null +++ b/src/test/ui/variance/variance-covariant-arg-trait-match.rs @@ -0,0 +1,27 @@ +#![allow(dead_code)] + +// Test that even when `T` is only used in covariant position, it +// is treated as invariant. + +trait Get<T> { + fn get(&self) -> T; +} + +fn get_min_from_max<'min, 'max, G>() + where 'max : 'min, G : Get<&'max i32> +{ + // Previously OK, now an error as traits are invariant. + impls_get::<G,&'min i32>() + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max, G>() + where 'max : 'min, G : Get<&'min i32> +{ + impls_get::<G,&'max i32>() + //~^ ERROR lifetime may not live long enough +} + +fn impls_get<G,T>() where G : Get<T> { } + +fn main() { } diff --git a/src/test/ui/variance/variance-covariant-arg-trait-match.stderr b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr new file mode 100644 index 000000000..4c7b6cf7c --- /dev/null +++ b/src/test/ui/variance/variance-covariant-arg-trait-match.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-trait-match.rs:14:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<G,&'min i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-covariant-arg-trait-match.rs:21:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<G,&'max i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.rs b/src/test/ui/variance/variance-covariant-self-trait-match.rs new file mode 100644 index 000000000..93c25e980 --- /dev/null +++ b/src/test/ui/variance/variance-covariant-self-trait-match.rs @@ -0,0 +1,27 @@ +#![allow(dead_code)] + +// Test that even when `Self` is only used in covariant position, it +// is treated as invariant. + +trait Get { + fn get() -> Self; +} + +fn get_min_from_max<'min, 'max, G>() + where 'max : 'min, G : 'max, &'max G : Get +{ + // Previously OK, now an error as traits are invariant. + impls_get::<&'min G>(); + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max, G>() + where 'max : 'min, G : 'max, &'min G : Get +{ + impls_get::<&'max G>(); + //~^ ERROR lifetime may not live long enough +} + +fn impls_get<G>() where G : Get { } + +fn main() { } diff --git a/src/test/ui/variance/variance-covariant-self-trait-match.stderr b/src/test/ui/variance/variance-covariant-self-trait-match.stderr new file mode 100644 index 000000000..9b7ba3b66 --- /dev/null +++ b/src/test/ui/variance/variance-covariant-self-trait-match.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-covariant-self-trait-match.rs:14:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'min G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-covariant-self-trait-match.rs:21:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'max G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-invariant-arg-object.rs b/src/test/ui/variance/variance-invariant-arg-object.rs new file mode 100644 index 000000000..7381b4130 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-arg-object.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] + +trait Get<T> : 'static { + fn get(&self, t: T) -> T; +} + +fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) + -> Box<dyn Get<&'min i32>> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + -> Box<dyn Get<&'max i32>> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/variance/variance-invariant-arg-object.stderr b/src/test/ui/variance/variance-invariant-arg-object.stderr new file mode 100644 index 000000000..9793a36be --- /dev/null +++ b/src/test/ui/variance/variance-invariant-arg-object.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-object.rs:11:5 + | +LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-object.rs:19:5 + | +LL | fn get_max_from_min<'min, 'max>(v: Box<dyn Get<&'min i32>>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.rs b/src/test/ui/variance/variance-invariant-arg-trait-match.rs new file mode 100644 index 000000000..fbcc24387 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-arg-trait-match.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] + +trait Get<T> { + fn get(&self, t: T) -> T; +} + +fn get_min_from_max<'min, 'max, G>() + where 'max : 'min, G : Get<&'max i32> +{ + impls_get::<G,&'min i32>() + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max, G>() + where 'max : 'min, G : Get<&'min i32> +{ + impls_get::<G,&'max i32>() + //~^ ERROR lifetime may not live long enough +} + +fn impls_get<G,T>() where G : Get<T> { } + +fn main() { } diff --git a/src/test/ui/variance/variance-invariant-arg-trait-match.stderr b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr new file mode 100644 index 000000000..60ffdd029 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-arg-trait-match.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-trait-match.rs:10:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<G,&'min i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-invariant-arg-trait-match.rs:17:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<G,&'max i32>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.rs b/src/test/ui/variance/variance-invariant-self-trait-match.rs new file mode 100644 index 000000000..95c4c2403 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-self-trait-match.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] + +trait Get { + fn get(&self) -> Self; +} + +fn get_min_from_max<'min, 'max, G>() + where 'max : 'min, &'max G : Get, G : 'max +{ + impls_get::<&'min G>(); + //~^ ERROR lifetime may not live long enough +} + +fn get_max_from_min<'min, 'max, G>() + where 'max : 'min, &'min G : Get, G : 'min +{ + impls_get::<&'max G>(); + //~^ ERROR lifetime may not live long enough +} + +fn impls_get<G>() where G : Get { } + +fn main() { } diff --git a/src/test/ui/variance/variance-invariant-self-trait-match.stderr b/src/test/ui/variance/variance-invariant-self-trait-match.stderr new file mode 100644 index 000000000..5b64bd091 --- /dev/null +++ b/src/test/ui/variance/variance-invariant-self-trait-match.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/variance-invariant-self-trait-match.rs:10:5 + | +LL | fn get_min_from_max<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'min G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: lifetime may not live long enough + --> $DIR/variance-invariant-self-trait-match.rs:17:5 + | +LL | fn get_max_from_min<'min, 'max, G>() + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | impls_get::<&'max G>(); + | ^^^^^^^^^^^^^^^^^^^^ requires that `'min` must outlive `'max` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/variance/variance-issue-20533.rs b/src/test/ui/variance/variance-issue-20533.rs new file mode 100644 index 000000000..a2459f873 --- /dev/null +++ b/src/test/ui/variance/variance-issue-20533.rs @@ -0,0 +1,43 @@ +// Regression test for issue #20533. At some point, only 1 out of the +// 3 errors below were being reported. + +use std::marker::PhantomData; + +fn foo<'a, T>(_x: &'a T) -> PhantomData<&'a ()> { + PhantomData +} + +struct Wrap<T>(T); + +fn bar<'a, T>(_x: &'a T) -> Wrap<PhantomData<&'a ()>> { + Wrap(PhantomData) +} + +struct Baked<'a>(PhantomData<&'a ()>); + +fn baz<'a, T>(_x: &'a T) -> Baked<'a> { + Baked(PhantomData) +} + +struct AffineU32(u32); + +fn main() { + { + let a = AffineU32(1); + let x = foo(&a); + drop(a); //~ ERROR cannot move out of `a` + drop(x); + } + { + let a = AffineU32(1); + let x = bar(&a); + drop(a); //~ ERROR cannot move out of `a` + drop(x); + } + { + let a = AffineU32(1); + let x = baz(&a); + drop(a); //~ ERROR cannot move out of `a` + drop(x); + } +} diff --git a/src/test/ui/variance/variance-issue-20533.stderr b/src/test/ui/variance/variance-issue-20533.stderr new file mode 100644 index 000000000..008e2a002 --- /dev/null +++ b/src/test/ui/variance/variance-issue-20533.stderr @@ -0,0 +1,33 @@ +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/variance-issue-20533.rs:28:14 + | +LL | let x = foo(&a); + | -- borrow of `a` occurs here +LL | drop(a); + | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here + +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/variance-issue-20533.rs:34:14 + | +LL | let x = bar(&a); + | -- borrow of `a` occurs here +LL | drop(a); + | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here + +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/variance-issue-20533.rs:40:14 + | +LL | let x = baz(&a); + | -- borrow of `a` occurs here +LL | drop(a); + | ^ move out of `a` occurs here +LL | drop(x); + | - borrow later used here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/variance/variance-object-types.rs b/src/test/ui/variance/variance-object-types.rs new file mode 100644 index 000000000..6ded24cd1 --- /dev/null +++ b/src/test/ui/variance/variance-object-types.rs @@ -0,0 +1,12 @@ +#![feature(rustc_attrs)] + + +// For better or worse, associated types are invariant, and hence we +// get an invariant result for `'a`. +#[rustc_variance] +struct Foo<'a> { //~ ERROR [o] + x: Box<dyn Fn(i32) -> &'a i32 + 'static> +} + +fn main() { +} diff --git a/src/test/ui/variance/variance-object-types.stderr b/src/test/ui/variance/variance-object-types.stderr new file mode 100644 index 000000000..ceee53aff --- /dev/null +++ b/src/test/ui/variance/variance-object-types.stderr @@ -0,0 +1,8 @@ +error[E0208]: [o] + --> $DIR/variance-object-types.rs:7:1 + | +LL | struct Foo<'a> { + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-regions-direct.rs b/src/test/ui/variance/variance-regions-direct.rs new file mode 100644 index 000000000..3f34e7655 --- /dev/null +++ b/src/test/ui/variance/variance-regions-direct.rs @@ -0,0 +1,65 @@ +// Test that we correctly infer variance for region parameters in +// various self-contained types. + +#![feature(rustc_attrs)] + +// Regions that just appear in normal spots are contravariant: + +#[rustc_variance] +struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -] + x: &'a isize, + y: &'b [isize], + c: &'c str +} + +// Those same annotations in function arguments become covariant: + +#[rustc_variance] +struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +] + x: extern "Rust" fn(&'a isize), + y: extern "Rust" fn(&'b [isize]), + c: extern "Rust" fn(&'c str), +} + +// Mutability induces invariance: + +#[rustc_variance] +struct Test4<'a, 'b:'a> { //~ ERROR [-, o] + x: &'a mut &'b isize, +} + +// Mutability induces invariance, even when in a +// contravariant context: + +#[rustc_variance] +struct Test5<'a, 'b:'a> { //~ ERROR [+, o] + x: extern "Rust" fn(&'a mut &'b isize), +} + +// Invariance is a trap from which NO ONE CAN ESCAPE. +// In other words, even though the `&'b isize` occurs in +// an argument list (which is contravariant), that +// argument list occurs in an invariant context. + +#[rustc_variance] +struct Test6<'a, 'b:'a> { //~ ERROR [-, o] + x: &'a mut extern "Rust" fn(&'b isize), +} + +// No uses at all is bivariant: + +#[rustc_variance] +struct Test7<'a> { //~ ERROR [*] + x: isize +} + +// Try enums too. + +#[rustc_variance] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] + Test8A(extern "Rust" fn(&'a isize)), + Test8B(&'b [isize]), + Test8C(&'b mut &'c str), +} + +fn main() {} diff --git a/src/test/ui/variance/variance-regions-direct.stderr b/src/test/ui/variance/variance-regions-direct.stderr new file mode 100644 index 000000000..25fb22732 --- /dev/null +++ b/src/test/ui/variance/variance-regions-direct.stderr @@ -0,0 +1,44 @@ +error[E0208]: [-, -, -] + --> $DIR/variance-regions-direct.rs:9:1 + | +LL | struct Test2<'a, 'b, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+, +, +] + --> $DIR/variance-regions-direct.rs:18:1 + | +LL | struct Test3<'a, 'b, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [-, o] + --> $DIR/variance-regions-direct.rs:27:1 + | +LL | struct Test4<'a, 'b:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+, o] + --> $DIR/variance-regions-direct.rs:35:1 + | +LL | struct Test5<'a, 'b:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [-, o] + --> $DIR/variance-regions-direct.rs:45:1 + | +LL | struct Test6<'a, 'b:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [*] + --> $DIR/variance-regions-direct.rs:52:1 + | +LL | struct Test7<'a> { + | ^^^^^^^^^^^^^^^^ + +error[E0208]: [+, -, o] + --> $DIR/variance-regions-direct.rs:59:1 + | +LL | enum Test8<'a, 'b, 'c:'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/variance/variance-regions-indirect.rs b/src/test/ui/variance/variance-regions-indirect.rs new file mode 100644 index 000000000..f84f25ada --- /dev/null +++ b/src/test/ui/variance/variance-regions-indirect.rs @@ -0,0 +1,34 @@ +// Test that we correctly infer variance for region parameters in +// case that involve multiple intricate types. +// Try enums too. + +#![feature(rustc_attrs)] + +#[rustc_variance] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *] + Test8A(extern "Rust" fn(&'a isize)), + Test8B(&'b [isize]), + Test8C(&'b mut &'c str), +} + +#[rustc_variance] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +] + f: Base<'z, 'y, 'x, 'w> +} + +#[rustc_variance] // Combine - and + to yield o +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *] + f: Base<'a, 'a, 'b, 'c> +} + +#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *] + f: Base<'a, 'b, 'a, 'c> +} + +#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o] + f: Base<'a, 'b, 'c, 'a> +} + +fn main() {} diff --git a/src/test/ui/variance/variance-regions-indirect.stderr b/src/test/ui/variance/variance-regions-indirect.stderr new file mode 100644 index 000000000..fc52492d7 --- /dev/null +++ b/src/test/ui/variance/variance-regions-indirect.stderr @@ -0,0 +1,32 @@ +error[E0208]: [+, -, o, *] + --> $DIR/variance-regions-indirect.rs:8:1 + | +LL | enum Base<'a, 'b, 'c:'b, 'd> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [*, o, -, +] + --> $DIR/variance-regions-indirect.rs:15:1 + | +LL | struct Derived1<'w, 'x:'y, 'y, 'z> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o, o, *] + --> $DIR/variance-regions-indirect.rs:20:1 + | +LL | struct Derived2<'a, 'b:'a, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o, -, *] + --> $DIR/variance-regions-indirect.rs:25:1 + | +LL | struct Derived3<'a:'b, 'b, 'c> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+, -, o] + --> $DIR/variance-regions-indirect.rs:30:1 + | +LL | struct Derived4<'a, 'b, 'c:'b> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/variance/variance-regions-unused-direct.rs b/src/test/ui/variance/variance-regions-unused-direct.rs new file mode 100644 index 000000000..2afe012bd --- /dev/null +++ b/src/test/ui/variance/variance-regions-unused-direct.rs @@ -0,0 +1,15 @@ +// Test that disallow lifetime parameters that are unused. + +use std::marker; + +struct Bivariant<'a>; //~ ERROR parameter `'a` is never used + +struct Struct<'a, 'd> { //~ ERROR parameter `'d` is never used + field: &'a [i32] +} + +trait Trait<'a, 'd> { // OK on traits + fn method(&'a self); +} + +fn main() {} diff --git a/src/test/ui/variance/variance-regions-unused-direct.stderr b/src/test/ui/variance/variance-regions-unused-direct.stderr new file mode 100644 index 000000000..1a600f5b0 --- /dev/null +++ b/src/test/ui/variance/variance-regions-unused-direct.stderr @@ -0,0 +1,19 @@ +error[E0392]: parameter `'a` is never used + --> $DIR/variance-regions-unused-direct.rs:5:18 + | +LL | struct Bivariant<'a>; + | ^^ unused parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `'d` is never used + --> $DIR/variance-regions-unused-direct.rs:7:19 + | +LL | struct Struct<'a, 'd> { + | ^^ unused parameter + | + = help: consider removing `'d`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/variance/variance-regions-unused-indirect.rs b/src/test/ui/variance/variance-regions-unused-indirect.rs new file mode 100644 index 000000000..1514e3956 --- /dev/null +++ b/src/test/ui/variance/variance-regions-unused-indirect.rs @@ -0,0 +1,11 @@ +// Test that disallow lifetime parameters that are unused. + +enum Foo<'a> { //~ ERROR parameter `'a` is never used + Foo1(Bar<'a>) +} + +enum Bar<'a> { //~ ERROR parameter `'a` is never used + Bar1(Foo<'a>) +} + +fn main() {} diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr new file mode 100644 index 000000000..93710cc13 --- /dev/null +++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr @@ -0,0 +1,19 @@ +error[E0392]: parameter `'a` is never used + --> $DIR/variance-regions-unused-indirect.rs:3:10 + | +LL | enum Foo<'a> { + | ^^ unused parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `'a` is never used + --> $DIR/variance-regions-unused-indirect.rs:7:10 + | +LL | enum Bar<'a> { + | ^^ unused parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/variance/variance-trait-bounds.rs b/src/test/ui/variance/variance-trait-bounds.rs new file mode 100644 index 000000000..ad5334602 --- /dev/null +++ b/src/test/ui/variance/variance-trait-bounds.rs @@ -0,0 +1,35 @@ +#![allow(dead_code)] +#![feature(rustc_attrs)] + +// Check that bounds on type parameters (other than `Self`) do not +// influence variance. + +trait Getter<T> { + fn get(&self) -> T; +} + +trait Setter<T> { + fn get(&self, _: T); +} + +#[rustc_variance] +struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +] + t: T, u: U +} + +#[rustc_variance] +enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +] + Foo(T) +} + +#[rustc_variance] +struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +] + t: T +} + +#[rustc_variance] +struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +] + t: T +} + +pub fn main() { } diff --git a/src/test/ui/variance/variance-trait-bounds.stderr b/src/test/ui/variance/variance-trait-bounds.stderr new file mode 100644 index 000000000..e3ef339f4 --- /dev/null +++ b/src/test/ui/variance/variance-trait-bounds.stderr @@ -0,0 +1,26 @@ +error[E0208]: [+, +] + --> $DIR/variance-trait-bounds.rs:16:1 + | +LL | struct TestStruct<U,T:Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [*, +] + --> $DIR/variance-trait-bounds.rs:21:1 + | +LL | enum TestEnum<U,T:Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [*, +] + --> $DIR/variance-trait-bounds.rs:26:1 + | +LL | struct TestContraStruct<U,T:Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [*, +] + --> $DIR/variance-trait-bounds.rs:31:1 + | +LL | struct TestBox<U,T:Getter<U>+Setter<U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/variance/variance-trait-matching.rs b/src/test/ui/variance/variance-trait-matching.rs new file mode 100644 index 000000000..b4efee7d6 --- /dev/null +++ b/src/test/ui/variance/variance-trait-matching.rs @@ -0,0 +1,38 @@ +#![allow(dead_code)] + +// Get<T> is covariant in T +trait Get<T> { + fn get(&self) -> T; +} + +struct Cloner<T:Clone> { + t: T +} + +impl<T:Clone> Get<T> for Cloner<T> { + fn get(&self) -> T { + self.t.clone() + } +} + +fn get<'a, G>(get: &G) -> i32 + where G : Get<&'a i32> +{ + // This fails to type-check because, without variance, we can't + // use `G : Get<&'a i32>` as evidence that `G : Get<&'b i32>`, + // even if `'a : 'b`. + pick(get, &22) //~ ERROR explicit lifetime required in the type of `get` [E0621] +} + +fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32 + where G : Get<&'b i32> +{ + let v = *get.get(); + if v % 2 != 0 { v } else { *if_odd } +} + +fn main() { + let x = Cloner { t: &23 }; + let y = get(&x); + assert_eq!(y, 23); +} diff --git a/src/test/ui/variance/variance-trait-matching.stderr b/src/test/ui/variance/variance-trait-matching.stderr new file mode 100644 index 000000000..3308cc6d2 --- /dev/null +++ b/src/test/ui/variance/variance-trait-matching.stderr @@ -0,0 +1,12 @@ +error[E0621]: explicit lifetime required in the type of `get` + --> $DIR/variance-trait-matching.rs:24:5 + | +LL | fn get<'a, G>(get: &G) -> i32 + | -- help: add explicit lifetime `'a` to the type of `get`: `&'a G` +... +LL | pick(get, &22) + | ^^^^^^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/variance/variance-trait-object-bound.rs b/src/test/ui/variance/variance-trait-object-bound.rs new file mode 100644 index 000000000..ec3c973bc --- /dev/null +++ b/src/test/ui/variance/variance-trait-object-bound.rs @@ -0,0 +1,18 @@ +// Checks that regions which appear in a trait object type are +// observed by the variance inference algorithm (and hence +// `TOption` is contavariant w/r/t `'a` and not bivariant). +// +// Issue #18262. + +#![feature(rustc_attrs)] + +use std::mem; + +trait T { fn foo(&self); } + +#[rustc_variance] +struct TOption<'a> { //~ ERROR [-] + v: Option<Box<dyn T + 'a>>, +} + +fn main() { } diff --git a/src/test/ui/variance/variance-trait-object-bound.stderr b/src/test/ui/variance/variance-trait-object-bound.stderr new file mode 100644 index 000000000..c86cf1f82 --- /dev/null +++ b/src/test/ui/variance/variance-trait-object-bound.stderr @@ -0,0 +1,8 @@ +error[E0208]: [-] + --> $DIR/variance-trait-object-bound.rs:14:1 + | +LL | struct TOption<'a> { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-types-bounds.rs b/src/test/ui/variance/variance-types-bounds.rs new file mode 100644 index 000000000..d1814dd97 --- /dev/null +++ b/src/test/ui/variance/variance-types-bounds.rs @@ -0,0 +1,43 @@ +// Test that we correctly infer variance for type parameters in +// various types and traits. + +#![feature(rustc_attrs)] + +#[rustc_variance] +struct TestImm<A, B> { //~ ERROR [+, +] + x: A, + y: B, +} + +#[rustc_variance] +struct TestMut<A, B:'static> { //~ ERROR [+, o] + x: A, + y: &'static mut B, +} + +#[rustc_variance] +struct TestIndirect<A:'static, B:'static> { //~ ERROR [+, o] + m: TestMut<A, B> +} + +#[rustc_variance] +struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o] + n: TestMut<A, B>, + m: TestMut<B, A> +} + +trait Getter<A> { + fn get(&self) -> A; +} + +trait Setter<A> { + fn set(&mut self, a: A); +} + +#[rustc_variance] +struct TestObject<A, R> { //~ ERROR [o, o] + n: Box<dyn Setter<A>+Send>, + m: Box<dyn Getter<R>+Send>, +} + +fn main() {} diff --git a/src/test/ui/variance/variance-types-bounds.stderr b/src/test/ui/variance/variance-types-bounds.stderr new file mode 100644 index 000000000..dbe8af75d --- /dev/null +++ b/src/test/ui/variance/variance-types-bounds.stderr @@ -0,0 +1,32 @@ +error[E0208]: [+, +] + --> $DIR/variance-types-bounds.rs:7:1 + | +LL | struct TestImm<A, B> { + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+, o] + --> $DIR/variance-types-bounds.rs:13:1 + | +LL | struct TestMut<A, B:'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+, o] + --> $DIR/variance-types-bounds.rs:19:1 + | +LL | struct TestIndirect<A:'static, B:'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o, o] + --> $DIR/variance-types-bounds.rs:24:1 + | +LL | struct TestIndirect2<A:'static, B:'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o, o] + --> $DIR/variance-types-bounds.rs:38:1 + | +LL | struct TestObject<A, R> { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/variance/variance-types.rs b/src/test/ui/variance/variance-types.rs new file mode 100644 index 000000000..b9b6d9c9b --- /dev/null +++ b/src/test/ui/variance/variance-types.rs @@ -0,0 +1,41 @@ +#![allow(dead_code)] +#![feature(rustc_attrs)] + +use std::cell::Cell; + +// Check that a type parameter which is only used in a trait bound is +// not considered bivariant. + +#[rustc_variance] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o] + t: &'a mut (A,B) +} + +#[rustc_variance] +struct InvariantCell<A> { //~ ERROR [o] + t: Cell<A> +} + +#[rustc_variance] +struct InvariantIndirect<A> { //~ ERROR [o] + t: InvariantCell<A> +} + +#[rustc_variance] +struct Covariant<A> { //~ ERROR [+] + t: A, u: fn() -> A +} + +#[rustc_variance] +struct Contravariant<A> { //~ ERROR [-] + t: fn(A) +} + +#[rustc_variance] +enum Enum<A,B,C> { //~ ERROR [+, -, o] + Foo(Covariant<A>), + Bar(Contravariant<B>), + Zed(Covariant<C>,Contravariant<C>) +} + +pub fn main() { } diff --git a/src/test/ui/variance/variance-types.stderr b/src/test/ui/variance/variance-types.stderr new file mode 100644 index 000000000..8358b18b7 --- /dev/null +++ b/src/test/ui/variance/variance-types.stderr @@ -0,0 +1,38 @@ +error[E0208]: [-, o, o] + --> $DIR/variance-types.rs:10:1 + | +LL | struct InvariantMut<'a,A:'a,B:'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o] + --> $DIR/variance-types.rs:15:1 + | +LL | struct InvariantCell<A> { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [o] + --> $DIR/variance-types.rs:20:1 + | +LL | struct InvariantIndirect<A> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+] + --> $DIR/variance-types.rs:25:1 + | +LL | struct Covariant<A> { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [-] + --> $DIR/variance-types.rs:30:1 + | +LL | struct Contravariant<A> { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0208]: [+, -, o] + --> $DIR/variance-types.rs:35:1 + | +LL | enum Enum<A,B,C> { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/variance/variance-unused-region-param.rs b/src/test/ui/variance/variance-unused-region-param.rs new file mode 100644 index 000000000..f0e4e03c9 --- /dev/null +++ b/src/test/ui/variance/variance-unused-region-param.rs @@ -0,0 +1,7 @@ +// Test that we report an error for unused type parameters in types. + +struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used +enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used +trait SomeTrait<'a> { fn foo(&self); } // OK on traits. + +fn main() {} diff --git a/src/test/ui/variance/variance-unused-region-param.stderr b/src/test/ui/variance/variance-unused-region-param.stderr new file mode 100644 index 000000000..7c7ec40ba --- /dev/null +++ b/src/test/ui/variance/variance-unused-region-param.stderr @@ -0,0 +1,19 @@ +error[E0392]: parameter `'a` is never used + --> $DIR/variance-unused-region-param.rs:3:19 + | +LL | struct SomeStruct<'a> { x: u32 } + | ^^ unused parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `'a` is never used + --> $DIR/variance-unused-region-param.rs:4:15 + | +LL | enum SomeEnum<'a> { Nothing } + | ^^ unused parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/variance/variance-unused-type-param.rs b/src/test/ui/variance/variance-unused-type-param.rs new file mode 100644 index 000000000..d11140643 --- /dev/null +++ b/src/test/ui/variance/variance-unused-type-param.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] + +// Test that we report an error for unused type parameters in types and traits, +// and that we offer a helpful suggestion. + +struct SomeStruct<A> { x: u32 } +//~^ ERROR parameter `A` is never used + +enum SomeEnum<A> { Nothing } +//~^ ERROR parameter `A` is never used + +// Here T might *appear* used, but in fact it isn't. +enum ListCell<T> { +//~^ ERROR parameter `T` is never used + Cons(Box<ListCell<T>>), + Nil +} + +struct WithBounds<T: Sized> {} +//~^ ERROR parameter `T` is never used + +struct WithWhereBounds<T> where T: Sized {} +//~^ ERROR parameter `T` is never used + +struct WithOutlivesBounds<T: 'static> {} +//~^ ERROR parameter `T` is never used + +fn main() {} diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr new file mode 100644 index 000000000..e612da118 --- /dev/null +++ b/src/test/ui/variance/variance-unused-type-param.stderr @@ -0,0 +1,54 @@ +error[E0392]: parameter `A` is never used + --> $DIR/variance-unused-type-param.rs:6:19 + | +LL | struct SomeStruct<A> { x: u32 } + | ^ unused parameter + | + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `A` to be a const parameter, use `const A: usize` instead + +error[E0392]: parameter `A` is never used + --> $DIR/variance-unused-type-param.rs:9:15 + | +LL | enum SomeEnum<A> { Nothing } + | ^ unused parameter + | + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `A` to be a const parameter, use `const A: usize` instead + +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:13:15 + | +LL | enum ListCell<T> { + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: usize` instead + +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:19:19 + | +LL | struct WithBounds<T: Sized> {} + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:22:24 + | +LL | struct WithWhereBounds<T> where T: Sized {} + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:25:27 + | +LL | struct WithOutlivesBounds<T: 'static> {} + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.rs b/src/test/ui/variance/variance-use-contravariant-struct-1.rs new file mode 100644 index 000000000..7f5906748 --- /dev/null +++ b/src/test/ui/variance/variance-use-contravariant-struct-1.rs @@ -0,0 +1,15 @@ +// Test various uses of structs with distint variances to make sure +// they permit lifetimes to be approximated as expected. + +struct SomeStruct<T>(fn(T)); + +fn foo<'min,'max>(v: SomeStruct<&'max ()>) + -> SomeStruct<&'min ()> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + + +fn main() { } diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr new file mode 100644 index 000000000..50de7c90f --- /dev/null +++ b/src/test/ui/variance/variance-use-contravariant-struct-1.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/variance-use-contravariant-struct-1.rs:10:5 + | +LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-use-contravariant-struct-2.rs b/src/test/ui/variance/variance-use-contravariant-struct-2.rs new file mode 100644 index 000000000..2113eb2ad --- /dev/null +++ b/src/test/ui/variance/variance-use-contravariant-struct-2.rs @@ -0,0 +1,17 @@ +// Test various uses of structs with distint variances to make sure +// they permit lifetimes to be approximated as expected. + +#![allow(dead_code)] +// build-pass (FIXME(62277): could be check-pass?) + +struct SomeStruct<T>(fn(T)); + +fn bar<'min,'max>(v: SomeStruct<&'min ()>) + -> SomeStruct<&'max ()> + where 'max : 'min +{ + v +} + + +fn main() { } diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.rs b/src/test/ui/variance/variance-use-covariant-struct-1.rs new file mode 100644 index 000000000..f0fd7b26e --- /dev/null +++ b/src/test/ui/variance/variance-use-covariant-struct-1.rs @@ -0,0 +1,14 @@ +// Test that a covariant struct does not permit the lifetime of a +// reference to be enlarged. + +struct SomeStruct<T>(T); + +fn foo<'min,'max>(v: SomeStruct<&'min ()>) + -> SomeStruct<&'max ()> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + +fn main() { } diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.stderr new file mode 100644 index 000000000..bab858c5a --- /dev/null +++ b/src/test/ui/variance/variance-use-covariant-struct-1.stderr @@ -0,0 +1,15 @@ +error: lifetime may not live long enough + --> $DIR/variance-use-covariant-struct-1.rs:10:5 + | +LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + +error: aborting due to previous error + diff --git a/src/test/ui/variance/variance-use-covariant-struct-2.rs b/src/test/ui/variance/variance-use-covariant-struct-2.rs new file mode 100644 index 000000000..ecd2204c9 --- /dev/null +++ b/src/test/ui/variance/variance-use-covariant-struct-2.rs @@ -0,0 +1,16 @@ +// Test that a covariant struct permits the lifetime of a reference to +// be shortened. + +#![allow(dead_code)] +// build-pass (FIXME(62277): could be check-pass?) + +struct SomeStruct<T>(T); + +fn foo<'min,'max>(v: SomeStruct<&'max ()>) + -> SomeStruct<&'min ()> + where 'max : 'min +{ + v +} + +fn main() { } diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.rs b/src/test/ui/variance/variance-use-invariant-struct-1.rs new file mode 100644 index 000000000..d40dbceb5 --- /dev/null +++ b/src/test/ui/variance/variance-use-invariant-struct-1.rs @@ -0,0 +1,23 @@ +// Test various uses of structs with distint variances to make sure +// they permit lifetimes to be approximated as expected. + +struct SomeStruct<T>(*mut T); + +fn foo<'min,'max>(v: SomeStruct<&'max ()>) + -> SomeStruct<&'min ()> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + +fn bar<'min,'max>(v: SomeStruct<&'min ()>) + -> SomeStruct<&'max ()> + where 'max : 'min +{ + v + //~^ ERROR lifetime may not live long enough +} + + +fn main() { } diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.stderr new file mode 100644 index 000000000..b9ca6e7d5 --- /dev/null +++ b/src/test/ui/variance/variance-use-invariant-struct-1.stderr @@ -0,0 +1,34 @@ +error: lifetime may not live long enough + --> $DIR/variance-use-invariant-struct-1.rs:10:5 + | +LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + = note: requirement occurs because of the type `SomeStruct<&()>`, which makes the generic argument `&()` invariant + = note: the struct `SomeStruct<T>` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: lifetime may not live long enough + --> $DIR/variance-use-invariant-struct-1.rs:18:5 + | +LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>) + | ---- ---- lifetime `'max` defined here + | | + | lifetime `'min` defined here +... +LL | v + | ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min` + | + = help: consider adding the following bound: `'min: 'max` + = note: requirement occurs because of the type `SomeStruct<&()>`, which makes the generic argument `&()` invariant + = note: the struct `SomeStruct<T>` is invariant over the parameter `T` + = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance + +error: aborting due to 2 previous errors + |