]> git.lizzy.rs Git - rust.git/blob - src/librustc/traits/object_safety.rs
Incorporate a stray test
[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 lint;
24 use traits;
25 use ty::{self, Ty, TyCtxt, TypeFoldable};
26 use ty::util::ExplicitSelf;
27 use std::borrow::Cow;
28 use syntax::ast;
29 use syntax_pos::Span;
30
31 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
32 pub enum ObjectSafetyViolation {
33     /// Self : Sized declared on the trait
34     SizedSelf,
35
36     /// Supertrait reference references `Self` an in illegal location
37     /// (e.g. `trait Foo : Bar<Self>`)
38     SupertraitSelf,
39
40     /// Method has something illegal
41     Method(ast::Name, MethodViolationCode),
42
43     /// Associated const
44     AssociatedConst(ast::Name),
45 }
46
47 impl ObjectSafetyViolation {
48     pub fn error_msg(&self) -> Cow<'static, str> {
49         match *self {
50             ObjectSafetyViolation::SizedSelf =>
51                 "the trait cannot require that `Self : Sized`".into(),
52             ObjectSafetyViolation::SupertraitSelf =>
53                 "the trait cannot use `Self` as a type parameter \
54                  in the supertraits or where-clauses".into(),
55             ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
56                 format!("method `{}` has no receiver", name).into(),
57             ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
58                 format!("method `{}` references the `Self` type \
59                          in its arguments or return type", name).into(),
60             ObjectSafetyViolation::Method(name,
61                                             MethodViolationCode::WhereClauseReferencesSelf(_)) =>
62                 format!("method `{}` references the `Self` type in where clauses", name).into(),
63             ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
64                 format!("method `{}` has generic type parameters", name).into(),
65             ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
66                 format!("method `{}` has a non-standard `self` type", name).into(),
67             ObjectSafetyViolation::AssociatedConst(name) =>
68                 format!("the trait cannot contain associated consts like `{}`", name).into(),
69         }
70     }
71 }
72
73 /// Reasons a method might not be object-safe.
74 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
75 pub enum MethodViolationCode {
76     /// e.g., `fn foo()`
77     StaticMethod,
78
79     /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
80     ReferencesSelf,
81
82     /// e.g. `fn foo(&self) where Self: Clone`
83     WhereClauseReferencesSelf(Span),
84
85     /// e.g., `fn foo<A>()`
86     Generic,
87
88     /// arbitrary `self` type, e.g. `self: Rc<Self>`
89     NonStandardSelfType,
90 }
91
92 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
93
94     /// Returns the object safety violations that affect
95     /// astconv - currently, Self in supertraits. This is needed
96     /// because `object_safety_violations` can't be used during
97     /// type collection.
98     pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
99                                             -> Vec<ObjectSafetyViolation>
100     {
101         let mut violations = vec![];
102
103         for def_id in traits::supertrait_def_ids(self, trait_def_id) {
104             if self.predicates_reference_self(def_id, true) {
105                 violations.push(ObjectSafetyViolation::SupertraitSelf);
106             }
107         }
108
109         debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
110                trait_def_id,
111                violations);
112
113         violations
114     }
115
116     pub fn object_safety_violations(self, trait_def_id: DefId)
117                                     -> Vec<ObjectSafetyViolation>
118     {
119         traits::supertrait_def_ids(self, trait_def_id)
120             .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
121             .collect()
122     }
123
124     fn object_safety_violations_for_trait(self, trait_def_id: DefId)
125                                           -> Vec<ObjectSafetyViolation>
126     {
127         // Check methods for violations.
128         let mut violations: Vec<_> = self.associated_items(trait_def_id)
129             .filter(|item| item.kind == ty::AssociatedKind::Method)
130             .filter_map(|item| {
131                 self.object_safety_violation_for_method(trait_def_id, &item)
132                     .map(|code| ObjectSafetyViolation::Method(item.ident.name, code))
133             }).filter(|violation| {
134                 if let ObjectSafetyViolation::Method(_,
135                                 MethodViolationCode::WhereClauseReferencesSelf(span)) = violation {
136                     // Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
137                     // It's also hard to get a use site span, so we use the method definition span.
138                     self.lint_node_note(
139                         lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
140                         ast::CRATE_NODE_ID,
141                         *span,
142                         &format!("the trait `{}` cannot be made into an object",
143                                 self.item_path_str(trait_def_id)),
144                         &violation.error_msg());
145                     false
146                 } else {
147                     true
148                 }
149             }).collect();
150
151         // Check the trait itself.
152         if self.trait_has_sized_self(trait_def_id) {
153             violations.push(ObjectSafetyViolation::SizedSelf);
154         }
155         if self.predicates_reference_self(trait_def_id, false) {
156             violations.push(ObjectSafetyViolation::SupertraitSelf);
157         }
158
159         violations.extend(self.associated_items(trait_def_id)
160             .filter(|item| item.kind == ty::AssociatedKind::Const)
161             .map(|item| ObjectSafetyViolation::AssociatedConst(item.ident.name)));
162
163         debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
164                trait_def_id,
165                violations);
166
167         violations
168     }
169
170     fn predicates_reference_self(
171         self,
172         trait_def_id: DefId,
173         supertraits_only: bool) -> bool
174     {
175         let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id));
176         let predicates = if supertraits_only {
177             self.super_predicates_of(trait_def_id)
178         } else {
179             self.predicates_of(trait_def_id)
180         };
181         predicates
182             .predicates
183             .into_iter()
184             .map(|predicate| predicate.subst_supertrait(self, &trait_ref))
185             .any(|predicate| {
186                 match predicate {
187                     ty::Predicate::Trait(ref data) => {
188                         // In the case of a trait predicate, we can skip the "self" type.
189                         data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
190                     }
191                     ty::Predicate::Projection(..) |
192                     ty::Predicate::WellFormed(..) |
193                     ty::Predicate::ObjectSafe(..) |
194                     ty::Predicate::TypeOutlives(..) |
195                     ty::Predicate::RegionOutlives(..) |
196                     ty::Predicate::ClosureKind(..) |
197                     ty::Predicate::Subtype(..) |
198                     ty::Predicate::ConstEvaluatable(..) => {
199                         false
200                     }
201                 }
202             })
203     }
204
205     fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
206         self.generics_require_sized_self(trait_def_id)
207     }
208
209     fn generics_require_sized_self(self, def_id: DefId) -> bool {
210         let sized_def_id = match self.lang_items().sized_trait() {
211             Some(def_id) => def_id,
212             None => { return false; /* No Sized trait, can't require it! */ }
213         };
214
215         // Search for a predicate like `Self : Sized` amongst the trait bounds.
216         let predicates = self.predicates_of(def_id);
217         let predicates = predicates.instantiate_identity(self).predicates;
218         elaborate_predicates(self, predicates)
219             .any(|predicate| {
220                 match predicate {
221                     ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
222                         trait_pred.skip_binder().self_ty().is_self()
223                     }
224                     ty::Predicate::Projection(..) |
225                     ty::Predicate::Trait(..) |
226                     ty::Predicate::Subtype(..) |
227                     ty::Predicate::RegionOutlives(..) |
228                     ty::Predicate::WellFormed(..) |
229                     ty::Predicate::ObjectSafe(..) |
230                     ty::Predicate::ClosureKind(..) |
231                     ty::Predicate::TypeOutlives(..) |
232                     ty::Predicate::ConstEvaluatable(..) => {
233                         false
234                     }
235                 }
236             })
237     }
238
239     /// Returns `Some(_)` if this method makes the containing trait not object safe.
240     fn object_safety_violation_for_method(self,
241                                           trait_def_id: DefId,
242                                           method: &ty::AssociatedItem)
243                                           -> Option<MethodViolationCode>
244     {
245         // Any method that has a `Self : Sized` requisite is otherwise
246         // exempt from the regulations.
247         if self.generics_require_sized_self(method.def_id) {
248             return None;
249         }
250
251         self.virtual_call_violation_for_method(trait_def_id, method)
252     }
253
254     /// We say a method is *vtable safe* if it can be invoked on a trait
255     /// object.  Note that object-safe traits can have some
256     /// non-vtable-safe methods, so long as they require `Self:Sized` or
257     /// otherwise ensure that they cannot be used when `Self=Trait`.
258     pub fn is_vtable_safe_method(self,
259                                  trait_def_id: DefId,
260                                  method: &ty::AssociatedItem)
261                                  -> bool
262     {
263         // Any method that has a `Self : Sized` requisite can't be called.
264         if self.generics_require_sized_self(method.def_id) {
265             return false;
266         }
267
268         match self.virtual_call_violation_for_method(trait_def_id, method) {
269             None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
270             Some(_) => false,
271         }
272     }
273
274     /// Returns `Some(_)` if this method cannot be called on a trait
275     /// object; this does not necessarily imply that the enclosing trait
276     /// is not object safe, because the method might have a where clause
277     /// `Self:Sized`.
278     fn virtual_call_violation_for_method(self,
279                                          trait_def_id: DefId,
280                                          method: &ty::AssociatedItem)
281                                          -> Option<MethodViolationCode>
282     {
283         // The method's first parameter must be something that derefs (or
284         // autorefs) to `&self`. For now, we only accept `self`, `&self`
285         // and `Box<Self>`.
286         if !method.method_has_self_argument {
287             return Some(MethodViolationCode::StaticMethod);
288         }
289
290         let sig = self.fn_sig(method.def_id);
291
292         let self_ty = self.mk_self_type();
293         let self_arg_ty = sig.skip_binder().inputs()[0];
294         if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
295             return Some(MethodViolationCode::NonStandardSelfType);
296         }
297
298         // The `Self` type is erased, so it should not appear in list of
299         // arguments or return type apart from the receiver.
300         for input_ty in &sig.skip_binder().inputs()[1..] {
301             if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
302                 return Some(MethodViolationCode::ReferencesSelf);
303             }
304         }
305         if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
306             return Some(MethodViolationCode::ReferencesSelf);
307         }
308
309         // We can't monomorphize things like `fn foo<A>(...)`.
310         if self.generics_of(method.def_id).own_counts().types != 0 {
311             return Some(MethodViolationCode::Generic);
312         }
313
314         if self.predicates_of(method.def_id).predicates.into_iter()
315                 // A trait object can't claim to live more than the concrete type,
316                 // so outlives predicates will always hold.
317                 .filter(|p| p.to_opt_type_outlives().is_none())
318                 .collect::<Vec<_>>()
319                 // Do a shallow visit so that `contains_illegal_self_type_reference`
320                 // may apply it's custom visiting.
321                 .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) {
322             let span = self.def_span(method.def_id);
323             return Some(MethodViolationCode::WhereClauseReferencesSelf(span));
324         }
325
326         None
327     }
328
329     fn contains_illegal_self_type_reference(self,
330                                             trait_def_id: DefId,
331                                             ty: Ty<'tcx>)
332                                             -> bool
333     {
334         // This is somewhat subtle. In general, we want to forbid
335         // references to `Self` in the argument and return types,
336         // since the value of `Self` is erased. However, there is one
337         // exception: it is ok to reference `Self` in order to access
338         // an associated type of the current trait, since we retain
339         // the value of those associated types in the object type
340         // itself.
341         //
342         // ```rust
343         // trait SuperTrait {
344         //     type X;
345         // }
346         //
347         // trait Trait : SuperTrait {
348         //     type Y;
349         //     fn foo(&self, x: Self) // bad
350         //     fn foo(&self) -> Self // bad
351         //     fn foo(&self) -> Option<Self> // bad
352         //     fn foo(&self) -> Self::Y // OK, desugars to next example
353         //     fn foo(&self) -> <Self as Trait>::Y // OK
354         //     fn foo(&self) -> Self::X // OK, desugars to next example
355         //     fn foo(&self) -> <Self as SuperTrait>::X // OK
356         // }
357         // ```
358         //
359         // However, it is not as simple as allowing `Self` in a projected
360         // type, because there are illegal ways to use `Self` as well:
361         //
362         // ```rust
363         // trait Trait : SuperTrait {
364         //     ...
365         //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
366         // }
367         // ```
368         //
369         // Here we will not have the type of `X` recorded in the
370         // object type, and we cannot resolve `Self as SomeOtherTrait`
371         // without knowing what `Self` is.
372
373         let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
374         let mut error = false;
375         ty.maybe_walk(|ty| {
376             match ty.sty {
377                 ty::TyParam(ref param_ty) => {
378                     if param_ty.is_self() {
379                         error = true;
380                     }
381
382                     false // no contained types to walk
383                 }
384
385                 ty::TyProjection(ref data) => {
386                     // This is a projected type `<Foo as SomeTrait>::X`.
387
388                     // Compute supertraits of current trait lazily.
389                     if supertraits.is_none() {
390                         let trait_ref = ty::Binder::bind(
391                             ty::TraitRef::identity(self, trait_def_id),
392                         );
393                         supertraits = Some(traits::supertraits(self, trait_ref).collect());
394                     }
395
396                     // Determine whether the trait reference `Foo as
397                     // SomeTrait` is in fact a supertrait of the
398                     // current trait. In that case, this type is
399                     // legal, because the type `X` will be specified
400                     // in the object type.  Note that we can just use
401                     // direct equality here because all of these types
402                     // are part of the formal parameter listing, and
403                     // hence there should be no inference variables.
404                     let projection_trait_ref = ty::Binder::bind(data.trait_ref(self));
405                     let is_supertrait_of_current_trait =
406                         supertraits.as_ref().unwrap().contains(&projection_trait_ref);
407
408                     if is_supertrait_of_current_trait {
409                         false // do not walk contained types, do not report error, do collect $200
410                     } else {
411                         true // DO walk contained types, POSSIBLY reporting an error
412                     }
413                 }
414
415                 _ => true, // walk contained types, if any
416             }
417         });
418
419         error
420     }
421 }
422
423 pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
424                                                 trait_def_id: DefId) -> bool {
425     tcx.object_safety_violations(trait_def_id).is_empty()
426 }