about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Kuber <esteban@kuber.com.ar>2021-10-11 19:20:13 +0000
committerEsteban Kuber <esteban@kuber.com.ar>2021-12-10 03:08:22 +0000
commitdd81e984660bf4273470d336eaed27f9e062ce1c (patch)
treea301e55380e215d759e5d87dd2b75d71acdd7135
parentd10fe26f39983c782f1a37a447f2c10c2ef561ba (diff)
downloadrust-dd81e984660bf4273470d336eaed27f9e062ce1c.tar.gz
rust-dd81e984660bf4273470d336eaed27f9e062ce1c.zip
Clean up visual output logic
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs92
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr2
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr2
-rw-r--r--src/test/ui/async-await/issues/issue-62097.stderr8
-rw-r--r--src/test/ui/async-await/issues/issue-72312.rs6
-rw-r--r--src/test/ui/async-await/issues/issue-72312.stderr11
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr10
-rw-r--r--src/test/ui/issues/issue-16922.stderr2
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.stderr6
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-2.stderr2
-rw-r--r--src/test/ui/regions/regions-close-object-into-object-4.stderr2
-rw-r--r--src/test/ui/regions/regions-proc-bound-capture.stderr2
-rw-r--r--src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr18
-rw-r--r--src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr4
14 files changed, 61 insertions, 106 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index c7ba5087b8c..3f7aa7773d1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -139,89 +139,39 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             //    |                               ...is captured here...
             (false, sup_origin.span())
         } else {
-            (true, param.param_ty_span)
+            (!sup_origin.span().overlaps(return_sp), param.param_ty_span)
         };
         err.span_label(capture_point, &format!("this data with {}...", lifetime));
 
         debug!("try_report_static_impl_trait: param_info={:?}", param);
 
+        let mut spans = spans.clone();
+
+        if mention_capture {
+            spans.push(sup_origin.span());
+        }
+        spans.sort();
+        spans.dedup();
+
         // We try to make the output have fewer overlapping spans if possible.
-        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
-            && sup_origin.span() != return_sp
-        {
-            // Customize the spans and labels depending on their relative order so
-            // that split sentences flow correctly.
-            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
-                // Avoid the following:
-                //
-                // error: cannot infer an appropriate lifetime
-                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
-                //    |
-                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-                //    |           ----                      ---------^-
-                //
-                // and instead show:
-                //
-                // error: cannot infer an appropriate lifetime
-                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50
-                //    |
-                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-                //    |           ----                               ^
-                err.span_label(
-                    sup_origin.span(),
-                    &format!(
-                        "...is captured here, requiring it to live as long as `'static`{}",
-                        if spans.is_empty() { "" } else { "..." },
-                    ),
-                );
-            } else {
-                if return_sp < sup_origin.span() && mention_capture {
-                    err.span_label(sup_origin.span(), "...is captured here...");
-                    err.span_note(
-                        return_sp,
-                        "...and is required to live as long as `'static` here",
-                    );
-                } else {
-                    err.span_label(
-                        return_sp,
-                        &format!(
-                            "...is required to live as long as `'static` here{}",
-                            if spans.is_empty() { "" } else { "..." },
-                        ),
-                    );
-                    if mention_capture {
-                        let span = sup_origin.span();
-                        let msg = if spans.iter().any(|sp| *sp > span) {
-                            "...is captured here..."
-                        } else {
-                            "...and is captured here"
-                        };
-                        err.span_label(span, msg);
-                    }
-                }
-            }
+        let (require_msg, require_span) = if sup_origin.span().overlaps(return_sp) {
+            ("...is captured and required to live as long as `'static` here", sup_origin.span())
         } else {
-            err.span_label(
-                return_sp,
-                &format!(
-                    "...is captured and required to live as long as `'static` here{}",
-                    if spans.is_empty() { "" } else { "..." },
-                ),
-            );
+            ("...and is required to live as long as `'static` here", return_sp)
+        };
+
+        for span in &spans {
+            err.span_label(*span, "...is captured here...");
         }
 
-        for span in spans {
-            let msg =
-                format!("...and is captured here{}", if mention_capture { " too" } else { "" });
-            if span.overlaps(return_sp) {
-                err.span_note(*span, &msg);
-            } else {
-                err.span_label(*span, &msg);
-            }
+        if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
+            err.span_note(require_span, require_msg);
+        } else {
+            err.span_label(require_span, require_msg);
         }
 
         if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
-            err.span_note(*bound, "`'static` lifetime requirement introduced by this trait bound");
+            err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
         }
 
         let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
index 0be9b37263a..6f63a2c5fc3 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr
@@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
 LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
    |                  ------- this data with lifetime `'a`...
 LL |    bar(foo, x)
-   |    ----^^^---- ...is captured and required to live as long as `'static` here
+   |        ^^^  - ...is captured and required to live as long as `'static` here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 0a44864b249..eb81da7852d 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -5,7 +5,7 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |                   -------- this data with lifetime `'a`...
 ...
 LL |     bar(foo, x)
