about summary refs log tree commit diff
path: root/tests/ui/impl-trait/multiple-lifetimes
diff options
context:
space:
mode:
authorAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-05 09:13:28 +0100
committerAlbert Larsan <74931857+albertlarsan68@users.noreply.github.com>2023-01-11 09:32:08 +0000
commitcf2dff2b1e3fa55fa5415d524200070d0d7aacfe (patch)
tree40a88d9a46aaf3e8870676eb2538378b75a263eb /tests/ui/impl-trait/multiple-lifetimes
parentca855e6e42787ecd062d81d53336fe6788ef51a9 (diff)
downloadrust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.tar.gz
rust-cf2dff2b1e3fa55fa5415d524200070d0d7aacfe.zip
Move /src/test to /tests
Diffstat (limited to 'tests/ui/impl-trait/multiple-lifetimes')
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/error-handling-2.rs26
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr12
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr15
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/error-handling.rs26
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr15
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs50
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs25
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs28
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs25
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs42
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs36
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr17
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs39
-rw-r--r--tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr17
14 files changed, 373 insertions, 0 deletions
diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
new file mode 100644
index 00000000000..2a2be6b7429
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
new file mode 100644
index 00000000000..90875708094
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling.polonius.stderr
new file mode 100644
index 00000000000..ccd0040030d
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/error-handling.rs b/tests/ui/impl-trait/multiple-lifetimes/error-handling.rs
new file mode 100644
index 00000000000..367e7f4e6ea
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling.stderr
new file mode 100644
index 00000000000..01d9f506a0c
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/tests/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
new file mode 100644
index 00000000000..5251eeee8bb
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
new file mode 100644
index 00000000000..0bddce49b40
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
new file mode 100644
index 00000000000..e363fdb36e3
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
new file mode 100644
index 00000000000..0f21dd5ffe5
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
new file mode 100644
index 00000000000..13ad1f7215f
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
new file mode 100644
index 00000000000..c6eea5323fd
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
new file mode 100644
index 00000000000..ec49a61795a
--- /dev/null
+++ b/tests/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 `impl Trait<'d, 'e>` 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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
new file mode 100644
index 00000000000..adcbca2a438
--- /dev/null
+++ b/tests/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/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
new file mode 100644
index 00000000000..c36f9bc6957
--- /dev/null
+++ b/tests/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 `impl Trait<'a, 'b>` 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`.