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