]> git.lizzy.rs Git - rust.git/blob - src/librustc/traits/object_safety.rs
Remove interior mutability from TraitDef by turning fields into queries.
[rust.git] / src / librustc / traits / object_safety.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! "Object safety" refers to the ability for a trait to be converted
12 //! to an object. In general, traits may only be converted to an
13 //! object if all of their methods meet certain criteria. In particular,
14 //! they must:
15 //!
16 //!   - have a suitable receiver from which we can extract a vtable;
17 //!   - not reference the erased type `Self` except for in this receiver;
18 //!   - not have generic type parameters
19
20 use super::elaborate_predicates;
21
22 use hir::def_id::DefId;
23 use traits;
24 use ty::{self, Ty, TyCtxt, TypeFoldable};
25 use ty::subst::Substs;
26 use std::borrow::Cow;
27 use syntax::ast;
28
29 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
30 pub enum ObjectSafetyViolation {
31     /// Self : Sized declared on the trait
32     SizedSelf,
33
34     /// Supertrait reference references `Self` an in illegal location
35     /// (e.g. `trait Foo : Bar<Self>`)
36     SupertraitSelf,
37
38     /// Method has something illegal
39     Method(ast::Name, MethodViolationCode),
40
41     /// Associated const
42     AssociatedConst(ast::Name),
43 }
44
45 impl ObjectSafetyViolation {
46     pub fn error_msg(&self) -> Cow<'static, str> {
47         match *self {
48             ObjectSafetyViolation::SizedSelf =>
49                 "the trait cannot require that `Self : Sized`".into(),
50             ObjectSafetyViolation::SupertraitSelf =>
51                 "the trait cannot use `Self` as a type parameter \
52                  in the supertraits or where-clauses".into(),
53             ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
54                 format!("method `{}` has no receiver", name).into(),
55             ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
56                 format!("method `{}` references the `Self` type \
57                          in its arguments or return type", name).into(),
58             ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
59                 format!("method `{}` has generic type parameters", name).into(),
60             ObjectSafetyViolation::AssociatedConst(name) =>
61                 format!("the trait cannot contain associated consts like `{}`", name).into(),
62         }
63     }
64 }
65
66 /// Reasons a method might not be object-safe.
67 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
68 pub enum MethodViolationCode {
69     /// e.g., `fn foo()`
70     StaticMethod,
71
72     /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
73     ReferencesSelf,
74
75     /// e.g., `fn foo<A>()`
76     Generic,
77 }
78
79 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
80
81     /// Returns the object safety violations that affect
82     /// astconv - currently, Self in supertraits. This is needed
83     /// because `object_safety_violations` can't be used during
84     /// type collection.
85     pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
86                                             -> Vec<ObjectSafetyViolation>
87     {
88         let mut violations = vec![];
89
90         for def_id in traits::supertrait_def_ids(self, trait_def_id) {
91             if self.predicates_reference_self(def_id, true) {
92                 violations.push(ObjectSafetyViolation::SupertraitSelf);
93             }
94         }
95
96         debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
97                trait_def_id,
98                violations);
99
100         violations
101     }
102
103     pub fn object_safety_violations(self, trait_def_id: DefId)
104                                     -> Vec<ObjectSafetyViolation>
105     {
106         traits::supertrait_def_ids(self, trait_def_id)
107             .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
108             .collect()
109     }
110
111     fn object_safety_violations_for_trait(self, trait_def_id: DefId)
112                                           -> Vec<ObjectSafetyViolation>
113     {
114         // Check methods for violations.
115         let mut violations: Vec<_> = self.associated_items(trait_def_id)
116             .filter(|item| item.kind == ty::AssociatedKind::Method)
117             .filter_map(|item| {
118                 self.object_safety_violation_for_method(trait_def_id, &item)
119                     .map(|code| ObjectSafetyViolation::Method(item.name, code))
120             }).collect();
121
122         // Check the trait itself.
123         if self.trait_has_sized_self(trait_def_id) {
124             violations.push(ObjectSafetyViolation::SizedSelf);
125         }
126         if self.predicates_reference_self(trait_def_id, false) {
127             violations.push(ObjectSafetyViolation::SupertraitSelf);
128         }
129
130         violations.extend(self.associated_items(trait_def_id)
131             .filter(|item| item.kind == ty::AssociatedKind::Const)
132             .map(|item| ObjectSafetyViolation::AssociatedConst(item.name)));
133
134         debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
135                trait_def_id,
136                violations);
137
138         violations
139     }
140
141     fn predicates_reference_self(
142         self,
143         trait_def_id: DefId,
144         supertraits_only: bool) -> bool
145     {
146         let trait_ref = ty::Binder(ty::TraitRef {
147             def_id: trait_def_id,
148             substs: Substs::identity_for_item(self, trait_def_id)
149         });
150         let predicates = if supertraits_only {
151             self.super_predicates_of(trait_def_id)
152         } else {
153             self.predicates_of(trait_def_id)
154         };
155         predicates
156             .predicates
157             .into_iter()
158             .map(|predicate| predicate.subst_supertrait(self, &trait_ref))
159             .any(|predicate| {
160                 match predicate {
161                     ty::Predicate::Trait(ref data) => {
162                         // In the case of a trait predicate, we can skip the "self" type.
163                         data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
164                     }
165                     ty::Predicate::Projection(..) |
166                     ty::Predicate::WellFormed(..) |
167                     ty::Predicate::ObjectSafe(..) |
168                     ty::Predicate::TypeOutlives(..) |
169                     ty::Predicate::RegionOutlives(..) |
170                     ty::Predicate::ClosureKind(..) |
171                     ty::Predicate::Subtype(..) |
172                     ty::Predicate::Equate(..) => {
173                         false
174                     }
175                 }
176             })
177     }
178
179     fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
180         self.generics_require_sized_self(trait_def_id)
181     }
182
183     fn generics_require_sized_self(self, def_id: DefId) -> bool {
184         let sized_def_id = match self.lang_items.sized_trait() {
185             Some(def_id) => def_id,
186             None => { return false; /* No Sized trait, can't require it! */ }
187         };
188
189         // Search for a predicate like `Self : Sized` amongst the trait bounds.
190         let predicates = self.predicates_of(def_id);
191         let predicates = predicates.instantiate_identity(self).predicates;
192         elaborate_predicates(self, predicates)
193             .any(|predicate| {
194                 match predicate {
195                     ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
196                         trait_pred.0.self_ty().is_self()
197                     }
198                     ty::Predicate::Projection(..) |
199                     ty::Predicate::Trait(..) |
200                     ty::Predicate::Equate(..) |
201                     ty::Predicate::Subtype(..) |
202                     ty::Predicate::RegionOutlives(..) |
203                     ty::Predicate::WellFormed(..) |
204                     ty::Predicate::ObjectSafe(..) |
205                     ty::Predicate::ClosureKind(..) |
206                     ty::Predicate::TypeOutlives(..) => {
207                         false
208                     }
209                 }
210             })
211     }
212
213     /// Returns `Some(_)` if this method makes the containing trait not object safe.
214     fn object_safety_violation_for_method(self,
215                                           trait_def_id: DefId,
216                                           method: &ty::AssociatedItem)
217                                           -> Option<MethodViolationCode>
218     {
219         // Any method that has a `Self : Sized` requisite is otherwise
220         // exempt from the regulations.
221         if self.generics_require_sized_self(method.def_id) {
222             return None;
223         }
224
225         self.virtual_call_violation_for_method(trait_def_id, method)
226     }
227
228     /// We say a method is *vtable safe* if it can be invoked on a trait
229     /// object.  Note that object-safe traits can have some
230     /// non-vtable-safe methods, so long as they require `Self:Sized` or
231     /// otherwise ensure that they cannot be used when `Self=Trait`.
232     pub fn is_vtable_safe_method(self,
233                                  trait_def_id: DefId,
234                                  method: &ty::AssociatedItem)
235                                  -> bool
236     {
237         // Any method that has a `Self : Sized` requisite can't be called.
238         if self.generics_require_sized_self(method.def_id) {
239             return false;
240         }
241
242         self.virtual_call_violation_for_method(trait_def_id, method).is_none()
243     }
244
245     /// Returns `Some(_)` if this method cannot be called on a trait
246     /// object; this does not necessarily imply that the enclosing trait
247     /// is not object safe, because the method might have a where clause
248     /// `Self:Sized`.
249     fn virtual_call_violation_for_method(self,
250                                          trait_def_id: DefId,
251                                          method: &ty::AssociatedItem)
252                                          -> Option<MethodViolationCode>
253     {
254         // The method's first parameter must be something that derefs (or
255         // autorefs) to `&self`. For now, we only accept `self`, `&self`
256         // and `Box<Self>`.
257         if !method.method_has_self_argument {
258             return Some(MethodViolationCode::StaticMethod);
259         }
260
261         // The `Self` type is erased, so it should not appear in list of
262         // arguments or return type apart from the receiver.
263         let ref sig = self.type_of(method.def_id).fn_sig();
264         for input_ty in &sig.skip_binder().inputs()[1..] {
265             if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
266                 return Some(MethodViolationCode::ReferencesSelf);
267             }
268         }
269         if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
270             return Some(MethodViolationCode::ReferencesSelf);
271         }
272
273         // We can't monomorphize things like `fn foo<A>(...)`.
274         if !self.generics_of(method.def_id).types.is_empty() {
275             return Some(MethodViolationCode::Generic);
276         }
277
278         None
279     }
280
281     fn contains_illegal_self_type_reference(self,
282                                             trait_def_id: DefId,
283                                             ty: Ty<'tcx>)
284                                             -> bool
285     {
286         // This is somewhat subtle. In general, we want to forbid
287         // references to `Self` in the argument and return types,
288         // since the value of `Self` is erased. However, there is one
289         // exception: it is ok to reference `Self` in order to access
290         // an associated type of the current trait, since we retain
291         // the value of those associated types in the object type
292         // itself.
293         //
294         // ```rust
295         // trait SuperTrait {
296         //     type X;
297         // }
298         //
299         // trait Trait : SuperTrait {
300         //     type Y;
301         //     fn foo(&self, x: Self) // bad
302         //     fn foo(&self) -> Self // bad
303         //     fn foo(&self) -> Option<Self> // bad
304         //     fn foo(&self) -> Self::Y // OK, desugars to next example
305         //     fn foo(&self) -> <Self as Trait>::Y // OK
306         //     fn foo(&self) -> Self::X // OK, desugars to next example
307         //     fn foo(&self) -> <Self as SuperTrait>::X // OK
308         // }
309         // ```
310         //
311         // However, it is not as simple as allowing `Self` in a projected
312         // type, because there are illegal ways to use `Self` as well:
313         //
314         // ```rust
315         // trait Trait : SuperTrait {
316         //     ...
317         //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
318         // }
319         // ```
320         //
321         // Here we will not have the type of `X` recorded in the
322         // object type, and we cannot resolve `Self as SomeOtherTrait`
323         // without knowing what `Self` is.
324
325         let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
326         let mut error = false;
327         ty.maybe_walk(|ty| {
328             match ty.sty {
329                 ty::TyParam(ref param_ty) => {
330                     if param_ty.is_self() {
331                         error = true;
332                     }
333
334                     false // no contained types to walk
335                 }
336
337                 ty::TyProjection(ref data) => {
338                     // This is a projected type `<Foo as SomeTrait>::X`.
339
340                     // Compute supertraits of current trait lazily.
341                     if supertraits.is_none() {
342                         let trait_ref = ty::Binder(ty::TraitRef {
343                             def_id: trait_def_id,
344                             substs: Substs::identity_for_item(self, trait_def_id)
345                         });
346                         supertraits = Some(traits::supertraits(self, trait_ref).collect());
347                     }
348
349                     // Determine whether the trait reference `Foo as
350                     // SomeTrait` is in fact a supertrait of the
351                     // current trait. In that case, this type is
352                     // legal, because the type `X` will be specified
353                     // in the object type.  Note that we can just use
354                     // direct equality here because all of these types
355                     // are part of the formal parameter listing, and
356                     // hence there should be no inference variables.
357                     let projection_trait_ref = ty::Binder(data.trait_ref.clone());
358                     let is_supertrait_of_current_trait =
359                         supertraits.as_ref().unwrap().contains(&projection_trait_ref);
360
361                     if is_supertrait_of_current_trait {
362                         false // do not walk contained types, do not report error, do collect $200
363                     } else {
364                         true // DO walk contained types, POSSIBLY reporting an error
365                     }
366                 }
367
368                 _ => true, // walk contained types, if any
369             }
370         });
371
372         error
373     }
374 }
375
376 pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
377                                          trait_def_id: DefId)
378                                          -> bool {
379     tcx.object_safety_violations(trait_def_id).is_empty()
380 }