object_safety.rs 15.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! "Object safety" refers to the ability for a trait to be converted
//! to an object. In general, traits may only be converted to an
//! object if all of their methods meet certain criteria. In particular,
//! they must:
//!
//!   - have a suitable receiver from which we can extract a vtable;
//!   - not reference the erased type `Self` except for in this receiver;
//!   - not have generic type parameters

use super::elaborate_predicates;

22
use hir::def_id::DefId;
23
use traits;
24 25
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::subst::Substs;
26
use ty::util::ExplicitSelf;
27
use std::borrow::Cow;
28 29
use syntax::ast;

30
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
31
pub enum ObjectSafetyViolation {
32 33 34
    /// Self : Sized declared on the trait
    SizedSelf,

35 36 37 38
    /// Supertrait reference references `Self` an in illegal location
    /// (e.g. `trait Foo : Bar<Self>`)
    SupertraitSelf,

J
Joseph Crail 已提交
39
    /// Method has something illegal
40
    Method(ast::Name, MethodViolationCode),
41 42 43

    /// Associated const
    AssociatedConst(ast::Name),
44 45
}

46 47 48 49 50 51 52
impl ObjectSafetyViolation {
    pub fn error_msg(&self) -> Cow<'static, str> {
        match *self {
            ObjectSafetyViolation::SizedSelf =>
                "the trait cannot require that `Self : Sized`".into(),
            ObjectSafetyViolation::SupertraitSelf =>
                "the trait cannot use `Self` as a type parameter \
53
                 in the supertraits or where-clauses".into(),
54 55 56 57 58 59 60
            ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
                format!("method `{}` has no receiver", name).into(),
            ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
                format!("method `{}` references the `Self` type \
                         in its arguments or return type", name).into(),
            ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
                format!("method `{}` has generic type parameters", name).into(),
61
            ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
M
Michael Hewson 已提交
62 63 64
                format!("method `{}` has a non-standard `self` type. Only `&self`, \
                        `&mut self`, and `Box<Self>` are currently supported \
                        for trait objects", name).into(),
65
            ObjectSafetyViolation::AssociatedConst(name) =>
W
Without Boats 已提交
66
                format!("the trait cannot contain associated consts like `{}`", name).into(),
67 68 69 70
        }
    }
}

71
/// Reasons a method might not be object-safe.
72
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
73
pub enum MethodViolationCode {
N
Niko Matsakis 已提交
74
    /// e.g., `fn foo()`
75 76
    StaticMethod,

N
Niko Matsakis 已提交
77
    /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
78 79
    ReferencesSelf,

N
Niko Matsakis 已提交
80
    /// e.g., `fn foo<A>()`
81
    Generic,
82 83 84

    /// arbitrary `self` type, e.g. `self: Rc<Self>`
    NonStandardSelfType,
85 86
}

87
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
88

89 90 91 92 93
    /// Returns the object safety violations that affect
    /// astconv - currently, Self in supertraits. This is needed
    /// because `object_safety_violations` can't be used during
    /// type collection.
    pub fn astconv_object_safety_violations(self, trait_def_id: DefId)
94
                                            -> Vec<ObjectSafetyViolation>
95 96 97
    {
        let mut violations = vec![];

98
        for def_id in traits::supertrait_def_ids(self, trait_def_id) {
99
            if self.predicates_reference_self(def_id, true) {
100 101
                violations.push(ObjectSafetyViolation::SupertraitSelf);
            }
102
        }
103

104 105 106
        debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
               trait_def_id,
               violations);
107

108 109 110 111
        violations
    }

    pub fn object_safety_violations(self, trait_def_id: DefId)
112
                                    -> Vec<ObjectSafetyViolation>
113 114 115 116 117
    {
        traits::supertrait_def_ids(self, trait_def_id)
            .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
            .collect()
    }
118

119
    fn object_safety_violations_for_trait(self, trait_def_id: DefId)
120
                                          -> Vec<ObjectSafetyViolation>
121 122
    {
        // Check methods for violations.
123 124
        let mut violations: Vec<_> = self.associated_items(trait_def_id)
            .filter(|item| item.kind == ty::AssociatedKind::Method)
125
            .filter_map(|item| {
126 127 128
                self.object_safety_violation_for_method(trait_def_id, &item)
                    .map(|code| ObjectSafetyViolation::Method(item.name, code))
            }).collect();
129

130 131 132 133
        // Check the trait itself.
        if self.trait_has_sized_self(trait_def_id) {
            violations.push(ObjectSafetyViolation::SizedSelf);
        }
134
        if self.predicates_reference_self(trait_def_id, false) {
135 136
            violations.push(ObjectSafetyViolation::SupertraitSelf);
        }
137

138 139 140 141
        violations.extend(self.associated_items(trait_def_id)
            .filter(|item| item.kind == ty::AssociatedKind::Const)
            .map(|item| ObjectSafetyViolation::AssociatedConst(item.name)));

142 143 144
        debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
               trait_def_id,
               violations);
