]> git.proxmox.com Git - rustc.git/blame - src/librustc/traits/object_safety.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc / traits / object_safety.rs
CommitLineData
1a4d82fc
JJ
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
1a4d82fc
JJ
20use super::elaborate_predicates;
21
54a0048b 22use hir::def_id::DefId;
54a0048b
SL
23use traits;
24use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
1a4d82fc
JJ
25use std::rc::Rc;
26use syntax::ast;
1a4d82fc 27
e9174d1e 28#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1a4d82fc
JJ
29pub enum ObjectSafetyViolation<'tcx> {
30 /// Self : Sized declared on the trait
31 SizedSelf,
32
85aaf69f
SL
33 /// Supertrait reference references `Self` an in illegal location
34 /// (e.g. `trait Foo : Bar<Self>`)
35 SupertraitSelf,
36
1a4d82fc
JJ
37 /// Method has something illegal
38 Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
39}
40
41/// Reasons a method might not be object-safe.
e9174d1e 42#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1a4d82fc 43pub enum MethodViolationCode {
1a4d82fc
JJ
44 /// e.g., `fn foo()`
45 StaticMethod,
46
47 /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
48 ReferencesSelf,
49
50 /// e.g., `fn foo<A>()`
51 Generic,
52}
53
a7813a04
XL
54impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
55 pub fn is_object_safe(self, trait_def_id: DefId) -> bool {
56 // Because we query yes/no results frequently, we keep a cache:
57 let def = self.lookup_trait_def(trait_def_id);
1a4d82fc 58
a7813a04
XL
59 let result = def.object_safety().unwrap_or_else(|| {
60 let result = self.object_safety_violations(trait_def_id).is_empty();
1a4d82fc 61
a7813a04
XL
62 // Record just a yes/no result in the cache; this is what is
63 // queried most frequently. Note that this may overwrite a
64 // previous result, but always with the same thing.
65 def.set_object_safety(result);
1a4d82fc 66
a7813a04
XL
67 result
68 });
1a4d82fc 69
a7813a04 70 debug!("is_object_safe({:?}) = {}", trait_def_id, result);
1a4d82fc 71
a7813a04 72 result
b039eaaf
SL
73 }
74
a7813a04
XL
75 /// Returns the object safety violations that affect
76 /// astconv - currently, Self in supertraits. This is needed
77 /// because `object_safety_violations` can't be used during
78 /// type collection.
79 pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
80 -> Vec<ObjectSafetyViolation<'tcx>>
81 {
82 let mut violations = vec![];
b039eaaf 83
a7813a04
XL
84 if self.supertraits_reference_self(trait_def_id) {
85 violations.push(ObjectSafetyViolation::SupertraitSelf);
86 }
1a4d82fc 87
a7813a04
XL
88 debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
89 trait_def_id,
90 violations);
1a4d82fc 91
a7813a04 92 violations
1a4d82fc 93 }
a7813a04
XL
94
95 pub fn object_safety_violations(self, trait_def_id: DefId)
96 -> Vec<ObjectSafetyViolation<'tcx>>
97 {
98 traits::supertrait_def_ids(self, trait_def_id)
99 .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
100 .collect()
85aaf69f 101 }
1a4d82fc 102
a7813a04
XL
103 fn object_safety_violations_for_trait(self, trait_def_id: DefId)
104 -> Vec<ObjectSafetyViolation<'tcx>>
105 {
106 // Check methods for violations.
107 let mut violations: Vec<_> =
108 self.trait_items(trait_def_id).iter()
109 .filter_map(|item| {
110 match *item {
111 ty::MethodTraitItem(ref m) => {
112 self.object_safety_violation_for_method(trait_def_id, &m)
113 .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
114 }
115 _ => None,
116 }
117 })
118 .collect();
1a4d82fc 119
a7813a04
XL
120 // Check the trait itself.
121 if self.trait_has_sized_self(trait_def_id) {
122 violations.push(ObjectSafetyViolation::SizedSelf);
123 }
124 if self.supertraits_reference_self(trait_def_id) {
125 violations.push(ObjectSafetyViolation::SupertraitSelf);
126 }
1a4d82fc 127
a7813a04
XL
128 debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
129 trait_def_id,
130 violations);
85aaf69f 131
a7813a04
XL
132 violations
133 }
c34b1796 134
a7813a04
XL
135 fn supertraits_reference_self(self, trait_def_id: DefId) -> bool {
136 let trait_def = self.lookup_trait_def(trait_def_id);
137 let trait_ref = trait_def.trait_ref.clone();
138 let trait_ref = trait_ref.to_poly_trait_ref();
139 let predicates = self.lookup_super_predicates(trait_def_id);
140 predicates
141 .predicates
142 .into_iter()
143 .map(|predicate| predicate.subst_supertrait(self, &trait_ref))
144 .any(|predicate| {
145 match predicate {
146 ty::Predicate::Trait(ref data) => {
147 // In the case of a trait predicate, we can skip the "self" type.
9e0c209e 148 data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
a7813a04
XL
149 }
150 ty::Predicate::Projection(..) |
151 ty::Predicate::WellFormed(..) |
152 ty::Predicate::ObjectSafe(..) |
153 ty::Predicate::TypeOutlives(..) |
154 ty::Predicate::RegionOutlives(..) |
155 ty::Predicate::ClosureKind(..) |
a7813a04
XL
156 ty::Predicate::Equate(..) => {
157 false
158 }
1a4d82fc 159 }
a7813a04 160 })
c34b1796
AL
161 }
162
a7813a04 163 fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
9e0c209e 164 self.generics_require_sized_self(trait_def_id)
a7813a04 165 }
1a4d82fc 166
9e0c209e 167 fn generics_require_sized_self(self, def_id: DefId) -> bool {
a7813a04
XL
168 let sized_def_id = match self.lang_items.sized_trait() {
169 Some(def_id) => def_id,
170 None => { return false; /* No Sized trait, can't require it! */ }
171 };
172
173 // Search for a predicate like `Self : Sized` amongst the trait bounds.
9e0c209e 174 let free_substs = self.construct_free_substs(def_id,
a7813a04 175 self.region_maps.node_extent(ast::DUMMY_NODE_ID));
9e0c209e
SL
176 let predicates = self.lookup_predicates(def_id);
177 let predicates = predicates.instantiate(self, free_substs).predicates;
a7813a04
XL
178 elaborate_predicates(self, predicates)
179 .any(|predicate| {
180 match predicate {
181 ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
182 trait_pred.0.self_ty().is_self()
183 }
184 ty::Predicate::Projection(..) |
185 ty::Predicate::Trait(..) |
a7813a04
XL
186 ty::Predicate::Equate(..) |
187 ty::Predicate::RegionOutlives(..) |
188 ty::Predicate::WellFormed(..) |
189 ty::Predicate::ObjectSafe(..) |
190 ty::Predicate::ClosureKind(..) |
191 ty::Predicate::TypeOutlives(..) => {
192 false
193 }
194 }
195 })
196 }
c34b1796 197
a7813a04
XL
198 /// Returns `Some(_)` if this method makes the containing trait not object safe.
199 fn object_safety_violation_for_method(self,
200 trait_def_id: DefId,
201 method: &ty::Method<'gcx>)
202 -> Option<MethodViolationCode>
203 {
204 // Any method that has a `Self : Sized` requisite is otherwise
205 // exempt from the regulations.
9e0c209e 206 if self.generics_require_sized_self(method.def_id) {
a7813a04 207 return None;
1a4d82fc
JJ
208 }
209
a7813a04 210 self.virtual_call_violation_for_method(trait_def_id, method)
1a4d82fc
JJ
211 }
212
a7813a04
XL
213 /// We say a method is *vtable safe* if it can be invoked on a trait
214 /// object. Note that object-safe traits can have some
215 /// non-vtable-safe methods, so long as they require `Self:Sized` or
216 /// otherwise ensure that they cannot be used when `Self=Trait`.
217 pub fn is_vtable_safe_method(self,
218 trait_def_id: DefId,
219 method: &ty::Method<'gcx>)
220 -> bool
221 {
222 // Any method that has a `Self : Sized` requisite can't be called.
9e0c209e 223 if self.generics_require_sized_self(method.def_id) {
a7813a04 224 return false;
1a4d82fc 225 }
1a4d82fc 226
a7813a04 227 self.virtual_call_violation_for_method(trait_def_id, method).is_none()
1a4d82fc
JJ
228 }
229
a7813a04
XL
230 /// Returns `Some(_)` if this method cannot be called on a trait
231 /// object; this does not necessarily imply that the enclosing trait
232 /// is not object safe, because the method might have a where clause
233 /// `Self:Sized`.
234 fn virtual_call_violation_for_method(self,
235 trait_def_id: DefId,
236 method: &ty::Method<'tcx>)
237 -> Option<MethodViolationCode>
238 {
239 // The method's first parameter must be something that derefs (or
240 // autorefs) to `&self`. For now, we only accept `self`, `&self`
241 // and `Box<Self>`.
242 match method.explicit_self {
243 ty::ExplicitSelfCategory::Static => {
244 return Some(MethodViolationCode::StaticMethod);
245 }
1a4d82fc 246
a7813a04
XL
247 ty::ExplicitSelfCategory::ByValue |
248 ty::ExplicitSelfCategory::ByReference(..) |
249 ty::ExplicitSelfCategory::ByBox => {
250 }
251 }
1a4d82fc 252
a7813a04
XL
253 // The `Self` type is erased, so it should not appear in list of
254 // arguments or return type apart from the receiver.
255 let ref sig = method.fty.sig;
256 for &input_ty in &sig.0.inputs[1..] {
257 if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
258 return Some(MethodViolationCode::ReferencesSelf);
259 }
260 }
5bcae85e
SL
261 if self.contains_illegal_self_type_reference(trait_def_id, sig.0.output) {
262 return Some(MethodViolationCode::ReferencesSelf);
a7813a04 263 }
1a4d82fc 264
a7813a04 265 // We can't monomorphize things like `fn foo<A>(...)`.
9e0c209e 266 if !method.generics.types.is_empty() {
a7813a04
XL
267 return Some(MethodViolationCode::Generic);
268 }
1a4d82fc 269
a7813a04
XL
270 None
271 }
272
273 fn contains_illegal_self_type_reference(self,
274 trait_def_id: DefId,
275 ty: Ty<'tcx>)
276 -> bool
277 {
278 // This is somewhat subtle. In general, we want to forbid
279 // references to `Self` in the argument and return types,
280 // since the value of `Self` is erased. However, there is one
281 // exception: it is ok to reference `Self` in order to access
282 // an associated type of the current trait, since we retain
283 // the value of those associated types in the object type
284 // itself.
285 //
286 // ```rust
287 // trait SuperTrait {
288 // type X;
289 // }
290 //
291 // trait Trait : SuperTrait {
292 // type Y;
293 // fn foo(&self, x: Self) // bad
294 // fn foo(&self) -> Self // bad
295 // fn foo(&self) -> Option<Self> // bad
296 // fn foo(&self) -> Self::Y // OK, desugars to next example
297 // fn foo(&self) -> <Self as Trait>::Y // OK
298 // fn foo(&self) -> Self::X // OK, desugars to next example
299 // fn foo(&self) -> <Self as SuperTrait>::X // OK
300 // }
301 // ```
302 //
303 // However, it is not as simple as allowing `Self` in a projected
304 // type, because there are illegal ways to use `Self` as well:
305 //
306 // ```rust
307 // trait Trait : SuperTrait {
308 // ...
309 // fn foo(&self) -> <Self as SomeOtherTrait>::X;
310 // }
311 // ```
312 //
313 // Here we will not have the type of `X` recorded in the
314 // object type, and we cannot resolve `Self as SomeOtherTrait`
315 // without knowing what `Self` is.
316
317 let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
318 let mut error = false;
319 ty.maybe_walk(|ty| {
320 match ty.sty {
321 ty::TyParam(ref param_ty) => {
9e0c209e 322 if param_ty.is_self() {
a7813a04
XL
323 error = true;
324 }
325
326 false // no contained types to walk
1a4d82fc
JJ
327 }
328
a7813a04
XL
329 ty::TyProjection(ref data) => {
330 // This is a projected type `<Foo as SomeTrait>::X`.
331
332 // Compute supertraits of current trait lazily.
333 if supertraits.is_none() {
334 let trait_def = self.lookup_trait_def(trait_def_id);
335 let trait_ref = ty::Binder(trait_def.trait_ref.clone());
336 supertraits = Some(traits::supertraits(self, trait_ref).collect());
337 }
338
339 // Determine whether the trait reference `Foo as
340 // SomeTrait` is in fact a supertrait of the
341 // current trait. In that case, this type is
342 // legal, because the type `X` will be specified
343 // in the object type. Note that we can just use
344 // direct equality here because all of these types
345 // are part of the formal parameter listing, and
346 // hence there should be no inference variables.
347 let projection_trait_ref = ty::Binder(data.trait_ref.clone());
348 let is_supertrait_of_current_trait =
349 supertraits.as_ref().unwrap().contains(&projection_trait_ref);
350
351 if is_supertrait_of_current_trait {
352 false // do not walk contained types, do not report error, do collect $200
353 } else {
354 true // DO walk contained types, POSSIBLY reporting an error
355 }
1a4d82fc 356 }
1a4d82fc 357
a7813a04
XL
358 _ => true, // walk contained types, if any
359 }
360 });
1a4d82fc 361
a7813a04
XL
362 error
363 }
1a4d82fc 364}