diff options
| author | bors <bors@rust-lang.org> | 2020-01-17 09:17:18 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-01-17 09:17:18 +0000 |
| commit | 2480c9eac15608591f58730aed27caac9c30b4c2 (patch) | |
| tree | a1b4e27967406769ec10400cde0384abf4cfd061 /src/librustc_error_codes/error_codes | |
| parent | 91ff7c689d4a2beb45bdd45f14cb65424a46ad9c (diff) | |
| parent | 98347cdbfffe9cf9328af24592ced2f240340255 (diff) | |
| download | rust-2480c9eac15608591f58730aed27caac9c30b4c2.tar.gz rust-2480c9eac15608591f58730aed27caac9c30b4c2.zip | |
Auto merge of #68305 - Dylan-DPC:rollup-aoohsz8, r=Dylan-DPC
Rollup of 6 pull requests Successful merges: - #67956 (Detail transitive containment in E0588 diagnostic) - #68153 (resolve: Point at the private item definitions in privacy errors) - #68195 (Account for common `impl Trait`/`dyn Trait` return type errors) - #68288 (Fix some of the rustfmt fallout in Miri) - #68292 (don't clone types that are copy) - #68301 (Don't propagate __RUST_TEST_INVOKE to subprocess) Failed merges: r? @ghost
Diffstat (limited to 'src/librustc_error_codes/error_codes')
| -rw-r--r-- | src/librustc_error_codes/error_codes/E0746.md | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md new file mode 100644 index 00000000000..16b2722f0ea --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0746.md @@ -0,0 +1,138 @@ +Return types cannot be `dyn Trait`s as they must be `Sized`. + +Erroneous code example: + +```compile_fail,E0277 +# // FIXME: after E0746 is in beta, change the above +trait T { + fn bar(&self); +} +struct S(usize); +impl T for S { + fn bar(&self) {} +} + +// Having the trait `T` as return type is invalid because +// unboxed trait objects do not have a statically known size: +fn foo() -> dyn T { + S(42) +} +``` + +To avoid the error there are a couple of options. + +If there is a single type involved, you can use [`impl Trait`]: + +``` +# trait T { +# fn bar(&self); +# } +# struct S(usize); +# impl T for S { +# fn bar(&self) {} +# } +// The compiler will select `S(usize)` as the materialized return type of this +// function, but callers will only know that the return type implements `T`. +fn foo() -> impl T { + S(42) +} +``` + +If there are multiple types involved, the only way you care to interact with +them is through the trait's interface, and having to rely on dynamic dispatch +is acceptable, then you can use [trait objects] with `Box`, or other container +types like `Rc` or `Arc`: + +``` +# trait T { +# fn bar(&self); +# } +# struct S(usize); +# impl T for S { +# fn bar(&self) {} +# } +struct O(&'static str); +impl T for O { + fn bar(&self) {} +} + +// This now returns a "trait object" and callers are only be able to access +// associated items from `T`. +fn foo(x: bool) -> Box<dyn T> { + if x { + Box::new(S(42)) + } else { + Box::new(O("val")) + } +} +``` + +Finally, if you wish to still be able to access the original type, you can +create a new `enum` with a variant for each type: + +``` +# trait T { +# fn bar(&self); +# } +# struct S(usize); +# impl T for S { +# fn bar(&self) {} +# } +# struct O(&'static str); +# impl T for O { +# fn bar(&self) {} +# } +enum E { + S(S), + O(O), +} + +// The caller can access the original types directly, but it needs to match on +// the returned `enum E`. +fn foo(x: bool) -> E { + if x { + E::S(S(42)) + } else { + E::O(O("val")) + } +} +``` + +You can even implement the `trait` on the returned `enum` so the callers +*don't* have to match on the returned value to invoke the associated items: + +``` +# trait T { +# fn bar(&self); +# } +# struct S(usize); +# impl T for S { +# fn bar(&self) {} +# } +# struct O(&'static str); +# impl T for O { +# fn bar(&self) {} +# } +# enum E { +# S(S), +# O(O), +# } +impl T for E { + fn bar(&self) { + match self { + E::S(s) => s.bar(), + E::O(o) => o.bar(), + } + } +} +``` + +If you decide to use trait objects, be aware that these rely on +[dynamic dispatch], which has performance implications, as the compiler needs +to emit code that will figure out which method to call *at runtime* instead of +during compilation. Using trait objects we are trading flexibility for +performance. + +[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits +[trait objects]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types +[dynamic dispatch]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#trait-objects-perform-dynamic-dispatch |
