about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-06-14 18:10:31 +0200
committerGitHub <noreply@github.com>2023-06-14 18:10:31 +0200
commit8aff1122c63ac294215a07f6f7fa992d29bb412d (patch)
tree2ad7950a44d890d66c3344303b7c1dc5ae02e0a9
parent7240943b2869fc47241ee6557c4645d04f2d274c (diff)
parentbc78d0cbf1efb76fa6d7c80bb029a4b6d9af92c3 (diff)
downloadrust-8aff1122c63ac294215a07f6f7fa992d29bb412d.tar.gz
rust-8aff1122c63ac294215a07f6f7fa992d29bb412d.zip
Rollup merge of #112611 - compiler-errors:unconstrained-lt-in-rpitit, r=oli-obk
Error on unconstrained lifetime in RPITIT

Fixes #109468

The only thing is that I had to split `tests/ui/impl-trait/in-trait/method-signature-matches.rs` into a bunch of different revisions because some error aren't being emitted if all the different examples are all together in one file :thinking:

r? `@oli-obk` just because i know you'll review it, feel free to re-roll
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs59
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs17
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr21
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr20
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr20
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.rs21
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.stderr74
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr9
-rw-r--r--tests/ui/impl-trait/in-trait/unconstrained-lt.rs16
12 files changed, 188 insertions, 102 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index dce31975dbc..4fbe68b8b6c 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -45,12 +45,7 @@ pub(super) fn compare_impl_method<'tcx>(
     debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
 
     let _: Result<_, ErrorGuaranteed> = try {
-        compare_self_type(tcx, impl_m, trait_m, impl_trait_ref)?;
-        compare_number_of_generics(tcx, impl_m, trait_m, false)?;
-        compare_generic_param_kinds(tcx, impl_m, trait_m, false)?;
-        compare_number_of_method_arguments(tcx, impl_m, trait_m)?;
-        compare_synthetic_generics(tcx, impl_m, trait_m)?;
-        compare_asyncness(tcx, impl_m, trait_m)?;
+        check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
         compare_method_predicate_entailment(
             tcx,
             impl_m,
@@ -61,6 +56,26 @@ pub(super) fn compare_impl_method<'tcx>(
     };
 }
 
+/// Checks a bunch of different properties of the impl/trait methods for
+/// compatibility, such as asyncness, number of argument, self receiver kind,
+/// and number of early- and late-bound generics.
+fn check_method_is_structurally_compatible<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_m: ty::AssocItem,
+    trait_m: ty::AssocItem,
+    impl_trait_ref: ty::TraitRef<'tcx>,
+    delay: bool,
+) -> Result<(), ErrorGuaranteed> {
+    compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?;
+    compare_number_of_generics(tcx, impl_m, trait_m, delay)?;
+    compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?;
+    compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?;
+    compare_synthetic_generics(tcx, impl_m, trait_m, delay)?;
+    compare_asyncness(tcx, impl_m, trait_m, delay)?;
+    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?;
+    Ok(())
+}
+
 /// This function is best explained by example. Consider a trait with it's implementation:
 ///
 /// ```rust
@@ -177,9 +192,6 @@ fn compare_method_predicate_entailment<'tcx>(
     let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
     let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
 
-    // Check region bounds.
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, false)?;
-
     // Create obligations for each predicate declared by the impl
     // definition in the context of the trait's parameter
     // environment. We can't just use `impl_env.caller_bounds`,
@@ -534,6 +546,7 @@ fn compare_asyncness<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
         match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
@@ -544,11 +557,14 @@ fn compare_asyncness<'tcx>(
                 // We don't know if it's ok, but at least it's already an error.
             }
             _ => {
-                return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
-                    span: tcx.def_span(impl_m.def_id),
-                    method_name: trait_m.name,
-                    trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
-                }));
+                return Err(tcx
+                    .sess
+                    .create_err(crate::errors::AsyncTraitImplShouldBeAsync {
+                        span: tcx.def_span(impl_m.def_id),
+                        method_name: trait_m.name,
+                        trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
+                    })
+                    .emit_unless(delay));
             }
         };
     }
