]> git.lizzy.rs Git - rust.git/blob - src/librustc_error_codes/error_codes/E0038.md
Rollup merge of #62514 - stephaneyfx:box-ffi, r=nikomatsakis
[rust.git] / src / librustc_error_codes / error_codes / E0038.md
1 Trait objects like `Box<Trait>` can only be constructed when certain
2 requirements are satisfied by the trait in question.
3
4 Trait objects are a form of dynamic dispatch and use a dynamically sized type
5 for the inner type. So, for a given trait `Trait`, when `Trait` is treated as a
6 type, as in `Box<Trait>`, the inner type is 'unsized'. In such cases the boxed
7 pointer is a 'fat pointer' that contains an extra pointer to a table of methods
8 (among other things) for dynamic dispatch. This design mandates some
9 restrictions on the types of traits that are allowed to be used in trait
10 objects, which are collectively termed as 'object safety' rules.
11
12 Attempting to create a trait object for a non object-safe trait will trigger
13 this error.
14
15 There are various rules:
16
17 ### The trait cannot require `Self: Sized`
18
19 When `Trait` is treated as a type, the type does not implement the special
20 `Sized` trait, because the type does not have a known size at compile time and
21 can only be accessed behind a pointer. Thus, if we have a trait like the
22 following:
23
24 ```
25 trait Foo where Self: Sized {
26
27 }
28 ```
29
30 We cannot create an object of type `Box<Foo>` or `&Foo` since in this case
31 `Self` would not be `Sized`.
32
33 Generally, `Self: Sized` is used to indicate that the trait should not be used
34 as a trait object. If the trait comes from your own crate, consider removing
35 this restriction.
36
37 ### Method references the `Self` type in its parameters or return type
38
39 This happens when a trait has a method like the following:
40
41 ```
42 trait Trait {
43     fn foo(&self) -> Self;
44 }
45
46 impl Trait for String {
47     fn foo(&self) -> Self {
48         "hi".to_owned()
49     }
50 }
51
52 impl Trait for u8 {
53     fn foo(&self) -> Self {
54         1
55     }
56 }
57 ```
58
59 (Note that `&self` and `&mut self` are okay, it's additional `Self` types which
60 cause this problem.)
61
62 In such a case, the compiler cannot predict the return type of `foo()` in a
63 situation like the following:
64
65 ```compile_fail,E0038
66 trait Trait {
67     fn foo(&self) -> Self;
68 }
69
70 fn call_foo(x: Box<Trait>) {
71     let y = x.foo(); // What type is y?
72     // ...
73 }
74 ```
75
76 If only some methods aren't object-safe, you can add a `where Self: Sized` bound
77 on them to mark them as explicitly unavailable to trait objects. The
78 functionality will still be available to all other implementers, including
79 `Box<Trait>` which is itself sized (assuming you `impl Trait for Box<Trait>`).
80
81 ```
82 trait Trait {
83     fn foo(&self) -> Self where Self: Sized;
84     // more functions
85 }
86 ```
87
88 Now, `foo()` can no longer be called on a trait object, but you will now be
89 allowed to make a trait object, and that will be able to call any object-safe
90 methods. With such a bound, one can still call `foo()` on types implementing
91 that trait that aren't behind trait objects.
92
93 ### Method has generic type parameters
94
95 As mentioned before, trait objects contain pointers to method tables. So, if we
96 have:
97
98 ```
99 trait Trait {
100     fn foo(&self);
101 }
102
103 impl Trait for String {
104     fn foo(&self) {
105         // implementation 1
106     }
107 }
108
109 impl Trait for u8 {
110     fn foo(&self) {
111         // implementation 2
112     }
113 }
114 // ...
115 ```
116
117 At compile time each implementation of `Trait` will produce a table containing
118 the various methods (and other items) related to the implementation.
119
120 This works fine, but when the method gains generic parameters, we can have a
121 problem.
122
123 Usually, generic parameters get _monomorphized_. For example, if I have
124
125 ```
126 fn foo<T>(x: T) {
127     // ...
128 }
129 ```
130
131 The machine code for `foo::<u8>()`, `foo::<bool>()`, `foo::<String>()`, or any
132 other type substitution is different. Hence the compiler generates the
133 implementation on-demand. If you call `foo()` with a `bool` parameter, the
134 compiler will only generate code for `foo::<bool>()`. When we have additional
135 type parameters, the number of monomorphized implementations the compiler
136 generates does not grow drastically, since the compiler will only generate an
137 implementation if the function is called with unparametrized substitutions
138 (i.e., substitutions where none of the substituted types are themselves
139 parametrized).
140
141 However, with trait objects we have to make a table containing _every_ object
142 that implements the trait. Now, if it has type parameters, we need to add
143 implementations for every type that implements the trait, and there could
144 theoretically be an infinite number of types.
145
146 For example, with:
147
148 ```
149 trait Trait {
150     fn foo<T>(&self, on: T);
151     // more methods
152 }
153
154 impl Trait for String {
155     fn foo<T>(&self, on: T) {
156         // implementation 1
157     }
158 }
159
160 impl Trait for u8 {
161     fn foo<T>(&self, on: T) {
162         // implementation 2
163     }
164 }
165
166 // 8 more implementations
167 ```
168
169 Now, if we have the following code:
170
171 ```compile_fail,E0038
172 # trait Trait { fn foo<T>(&self, on: T); }
173 # impl Trait for String { fn foo<T>(&self, on: T) {} }
174 # impl Trait for u8 { fn foo<T>(&self, on: T) {} }
175 # impl Trait for bool { fn foo<T>(&self, on: T) {} }
176 # // etc.
177 fn call_foo(thing: Box<Trait>) {
178     thing.foo(true); // this could be any one of the 8 types above
179     thing.foo(1);
180     thing.foo("hello");
181 }
182 ```
183
184 We don't just need to create a table of all implementations of all methods of
185 `Trait`, we need to create such a table, for each different type fed to
186 `foo()`. In this case this turns out to be (10 types implementing `Trait`)\*(3
187 types being fed to `foo()`) = 30 implementations!
188
189 With real world traits these numbers can grow drastically.
190
191 To fix this, it is suggested to use a `where Self: Sized` bound similar to the
192 fix for the sub-error above if you do not intend to call the method with type
193 parameters:
194
195 ```
196 trait Trait {
197     fn foo<T>(&self, on: T) where Self: Sized;
198     // more methods
199 }
200 ```
201
202 If this is not an option, consider replacing the type parameter with another
203 trait object (e.g., if `T: OtherTrait`, use `on: Box<OtherTrait>`). If the
204 number of types you intend to feed to this method is limited, consider manually
205 listing out the methods of different types.
206
207 ### Method has no receiver
208
209 Methods that do not take a `self` parameter can't be called since there won't be
210 a way to get a pointer to the method table for them.
211
212 ```
213 trait Foo {
214     fn foo() -> u8;
215 }
216 ```
217
218 This could be called as `<Foo as Foo>::foo()`, which would not be able to pick
219 an implementation.
220
221 Adding a `Self: Sized` bound to these methods will generally make this compile.
222
223 ```
224 trait Foo {
225     fn foo() -> u8 where Self: Sized;
226 }
227 ```
228
229 ### The trait cannot contain associated constants
230
231 Just like static functions, associated constants aren't stored on the method
232 table. If the trait or any subtrait contain an associated constant, they cannot
233 be made into an object.
234
235 ```compile_fail,E0038
236 trait Foo {
237     const X: i32;
238 }
239
240 impl Foo {}
241 ```
242
243 A simple workaround is to use a helper method instead:
244
245 ```
246 trait Foo {
247     fn x(&self) -> i32;
248 }
249 ```
250
251 ### The trait cannot use `Self` as a type parameter in the supertrait listing
252
253 This is similar to the second sub-error, but subtler. It happens in situations
254 like the following:
255
256 ```compile_fail,E0038
257 trait Super<A: ?Sized> {}
258
259 trait Trait: Super<Self> {
260 }
261
262 struct Foo;
263
264 impl Super<Foo> for Foo{}
265
266 impl Trait for Foo {}
267
268 fn main() {
269     let x: Box<dyn Trait>;
270 }
271 ```
272
273 Here, the supertrait might have methods as follows:
274
275 ```
276 trait Super<A: ?Sized> {
277     fn get_a(&self) -> &A; // note that this is object safe!
278 }
279 ```
280
281 If the trait `Trait` was deriving from something like `Super<String>` or
282 `Super<T>` (where `Foo` itself is `Foo<T>`), this is okay, because given a type
283 `get_a()` will definitely return an object of that type.
284
285 However, if it derives from `Super<Self>`, even though `Super` is object safe,
286 the method `get_a()` would return an object of unknown type when called on the
287 function. `Self` type parameters let us make object safe traits no longer safe,
288 so they are forbidden when specifying supertraits.
289
290 There's no easy fix for this, generally code will need to be refactored so that
291 you no longer need to derive from `Super<Self>`.