Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Explanation For Error E0772 #88205

Merged
merged 1 commit into from
Jan 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ E0768: include_str!("./error_codes/E0768.md"),
E0769: include_str!("./error_codes/E0769.md"),
E0770: include_str!("./error_codes/E0770.md"),
E0771: include_str!("./error_codes/E0771.md"),
E0772: include_str!("./error_codes/E0772.md"),
E0773: include_str!("./error_codes/E0773.md"),
E0774: include_str!("./error_codes/E0774.md"),
E0775: include_str!("./error_codes/E0775.md"),
Expand Down Expand Up @@ -641,5 +642,4 @@ E0785: include_str!("./error_codes/E0785.md"),
// E0723, unstable feature in `const` context
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
}
89 changes: 89 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0772.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
A trait object has some specific lifetime `'1`, but it was used in a way that
requires it to have a `'static` lifetime.

Example of erroneous code:

```compile_fail,E0772
trait BooleanLike {}
trait Person {}

impl BooleanLike for bool {}

impl dyn Person {
fn is_cool(&self) -> bool {
// hey you, you're pretty cool
true
}
}

fn get_is_cool<'p>(person: &'p dyn Person) -> impl BooleanLike {
// error: `person` has an anonymous lifetime `'p` but calling
// `print_cool_fn` introduces an implicit `'static` lifetime
// requirement
person.is_cool()
}
```

The trait object `person` in the function `get_is_cool`, while already being
behind a reference with lifetime `'p`, also has it's own implicit lifetime,
`'2`.

Lifetime `'2` represents the data the trait object might hold inside, for
example:

```
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
trait MyTrait {}

struct MyStruct<'a>(&'a i32);

impl<'a> MyTrait for MyStruct<'a> {}
```

With this scenario, if a trait object of `dyn MyTrait + '2` was made from
`MyStruct<'a>`, `'a` must live as long, if not longer than `'2`. This allows the
trait object's internal data to be accessed safely from any trait methods. This
rule also goes for any lifetime any struct made into a trait object may have.

In the implementation for `dyn Person`, the `'2` lifetime representing the
internal data was ommitted, meaning that the compiler inferred the lifetime
`'static`. As a result, the implementation's `is_cool` is inferred by the
compiler to look like this:

```
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
# trait Person {}
#
camelid marked this conversation as resolved.
Show resolved Hide resolved
# impl dyn Person {
fn is_cool<'a>(self: &'a (dyn Person + 'static)) -> bool {unimplemented!()}
# }
```

While the `get_is_cool` function is inferred to look like this:

```
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
# trait Person {}
# trait BooleanLike {}
#
fn get_is_cool<'p, R: BooleanLike>(person: &'p (dyn Person + 'p)) -> R {
unimplemented!()
}
```

Which brings us to the core of the problem; the assignment of type
`&'_ (dyn Person + '_)` to type `&'_ (dyn Person + 'static)` is impossible.

Fixing it is as simple as being generic over lifetime `'2`, as to prevent the
compiler from inferring it as `'static`:

```
# trait Person {}
#
impl<'d> dyn Person + 'd {/* ... */}

// This works too, and is more elegant:
//impl dyn Person + '_ {/* ... */}
```

See the [Rust Reference on Trait Object Lifetime Bounds][trait-objects] for
more information on trait object lifetimes.

[trait-object-lifetime-bounds]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0515`.
Some errors have detailed explanations: E0515, E0772.
For more information about an error, try `rustc --explain E0515`.
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,5 @@ LL | impl MyTrait for Box<dyn ObjectTrait + '_> {

error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0759`.
Some errors have detailed explanations: E0759, E0772.
For more information about an error, try `rustc --explain E0759`.