@@ -602,9 +618,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 
     // First, check a few of the same things as `compare_impl_method`,
     // just so we don't ICE during substitution later.
-    compare_number_of_generics(tcx, impl_m, trait_m, true)?;
-    compare_generic_param_kinds(tcx, impl_m, trait_m, true)?;
-    check_region_bounds_on_impl_item(tcx, impl_m, trait_m, true)?;
+    check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
 
     let trait_to_impl_substs = impl_trait_ref.substs;
 
@@ -1097,6 +1111,7 @@ fn compare_self_type<'tcx>(
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     // Try to give more informative error messages about self typing
     // mismatches. Note that any mismatch will also be detected
@@ -1145,7 +1160,7 @@ fn compare_self_type<'tcx>(
             } else {
                 err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
             }
-            return Err(err.emit());
+            return Err(err.emit_unless(delay));
         }
 
         (true, false) => {
@@ -1166,7 +1181,7 @@ fn compare_self_type<'tcx>(
                 err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
             }
 
-            return Err(err.emit());
+            return Err(err.emit_unless(delay));
         }
     }
 
@@ -1352,6 +1367,7 @@ fn compare_number_of_method_arguments<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     let impl_m_fty = tcx.fn_sig(impl_m.def_id);
     let trait_m_fty = tcx.fn_sig(trait_m.def_id);
@@ -1422,7 +1438,7 @@ fn compare_number_of_method_arguments<'tcx>(
             ),
         );
 
-        return Err(err.emit());
+        return Err(err.emit_unless(delay));
     }
 
     Ok(())
@@ -1432,6 +1448,7 @@ fn compare_synthetic_generics<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: ty::AssocItem,
     trait_m: ty::AssocItem,
+    delay: bool,
 ) -> Result<(), ErrorGuaranteed> {
     // FIXME(chrisvittal) Clean up this function, list of FIXME items:
     //     1. Better messages for the span labels
@@ -1551,7 +1568,7 @@ fn compare_synthetic_generics<'tcx>(
                 }
                 _ => unreachable!(),
             }
-            error_found = Some(err.emit());
+            error_found = Some(err.emit_unless(delay));
         }
     }
     if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 612d4ff3df8..5526dd4b007 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -106,10 +106,23 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
                     if item.defaultness(tcx).has_value() {
                         cgp::parameters_for(&tcx.type_of(def_id).subst_identity(), true)
                     } else {
-                        Vec::new()
+                        vec![]
                     }
                 }
