about summary refs log tree commit diff
path: root/src/librustc_error_codes/error_codes
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-01-17 09:17:18 +0000
committerbors <bors@rust-lang.org>2020-01-17 09:17:18 +0000
commit2480c9eac15608591f58730aed27caac9c30b4c2 (patch)
treea1b4e27967406769ec10400cde0384abf4cfd061 /src/librustc_error_codes/error_codes
parent91ff7c689d4a2beb45bdd45f14cb65424a46ad9c (diff)
parent98347cdbfffe9cf9328af24592ced2f240340255 (diff)
downloadrust-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.md138
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