Skip to content

Commit

Permalink
Account for RPITIT in E0310 explicit lifetime constraint suggestion
Browse files Browse the repository at this point in the history
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())
    }
}
```

emit a suggestion to further constrain the RPITIT, instead of what we did previously, suggest restricting 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
   |
help: consider adding an explicit lifetime bound
   |
LL |     fn f() -> impl Fn() + 'static;
   |                         +++++++++
```

Fix #119773.
  • Loading branch information
estebank committed Feb 22, 2024
1 parent 2dc0170 commit 18bc36b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
11 changes: 11 additions & 0 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2433,6 +2433,17 @@ 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 { opaque_def_id, .. }) =
self.tcx.opt_rpitit_info(p.def_id)
{
// The lifetime found in the `impl` is longer than the one on the RPITIT.
suggs.push((
self.tcx.def_span(opaque_def_id).shrink_to_hi(),
format!(" + {lt_name}"),
));
} 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);
Expand Down
5 changes: 4 additions & 1 deletion tests/ui/impl-trait/in-trait/async-and-ret-ref.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ 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`...
help: consider adding an explicit lifetime bound
|
LL | async fn foo() -> &'static impl T + 'static;
| +++++++++

error: aborting due to 1 previous error

Expand Down
16 changes: 16 additions & 0 deletions tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.rs
Original file line number Diff line number Diff line change
@@ -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 () {}
17 changes: 17 additions & 0 deletions tests/ui/impl-trait/in-trait/missing-static-bound-from-impl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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
|
help: consider adding an explicit lifetime bound
|
LL | fn f() -> impl Fn() + 'static;
| +++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0310`.

0 comments on commit 18bc36b

Please sign in to comment.