-                ty::AssocKind::Fn | ty::AssocKind::Const => Vec::new(),
+                ty::AssocKind::Fn => {
+                    if !tcx.lower_impl_trait_in_trait_to_assoc_ty()
+                        && item.defaultness(tcx).has_value()
+                        && tcx.impl_method_has_trait_impl_trait_tys(item.def_id)
+                        && let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
+                    {
+                        table.values().copied().flat_map(|ty| {
+                            cgp::parameters_for(&ty.subst_identity(), true)
+                        }).collect()
+                    } else {
+                        vec![]
+                    }
+                }
+                ty::AssocKind::Const => vec![],
             }
         })
         .collect();
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
new file mode 100644
index 00000000000..f604ada6ac7
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr
@@ -0,0 +1,21 @@
+error[E0053]: method `early` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:58:27
+   |
+LL |     fn early<'late, T>(_: &'late ()) {}
+   |                     -     ^^^^^^^^^
+   |                     |     |
+   |                     |     expected type parameter `T`, found `()`
+   |                     |     help: change the parameter type to match the trait: `&'early T`
+   |                     this type parameter
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:53:28
+   |
+LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
+   |                            ^^^^^^^^^
+   = note: expected signature `fn(&'early T)`
+              found signature `fn(&())`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
new file mode 100644
index 00000000000..d3183b92e84
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr
@@ -0,0 +1,20 @@
+error[E0053]: method `owo` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:14:15
+   |
+LL |     fn owo(_: u8) {}
+   |               ^^
+   |               |
+   |               expected `()`, found `u8`
+   |               help: change the parameter type to match the trait: `()`
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:9:15
+   |
+LL |     fn owo(x: ()) -> impl Sized;
+   |               ^^
+   = note: expected signature `fn(())`
+              found signature `fn(u8)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
new file mode 100644
index 00000000000..80fda1c9fe1
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr
@@ -0,0 +1,20 @@
+error[E0053]: method `owo` has an incompatible type for trait
+  --> $DIR/method-signature-matches.rs:25:21
+   |
+LL |     async fn owo(_: u8) {}
+   |                     ^^
+   |                     |
+   |                     expected `()`, found `u8`
+   |                     help: change the parameter type to match the trait: `()`
+   |
+note: type in trait
+  --> $DIR/method-signature-matches.rs:20:21
+   |
+LL |     async fn owo(x: ()) {}
+   |                     ^^
+   = note: expected signature `fn(()) -> _`
+              found signature `fn(u8) -> _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.rs b/tests/ui/impl-trait/in-trait/method-signature-matches.rs
index c848ee3f643..294f93b30d0 100644
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.rs
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.rs
@@ -1,51 +1,62 @@
 // edition: 2021
+// revisions: mismatch mismatch_async too_many too_few lt
 
 #![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
 #![allow(incomplete_features)]
 
+#[cfg(mismatch)]
 trait Uwu {
     fn owo(x: ()) -> impl Sized;
 }
 
+#[cfg(mismatch)]
 impl Uwu for () {
     fn owo(_: u8) {}
-    //~^ ERROR method `owo` has an incompatible type for trait
+    //[mismatch]~^ ERROR method `owo` has an incompatible type for trait
 }
 
+#[cfg(mismatch_async)]
 trait AsyncUwu {
     async fn owo(x: ()) {}
 }
 
+#[cfg(mismatch_async)]
 impl AsyncUwu for () {
     async fn owo(_: u8) {}
-    //~^ ERROR method `owo` has an incompatible type for trait
+    //[mismatch_async]~^ ERROR method `owo` has an incompatible type for trait
 }
 
+#[cfg(too_many)]
 trait TooMuch {
     fn calm_down_please() -> impl Sized;
 }
 
+#[cfg(too_many)]
 impl TooMuch for () {
     fn calm_down_please(_: (), _: (), _: ()) {}
-    //~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
+    //[too_many]~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
 }
 
+#[cfg(too_few)]
 trait TooLittle {
     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
 }
 
+#[cfg(too_few)]
 impl TooLittle for () {
     fn come_on_a_little_more_effort() {}
-    //~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
+    //[too_few]~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
 }
 
+#[cfg(lt)]
 trait Lifetimes {
     fn early<'early, T>(x: &'early T) -> impl Sized;
 }
 
+#[cfg(lt)]
 impl Lifetimes for () {
     fn early<'late, T>(_: &'late ()) {}
