diff options
Diffstat (limited to 'compiler/rustc_error_codes/src/error_codes/E0772.md')
-rw-r--r-- | compiler/rustc_error_codes/src/error_codes/E0772.md | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md new file mode 100644 index 000000000..5ffffd511 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0772.md @@ -0,0 +1,91 @@ +#### Note: this error code is no longer emitted by the compiler. + +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 +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: + +``` +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 omitted, 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: + +``` +# trait Person {} +# +# 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: + +``` +# 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 |