-   |     ----^^^---- ...is captured and required to live as long as `'static` here
+   |         ^^^  - ...is captured and required to live as long as `'static` here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr
index bb329a4a0c2..7aea147c6cf 100644
--- a/src/test/ui/async-await/issues/issue-62097.stderr
+++ b/src/test/ui/async-await/issues/issue-62097.stderr
@@ -4,14 +4,14 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
 LL |     pub async fn run_dummy_fn(&self) {
    |                               ^^^^^ this data with an anonymous lifetime `'_`...
 LL |         foo(|| self.bar()).await;
-   |         --- ...is required to live as long as `'static` here...
+   |         ------------------------ ...is captured here...
    |
-note: ...and is captured here
+note: ...and is required to live as long as `'static` here
   --> $DIR/issue-62097.rs:13:9
    |
 LL |         foo(|| self.bar()).await;
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-note: `'static` lifetime requirement introduced by this trait bound
+   |         ^^^
+note: `'static` lifetime requirement introduced by this bound
   --> $DIR/issue-62097.rs:4:19
    |
 LL |     F: FnOnce() + 'static
diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs
index d33685e02f1..eb0cc7e6aec 100644
--- a/src/test/ui/async-await/issues/issue-72312.rs
+++ b/src/test/ui/async-await/issues/issue-72312.rs
@@ -1,6 +1,6 @@
 // edition:2018
 fn require_static<T: 'static>(val: T) -> T {
-    //~^ NOTE 'static` lifetime requirement introduced by this trait bound
+    //~^ NOTE 'static` lifetime requirement introduced by this bound
     val
 }
 