-    //~^ ERROR method `early` has an incompatible type for trait
+    //[lt]~^ ERROR method `early` has an incompatible type for trait
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.stderr
deleted file mode 100644
index 3ec62020e6c..00000000000
--- a/tests/ui/impl-trait/in-trait/method-signature-matches.stderr
+++ /dev/null
@@ -1,74 +0,0 @@
-error[E0053]: method `owo` has an incompatible type for trait
-  --> $DIR/method-signature-matches.rs:11:15
-   |
-LL |     fn owo(_: u8) {}
-   |               ^^
-   |               |
-   |               expected `()`, found `u8`
-   |               help: change the parameter type to match the trait: `()`
-   |
-note: type in trait
-  --> $DIR/method-signature-matches.rs:7:15
-   |
-LL |     fn owo(x: ()) -> impl Sized;
-   |               ^^
-   = note: expected signature `fn(())`
-              found signature `fn(u8)`
-
-error[E0053]: method `owo` has an incompatible type for trait
-  --> $DIR/method-signature-matches.rs:20:21
-   |
-LL |     async fn owo(_: u8) {}
-   |                     ^^
-   |                     |
-   |                     expected `()`, found `u8`
-   |                     help: change the parameter type to match the trait: `()`
-   |
-note: type in trait
-  --> $DIR/method-signature-matches.rs:16:21
-   |
-LL |     async fn owo(x: ()) {}
-   |                     ^^
-   = note: expected signature `fn(()) -> _`
-              found signature `fn(u8) -> _`
-
-error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
-  --> $DIR/method-signature-matches.rs:29:28
-   |
-LL |     fn calm_down_please() -> impl Sized;
-   |     ------------------------------------ trait requires 0 parameters
-...
-LL |     fn calm_down_please(_: (), _: (), _: ()) {}
-   |                            ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
-
-error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
-  --> $DIR/method-signature-matches.rs:38:5
-   |
-LL |     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
-   |                                        ---------------- trait requires 3 parameters
-...
-LL |     fn come_on_a_little_more_effort() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
-
-error[E0053]: method `early` has an incompatible type for trait
-  --> $DIR/method-signature-matches.rs:47:27
-   |
-LL |     fn early<'late, T>(_: &'late ()) {}
-   |                     -     ^^^^^^^^^
-   |                     |     |
-   |                     |     expected type parameter `T`, found `()`
-   |                     |     help: change the parameter type to match the trait: `&'early T`
-   |                     this type parameter
-   |
-note: type in trait
-  --> $DIR/method-signature-matches.rs:43:28
-   |
-LL |     fn early<'early, T>(x: &'early T) -> impl Sized;
-   |                            ^^^^^^^^^
-   = note: expected signature `fn(&'early T)`
-              found signature `fn(&())`
-
-error: aborting due to 5 previous errors
-
-Some errors have detailed explanations: E0050, E0053.
-For more information about an error, try `rustc --explain E0050`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr
new file mode 100644
index 00000000000..24bcfeb748f
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr
@@ -0,0 +1,12 @@
+error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
+  --> $DIR/method-signature-matches.rs:47:5
+   |
+LL |     fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
+   |                                        ---------------- trait requires 3 parameters
+...
+LL |     fn come_on_a_little_more_effort() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 3 parameters, found 0
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0050`.
diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr
new file mode 100644
index 00000000000..616cbd2905c
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr
@@ -0,0 +1,12 @@
+error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
+  --> $DIR/method-signature-matches.rs:36:28
+   |
+LL |     fn calm_down_please() -> impl Sized;
+   |     ------------------------------------ trait requires 0 parameters
+...
+LL |     fn calm_down_please(_: (), _: (), _: ()) {}
+   |                            ^^^^^^^^^^^^^^^^ expected 0 parameters, found 3
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0050`.
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr
new file mode 100644
index 00000000000..bf088ae8b25
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.current.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-lt.rs:10:6
+   |
+LL | impl<'a, T> Foo for T {
+   |      ^^ unconstrained lifetime parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr
new file mode 100644
index 00000000000..bf088ae8b25
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.next.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/unconstrained-lt.rs:10:6
+   |
+LL | impl<'a, T> Foo for T {
+   |      ^^ unconstrained lifetime parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs
new file mode 100644
index 00000000000..f966be43a6e
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs
@@ -0,0 +1,16 @@
+// [next] compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty
+// revisions: current next
+
+#![feature(return_position_impl_trait_in_trait)]
+
+trait Foo {
+    fn test() -> impl Sized;
+}
+
+impl<'a, T> Foo for T {
+    //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
+
+    fn test() -> &'a () { &() }
+}
+
+fn main() {}