145

146 147
        violations
    }
148

149 150 151 152 153
    fn predicates_reference_self(
        self,
        trait_def_id: DefId,
        supertraits_only: bool) -> bool
    {
154 155 156 157
        let trait_ref = ty::Binder(ty::TraitRef {
            def_id: trait_def_id,
            substs: Substs::identity_for_item(self, trait_def_id)
        });
158
        let predicates = if supertraits_only {
159
            self.super_predicates_of(trait_def_id)
160
        } else {
161
            self.predicates_of(trait_def_id)
162
        };
163 164 165 166 167 168 169 170
        predicates
            .predicates
            .into_iter()
            .map(|predicate| predicate.subst_supertrait(self, &trait_ref))
            .any(|predicate| {
                match predicate {
                    ty::Predicate::Trait(ref data) => {
                        // In the case of a trait predicate, we can skip the "self" type.
171
                        data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
172 173 174 175 176 177 178
                    }
                    ty::Predicate::Projection(..) |
                    ty::Predicate::WellFormed(..) |
                    ty::Predicate::ObjectSafe(..) |
                    ty::Predicate::TypeOutlives(..) |
                    ty::Predicate::RegionOutlives(..) |
                    ty::Predicate::ClosureKind(..) |
N
Niko Matsakis 已提交
179
                    ty::Predicate::Subtype(..) |
180 181
                    ty::Predicate::Equate(..) |
                    ty::Predicate::ConstEvaluatable(..) => {
182 183
                        false
                    }
184
                }
185 186
            })
    }
187

188
    fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
189
        self.generics_require_sized_self(trait_def_id)
190
    }
191

192
    fn generics_require_sized_self(self, def_id: DefId) -> bool {
193
        let sized_def_id = match self.lang_items().sized_trait() {
194 195 196 197 198
            Some(def_id) => def_id,
            None => { return false; /* No Sized trait, can't require it! */ }
        };

        // Search for a predicate like `Self : Sized` amongst the trait bounds.
199
        let predicates = self.predicates_of(def_id);
200
        let predicates = predicates.instantiate_identity(self).predicates;
201 202 203 204 205 206 207 208 209
        elaborate_predicates(self, predicates)
            .any(|predicate| {
                match predicate {
                    ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
                        trait_pred.0.self_ty().is_self()
                    }
                    ty::Predicate::Projection(..) |
                    ty::Predicate::Trait(..) |
                    ty::Predicate::Equate(..) |
N
Niko Matsakis 已提交
210
                    ty::Predicate::Subtype(..) |
211 212 213 214
                    ty::Predicate::RegionOutlives(..) |
                    ty::Predicate::WellFormed(..) |
                    ty::Predicate::ObjectSafe(..) |
                    ty::Predicate::ClosureKind(..) |
215 216
                    ty::Predicate::TypeOutlives(..) |
                    ty::Predicate::ConstEvaluatable(..) => {
217 218
                        false
                    }
219
                }
220 221 222 223 224 225
            })
    }

    /// Returns `Some(_)` if this method makes the containing trait not object safe.
    fn object_safety_violation_for_method(self,
                                          trait_def_id: DefId,
226
                                          method: &ty::AssociatedItem)
227 228 229 230
                                          -> Option<MethodViolationCode>
    {
        // Any method that has a `Self : Sized` requisite is otherwise
        // exempt from the regulations.
231
        if self.generics_require_sized_self(method.def_id) {
232 233
            return None;
        }
234

235
        self.virtual_call_violation_for_method(trait_def_id, method)
236 237
    }

238 239 240 241 242 243
    /// We say a method is *vtable safe* if it can be invoked on a trait
    /// object.  Note that object-safe traits can have some
    /// non-vtable-safe methods, so long as they require `Self:Sized` or
    /// otherwise ensure that they cannot be used when `Self=Trait`.
    pub fn is_vtable_safe_method(self,
                                 trait_def_id: DefId,
244
                                 method: &ty::AssociatedItem)
245 246
                                 -> bool
    {
247
        // Any method that has a `Self : Sized` requisite can't be called.
248
        if self.generics_require_sized_self(method.def_id) {
249 250 251
            return false;
        }

252 253
        self.virtual_call_violation_for_method(trait_def_id, method).is_none()
    }
254

255 256 257 258 259 260
    /// Returns `Some(_)` if this method cannot be called on a trait
    /// object; this does not necessarily imply that the enclosing trait
    /// is not object safe, because the method might have a where clause
    /// `Self:Sized`.
    fn virtual_call_violation_for_method(self,
                                         trait_def_id: DefId,
261
                                         method: &ty::AssociatedItem)