@@ -10,8 +10,8 @@ impl Problem {
     pub async fn start(&self) { //~ ERROR E0759
         //~^ NOTE this data with an anonymous lifetime `'_`
         //~| NOTE in this expansion of desugaring of `async` block or function
-        require_static(async move { //~ NOTE ...is required to live as long as `'static` here
-            &self; //~ NOTE ...and is captured here
+        require_static(async move { //~ NOTE ...and is required to live as long as `'static` here
+            &self; //~ NOTE ...is captured here...
         });
     }
 }
diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr
index ee5ee6f0f93..7a72edd4e53 100644
--- a/src/test/ui/async-await/issues/issue-72312.stderr
+++ b/src/test/ui/async-await/issues/issue-72312.stderr
@@ -4,12 +4,15 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'
 LL |     pub async fn start(&self) {
    |                        ^^^^^ this data with an anonymous lifetime `'_`...
 ...
-LL |         require_static(async move {
-   |         -------------- ...is required to live as long as `'static` here...
 LL |             &self;
-   |             ----- ...and is captured here
+   |             ----- ...is captured here...
+   |
+note: ...and is required to live as long as `'static` here
+  --> $DIR/issue-72312.rs:13:9
    |
-note: `'static` lifetime requirement introduced by this trait bound
+LL |         require_static(async move {
+   |         ^^^^^^^^^^^^^^
+note: `'static` lifetime requirement introduced by this bound
   --> $DIR/issue-72312.rs:2:22
    |
 LL | fn require_static<T: 'static>(val: T) -> T {
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index d65dea7adc9..e80372766dc 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -80,7 +80,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
   --> $DIR/must_outlive_least_region_or_bound.rs:24:65
    |
 LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-   |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
+   |               ---- this data with an anonymous lifetime `'_`... ^ ...is captured and required to live as long as `'static` here
    |
 help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound
    |
@@ -136,7 +136,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
   --> $DIR/must_outlive_least_region_or_bound.rs:16:50
    |
 LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-   |               ----                               ^ ...is captured here, requiring it to live as long as `'static`
+   |               ----                               ^ ...is captured and required to live as long as `'static` here
    |               |
    |               this data with an anonymous lifetime `'_`...
    |
@@ -149,7 +149,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
   --> $DIR/must_outlive_least_region_or_bound.rs:18:59
    |
 LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
-   |                     -------                               ^ ...is captured here, requiring it to live as long as `'static`
+   |                     -------                               ^ ...is captured and required to live as long as `'static` here
    |                     |
    |                     this data with lifetime `'a`...
    |
@@ -162,7 +162,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
   --> $DIR/must_outlive_least_region_or_bound.rs:20:60
    |
 LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-   |               ----                                         ^ ...is captured here, requiring it to live as long as `'static`
+   |               ----                                         ^ ...is captured and required to live as long as `'static` here
    |               |
    |               this data with an anonymous lifetime `'_`...
    |
@@ -179,7 +179,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
   --> $DIR/must_outlive_least_region_or_bound.rs:22:69
    |
 LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-   |                     ------- this data with lifetime `'a`...         ^ ...is captured here, requiring it to live as long as `'static`
+   |                     ------- this data with lifetime `'a`...         ^ ...is captured and required to live as long as `'static` here
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
    |
diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr
index 8b09b7d5907..ff7b3b67140 100644
--- a/src/test/ui/issues/issue-16922.stderr
+++ b/src/test/ui/issues/issue-16922.stderr
@@ -4,7 +4,7 @@ error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `
 LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
    |                       -- this data with an anonymous lifetime `'_`...
 LL |     Box::new(value) as Box<dyn Any>
-   |              ^^^^^ ...is captured here, requiring it to live as long as `'static`
+   |              ^^^^^ ...is captured and required to live as long as `'static` here
    |
 help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound
    |
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
index 04d22e58a1d..9eb24c1bd37 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr
@@ -4,7 +4,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
 LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
    |         ----- this data with an anonymous lifetime `'_`...
 LL |     let x: Box<dyn Foo + 'static> = Box::new(v);
-   |                                              ^ ...is captured here, requiring it to live as long as `'static`
+   |                                              ^ ...is captured and required to live as long as `'static` here
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
@@ -21,7 +21,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta
 LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
    |         ----- this data with an anonymous lifetime `'_`...
 LL |     Box::new(v)
-   |              ^ ...is captured here, requiring it to live as long as `'static`
+   |              ^ ...is captured and required to live as long as `'static` here
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
@@ -39,7 +39,7 @@ LL | fn c(v: &[u8]) -> Box<dyn Foo> {
    |         ----- this data with an anonymous lifetime `'_`...
 ...
 LL |     Box::new(v)
-   |              ^ ...is captured here, requiring it to live as long as `'static`
+   |              ^ ...is captured and required to live as long as `'static` here
    |
 help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound
    |
diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr
index 9a7df8c0188..9c803d4e1d4 100644
--- a/src/test/ui/regions/regions-close-object-into-object-2.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr
@@ -4,7 +4,7 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime
 LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
    |                         ------------------ this data with lifetime `'a`...
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...is captured here, requiring it to live as long as `'static`
+   |                ^^^ ...is captured and required to live as long as `'static` here
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr
index a7a9b16b080..27bb19a89df 100644
--- a/src/test/ui/regions/regions-close-object-into-object-4.stderr
+++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr
@@ -4,7 +4,7 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime
 LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |                   ---------------- this data with lifetime `'a`...
 LL |     Box::new(B(&*v)) as Box<dyn X>
-   |                ^^^ ...is captured here, requiring it to live as long as `'static`
+   |                ^^^ ...is captured and required to live as long as `'static` here
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr
index 50b3748bf40..a257576e5d1 100644
--- a/src/test/ui/regions/regions-proc-bound-capture.stderr
+++ b/src/test/ui/regions/regions-proc-bound-capture.stderr
@@ -5,7 +5,7 @@ LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
    |                   ------ this data with an anonymous lifetime `'_`...
 LL |     // This is illegal, because the region bound on `proc` is 'static.
 LL |     Box::new(move || { *x })
-   |              ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`
+   |              ^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x`
    |
diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
index 04560ea4e29..3d6308a0825 100644
--- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
+++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr
@@ -39,13 +39,13 @@ LL |     let y = x as &dyn Bar<'_, '_>;
    |             ...is captured here...
 LL |
 LL |     y.get_b() // ERROR
-   |     --------- ...is required to live as long as `'static` here...
+   |     - ...is captured here...
    |
-note: ...and is captured here too
+note: ...and is required to live as long as `'static` here
   --> $DIR/type-checking-test-4.rs:29:5
    |
 LL |     y.get_b() // ERROR
-   |     ^
+   |     ^^^^^^^^^
 
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/type-checking-test-4.rs:33:5
@@ -53,7 +53,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
 LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                       ------------ this data with lifetime `'a`...
 LL |     <_ as Bar>::get_b(x) // ERROR
-   |     ^^^^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`
+   |     ^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
 
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/type-checking-test-4.rs:38:15
@@ -61,7 +61,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime
 LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
    |                       ------------ this data with lifetime `'a`...
 LL |     <_ as Bar<'_, '_>>::get_b(x) // ERROR
-   |     ----------^^---------------- ...is captured and required to live as long as `'static` here
+   |     ----------^^------------- ...is captured and required to live as long as `'static` here
 
 error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
   --> $DIR/type-checking-test-4.rs:43:27
@@ -74,16 +74,16 @@ LL |     let y = x as &dyn Bar<'_, '_>;
    |             ...is captured here...
 LL |
 LL |     y.get_b(); // ERROR
-   |     - ...and is captured here too
+   |     - ...is captured here...
 LL |     let z = y;
 LL |     z.get_b() // ERROR
-   |     --------- ...is required to live as long as `'static` here...
+   |     - ...is captured here...
    |
-note: ...and is captured here too
+note: ...and is required to live as long as `'static` here
   --> $DIR/type-checking-test-4.rs:47:5
    |
 LL |     z.get_b() // ERROR
-   |     ^
+   |     ^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
index de3a6bbae17..da0f6d0ecde 100644
--- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
+++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr
@@ -5,7 +5,9 @@ LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
    |                ---- this data with an anonymous lifetime `'_`...
 LL |     //                      ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
 LL |     Box::new(items.iter())
-   |     ---------------^^^^--- ...is captured and required to live as long as `'static` here
+   |              ----- ^^^^
+   |              |
+   |              ...is captured and required to live as long as `'static` here
    |
 help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound
    |