From 5e6da720f621308a0f44e7c6bbd13a9fad68b240 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 22 Feb 2024 06:15:55 +0000
Subject: [PATCH] Account for RPITIT in E0310 explicit lifetime constraint
 suggestion

When given

```rust
trait Original {
    fn f() -> impl Fn();
}

trait Erased {
    fn f(&self) -> Box<dyn Fn()>;
}

impl<T: Original> Erased for T {
    fn f(&self) -> Box<dyn Fn()> {
        Box::new(<T as Original>::f())
    }
}
```

avoid suggestion to restrict the `Trait::{opaque}` type in a `where` clause:

```
error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough
  --> $DIR/missing-static-bound-from-impl.rs:11:9
   |
LL |         Box::new(<T as Original>::f())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |         |
   |         the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime...
   |         ...so that the type `impl Fn()` will meet its required lifetime bounds
```

CC #119773.
---
 .../rustc_infer/src/infer/error_reporting/mod.rs |  8 ++++++++
 .../impl-trait/in-trait/async-and-ret-ref.stderr |  2 --
 .../in-trait/missing-static-bound-from-impl.rs   | 16 ++++++++++++++++
 .../missing-static-bound-from-impl.stderr        | 12 ++++++++++++
 4 files changed, 36 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs
 create mode 100644 tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 505d56cf49179..470b97b777835 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2434,6 +2434,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let suggestion =
                     if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
                 suggs.push((sp, suggestion))
+            } else if let GenericKind::Alias(ref p) = bound_kind
+                && let ty::Projection = p.kind(self.tcx)
+                && let DefKind::AssocTy = self.tcx.def_kind(p.def_id)
+                && let Some(ty::ImplTraitInTraitData::Trait { .. }) =
+                    self.tcx.opt_rpitit_info(p.def_id)
+            {
+                // The lifetime found in the `impl` is longer than the one on the RPITIT.
+                // Do not suggest `<Type as Trait>::{opaque}: 'static`.
             } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
                 let pred = format!("{bound_kind}: {lt_name}");
                 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
diff --git a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
index 79a86b0a3aedf..15aa3cf54bbe5 100644
--- a/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
+++ b/tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
@@ -6,8 +6,6 @@ LL |     async fn foo() -> &'static impl T;
    |     |
    |     the associated type `<Self as MyTrait>::{opaque#0}` must be valid for the static lifetime...
    |     ...so that the reference type `&'static impl T` does not outlive the data it points at
-   |
-   = help: consider adding an explicit lifetime bound `<Self as MyTrait>::{opaque#0}: 'static`...
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs
new file mode 100644
index 0000000000000..a36799c3ebd46
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs
@@ -0,0 +1,16 @@
+trait Original {
+    fn f() -> impl Fn();
+}
+
+trait Erased {
+    fn f(&self) -> Box<dyn Fn()>;
+}
+
+impl<T: Original> Erased for T {
+    fn f(&self) -> Box<dyn Fn()> {
+        Box::new(<T as Original>::f())
+        //~^ ERROR the associated type `<T as Original>::{opaque#0}` may not live long enough
+    }
+}
+
+fn main () {}
diff --git a/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr
new file mode 100644
index 0000000000000..5ec0ee38347aa
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr
@@ -0,0 +1,12 @@
+error[E0310]: the associated type `<T as Original>::{opaque#0}` may not live long enough
+  --> $DIR/missing-static-bound-from-impl.rs:11:9
+   |
+LL |         Box::new(<T as Original>::f())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         the associated type `<T as Original>::{opaque#0}` must be valid for the static lifetime...
+   |         ...so that the type `impl Fn()` will meet its required lifetime bounds
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0310`.