262 263 264 265 266
                                         -> Option<MethodViolationCode>
    {
        // The method's first parameter must be something that derefs (or
        // autorefs) to `&self`. For now, we only accept `self`, `&self`
        // and `Box<Self>`.
267 268
        if !method.method_has_self_argument {
            return Some(MethodViolationCode::StaticMethod);
269 270
        }

271 272 273 274 275 276 277 278
        let sig = self.fn_sig(method.def_id);

        let self_ty = self.mk_self_type();
        let self_arg_ty = sig.skip_binder().inputs()[0];
        if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
            return Some(MethodViolationCode::NonStandardSelfType);
        }

279 280
        // The `Self` type is erased, so it should not appear in list of
        // arguments or return type apart from the receiver.
281
        for input_ty in &sig.skip_binder().inputs()[1..] {
282 283 284
            if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
                return Some(MethodViolationCode::ReferencesSelf);
            }
285
        }
286
        if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
287
            return Some(MethodViolationCode::ReferencesSelf);
288
        }
289 290

        // We can't monomorphize things like `fn foo<A>(...)`.
291
        if !self.generics_of(method.def_id).types.is_empty() {
292
            return Some(MethodViolationCode::Generic);
293 294
        }

295
        None
296 297
    }

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
    fn contains_illegal_self_type_reference(self,
                                            trait_def_id: DefId,
                                            ty: Ty<'tcx>)
                                            -> bool
    {
        // This is somewhat subtle. In general, we want to forbid
        // references to `Self` in the argument and return types,
        // since the value of `Self` is erased. However, there is one
        // exception: it is ok to reference `Self` in order to access
        // an associated type of the current trait, since we retain
        // the value of those associated types in the object type
        // itself.
        //
        // ```rust
        // trait SuperTrait {
        //     type X;
        // }
        //
        // trait Trait : SuperTrait {
        //     type Y;
        //     fn foo(&self, x: Self) // bad
        //     fn foo(&self) -> Self // bad
        //     fn foo(&self) -> Option<Self> // bad
        //     fn foo(&self) -> Self::Y // OK, desugars to next example
        //     fn foo(&self) -> <Self as Trait>::Y // OK
        //     fn foo(&self) -> Self::X // OK, desugars to next example
        //     fn foo(&self) -> <Self as SuperTrait>::X // OK
        // }
        // ```
        //
        // However, it is not as simple as allowing `Self` in a projected
        // type, because there are illegal ways to use `Self` as well:
        //
        // ```rust
        // trait Trait : SuperTrait {
        //     ...
        //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
        // }
        // ```
        //
        // Here we will not have the type of `X` recorded in the
        // object type, and we cannot resolve `Self as SomeOtherTrait`
        // without knowing what `Self` is.

        let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
        let mut error = false;
        ty.maybe_walk(|ty| {
            match ty.sty {
                ty::TyParam(ref param_ty) => {
347
                    if param_ty.is_self() {
348 349 350 351
                        error = true;
                    }

                    false // no contained types to walk
352 353
                }

354 355 356 357 358
                ty::TyProjection(ref data) => {
                    // This is a projected type `<Foo as SomeTrait>::X`.

                    // Compute supertraits of current trait lazily.
                    if supertraits.is_none() {
359 360 361 362
                        let trait_ref = ty::Binder(ty::TraitRef {
                            def_id: trait_def_id,
                            substs: Substs::identity_for_item(self, trait_def_id)
                        });
363 364 365 366 367 368 369 370 371 372 373
                        supertraits = Some(traits::supertraits(self, trait_ref).collect());
                    }

                    // Determine whether the trait reference `Foo as
                    // SomeTrait` is in fact a supertrait of the
                    // current trait. In that case, this type is
                    // legal, because the type `X` will be specified
                    // in the object type.  Note that we can just use
                    // direct equality here because all of these types
                    // are part of the formal parameter listing, and
                    // hence there should be no inference variables.
374
                    let projection_trait_ref = ty::Binder(data.trait_ref(self));
375 376 377 378 379 380 381 382
                    let is_supertrait_of_current_trait =
                        supertraits.as_ref().unwrap().contains(&projection_trait_ref);

                    if is_supertrait_of_current_trait {
                        false // do not walk contained types, do not report error, do collect $200
                    } else {
                        true // DO walk contained types, POSSIBLY reporting an error
                    }
383 384
                }

385
                _ => true, // walk contained types, if any
386
            }
387
        });
388

389 390
        error
    }
391
}
392 393 394 395 396 397

pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         trait_def_id: DefId)
                                         -> bool {
    tcx.object_safety_violations(trait_def_id).is_empty()
}