summaryrefslogtreecommitdiffstats
path: root/src/test/ui/impl-trait/multiple-lifetimes
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/impl-trait/multiple-lifetimes')
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs26
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr12
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr15
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs26
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr15
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs50
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs25
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs28
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs25
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs42
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs36
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr17
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs39
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr17
14 files changed, 373 insertions, 0 deletions
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
new file mode 100644
index 000000000..2a2be6b74
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
@@ -0,0 +1,26 @@
+#![feature(type_alias_impl_trait)]
+
+#[derive(Clone)]
+struct CopyIfEq<T, U>(T, U);
+
+impl<T: Copy> Copy for CopyIfEq<T, T> {}
+
+type E<'a, 'b> = impl Sized;
+
+fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);
+
+ // This assignment requires that `x` and `y` have the same type due to the
+ // `Copy` impl. The reason why we are using a copy to create a constraint
+ // is that only borrow checking (not regionck in type checking) enforces
+ // this bound.
+ let u = v;
+ let _: *mut &'a i32 = u.1;
+ unsafe {
+ let _: &'b i32 = *u.0;
+ }
+ u.0
+ //~^ ERROR hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
new file mode 100644
index 000000000..908757080
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
@@ -0,0 +1,12 @@
+error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
+ --> $DIR/error-handling-2.rs:22:5
+ |
+LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ | -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here
+...
+LL | u.0
+ | ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
new file mode 100644
index 000000000..ccd004003
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/error-handling.rs:22:16
+ |
+LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | let _: &'b i32 = *u.0;
+ | ^^^^^^^ type annotation requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
new file mode 100644
index 000000000..367e7f4e6
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
@@ -0,0 +1,26 @@
+#![feature(type_alias_impl_trait)]
+
+#[derive(Clone)]
+struct CopyIfEq<T, U>(T, U);
+
+impl<T: Copy> Copy for CopyIfEq<T, T> {}
+
+type E<'a, 'b> = impl Sized;
+
+fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);
+
+ // This assignment requires that `x` and `y` have the same type due to the
+ // `Copy` impl. The reason why we are using a copy to create a constraint
+ // is that only borrow checking (not regionck in type checking) enforces
+ // this bound.
+ let u = v;
+ let _: *mut &'a i32 = u.1;
+ unsafe {
+ let _: &'b i32 = *u.0;
+ //~^ ERROR lifetime may not live long enough
+ }
+ u.0
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr
new file mode 100644
index 000000000..01d9f506a
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr
@@ -0,0 +1,15 @@
+error: lifetime may not live long enough
+ --> $DIR/error-handling.rs:20:16
+ |
+LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | let _: &'b i32 = *u.0;
+ | ^^^^^^^ type annotation requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
new file mode 100644
index 000000000..5251eeee8
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
@@ -0,0 +1,50 @@
+// edition:2018
+// check-pass
+
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// `Invert<'a> <: Invert<'b>` if `'b: 'a`, unlike most types.
+//
+// I am purposefully avoiding the terms co- and contra-variant because
+// their application to regions depends on how you interpreted Rust
+// regions. -nikomatsakis
+struct Invert<'a>(fn(&'a u8));
+
+fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Invert<'a>, b: Invert<'b>) -> impl Trait<'d, 'e>
+where
+ 'c: 'a,
+ 'c: 'b,
+ 'd: 'c,
+{
+ // Representing the where clauses as a graph, where `A: B` is an
+ // edge `B -> A`:
+ //
+ // ```
+ // 'a -> 'c -> 'd
+ // ^
+ // |
+ // 'b
+ // ```
+ //
+ // Meanwhile we return a value &'0 u8 where we have the constraints:
+ //
+ // ```
+ // '0: 'a
+ // '0: 'b
+ // '0 in ['d, 'e]
+ // ```
+ //
+ // Here, ignoring the "in" constraint, the minimal choice for `'0`
+ // is `'c`, but that is not in the "in set". Still, that reduces
+ // the range of options in the "in set" to just `'d` (`'e: 'c`
+ // does not hold).
+ let p = if condition() { a } else { b };
+ p
+}
+
+fn condition() -> bool {
+ true
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
new file mode 100644
index 000000000..0bddce49b
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
@@ -0,0 +1,25 @@
+// edition:2018
+// build-pass (FIXME(62277): could be check-pass?
+
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// Test case where we have elision in the impl trait and we have to
+// pick the right region.
+
+// Ultimately `Trait<'x, 'static>`.
+fn upper_bounds1(a: &u8) -> impl Trait<'_, 'static> {
+ (a, a)
+}
+
+// Ultimately `Trait<'x, 'x>`, so not really multiple bounds.
+fn upper_bounds2(a: &u8) -> impl Trait<'_, '_> {
+ (a, a)
+}
+
+// Kind of a weird annoying case.
+fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> {
+ (a, a)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
new file mode 100644
index 000000000..e363fdb36
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
@@ -0,0 +1,28 @@
+// edition:2018
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// Here we wind up selecting `'a` and `'b` in the hidden type because
+// those are the types that appear in the original values.
+
+type Foo<'a, 'b> = impl Trait<'a, 'b>;
+
+fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> {
+ // In this simple case, you have a hidden type `(&'0 u8, &'1 u8)` and constraints like
+ //
+ // ```
+ // 'a: '0
+ // 'b: '1
+ // '0 in ['a, 'b]
+ // '1 in ['a, 'b]
+ // ```
+ //
+ // We use the fact that `'a: 0'` must hold (combined with the in
+ // constraint) to determine that `'0 = 'a` must be the answer.
+ (a, b)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
new file mode 100644
index 000000000..0f21dd5ff
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
@@ -0,0 +1,25 @@
+// edition:2018
+// build-pass (FIXME(62277): could be check-pass?)
+
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// Here we wind up selecting `'a` and `'b` in the hidden type because
+// those are the types that appear in the original values.
+
+fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
+ // In this simple case, you have a hidden type `(&'0 u8, &'1 u8)` and constraints like
+ //
+ // ```
+ // 'a: '0
+ // 'b: '1
+ // '0 in ['a, 'b]
+ // '1 in ['a, 'b]
+ // ```
+ //
+ // We use the fact that `'a: 0'` must hold (combined with the in
+ // constraint) to determine that `'0 = 'a` must be the answer.
+ (a, b)
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
new file mode 100644
index 000000000..13ad1f721
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
@@ -0,0 +1,42 @@
+// edition:2018
+// build-pass (FIXME(62277): could be check-pass?)
+
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types.
+//
+// I am purposefully avoiding the terms co- and contra-variant because
+// their application to regions depends on how you interpreted Rust
+// regions. -nikomatsakis
+struct Ordinary<'a>(&'a u8);
+
+// Here we wind up selecting `'e` in the hidden type because
+// we need something outlived by both `'a` and `'b` and only `'e` applies.
+
+fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
+where
+ 'a: 'e,
+ 'b: 'e,
+ 'a: 'd,
+{
+ // We return a value:
+ //
+ // ```
+ // 'a: '0
+ // 'b: '1
+ // '0 in ['d, 'e]
+ // ```
+ //
+ // but we don't have it.
+ //
+ // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b.
+ let p = if condition() { a } else { b };
+ p
+}
+
+fn condition() -> bool {
+ true
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
new file mode 100644
index 000000000..c6eea5323
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
@@ -0,0 +1,36 @@
+// edition:2018
+
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types.
+//
+// I am purposefully avoiding the terms co- and contra-variant because
+// their application to regions depends on how you interpreted Rust
+// regions. -nikomatsakis
+struct Ordinary<'a>(&'a u8);
+
+// Here we get an error because none of our choices (either `'d` nor `'e`) are outlived
+// by both `'a` and `'b`.
+
+fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
+where
+ 'a: 'e,
+ 'b: 'd,
+{
+ // Hidden type `Ordinary<'0>` with constraints:
+ //
+ // ```
+ // 'a: '0
+ // 'b: '0
+ // 'a in ['d, 'e]
+ // ```
+ if condition() { a } else { b }
+ //~^ ERROR hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds
+}
+
+fn condition() -> bool {
+ true
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
new file mode 100644
index 000000000..cb1dc0b7d
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -0,0 +1,17 @@
+error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds
+ --> $DIR/ordinary-bounds-unrelated.rs:28:33
+ |
+LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
+ | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+...
+LL | if condition() { a } else { b }
+ | ^
+ |
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+ |
+LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
new file mode 100644
index 000000000..adcbca2a4
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
@@ -0,0 +1,39 @@
+// edition:2018
+
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
+
+// `Ordinary<'a> <: Ordinary<'b>` if `'a: 'b`, as with most types.
+//
+// I am purposefully avoiding the terms co- and contra-variant because
+// their application to regions depends on how you interpreted Rust
+// regions. -nikomatsakis
+struct Ordinary<'a>(&'a u8);
+
+// Here we need something outlived by `'a` *and* outlived by `'b`, but
+// we can only name `'a` and `'b` (and neither suits). So we get an
+// error. Somewhat unfortunate, though, since the caller would have to
+// consider the loans for both `'a` and `'b` alive.
+
+fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
+{
+ // We return a value:
+ //
+ // ```
+ // 'a: '0
+ // 'b: '1
+ // '0 in ['a, 'b]
+ // ```
+ //
+ // but we don't have it.
+ //
+ // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b.
+ if condition() { a } else { b }
+ //~^ ERROR hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds
+}
+
+fn condition() -> bool {
+ true
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
new file mode 100644
index 000000000..4388e6601
--- /dev/null
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -0,0 +1,17 @@
+error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds
+ --> $DIR/ordinary-bounds-unsuited.rs:31:33
+ |
+LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
+ | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
+...
+LL | if condition() { a } else { b }
+ | ^
+ |
+help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
+ |
+LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.