object_safety.rs 17.5 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 lint;
24
use traits;
25
use ty::{self, Ty, TyCtxt, TypeFoldable};
26
use ty::subst::Substs;
27
use ty::util::ExplicitSelf;
28
use std::borrow::Cow;
29
use syntax::ast;
30
use syntax_pos::Span;
31

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

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

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

    /// Associated const
    AssociatedConst(ast::Name),
46 47
}

48 49 50 51 52 53 54
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 \
55
                 in the supertraits or where-clauses".into(),
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(),
61 62 63
            ObjectSafetyViolation::Method(name,
                                            MethodViolationCode::WhereClauseReferencesSelf(_)) =>
                format!("method `{}` references the `Self` type in where clauses", name).into(),
64 65
            ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
                format!("method `{}` has generic type parameters", name).into(),
66
            ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
67
                format!("method `{}` has a non-standard `self` type", name).into(),
68
            ObjectSafetyViolation::AssociatedConst(name) =>
W
Without Boats 已提交
69
                format!("the trait cannot contain associated consts like `{}`", name).into(),
70 71 72 73
        }
    }
}

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

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

83 84 85
    /// e.g. `fn foo(&self) where Self: Clone`
    WhereClauseReferencesSelf(Span),

N
Niko Matsakis 已提交
86
    /// e.g., `fn foo<A>()`
87
    Generic,
88 89 90

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

93
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
94

95 96 97 98 99
    /// 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)
100
                                            -> Vec<ObjectSafetyViolation>
101 102 103
    {
        let mut violations = vec![];

104
        for def_id in traits::supertrait_def_ids(self, trait_def_id) {
105
            if self.predicates_reference_self(def_id, true) {
106 107
                violations.push(ObjectSafetyViolation::SupertraitSelf);
            }
108
        }
109

110 111 112
        debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}",
               trait_def_id,
               violations);
113

114 115 116 117
        violations
    }

    pub fn object_safety_violations(self, trait_def_id: DefId)
118
                                    -> Vec<ObjectSafetyViolation>
119 120 121 122 123
    {
        traits::supertrait_def_ids(self, trait_def_id)
            .flat_map(|def_id| self.object_safety_violations_for_trait(def_id))
            .collect()
    }
124

125
    fn object_safety_violations_for_trait(self, trait_def_id: DefId)
126
                                          -> Vec<ObjectSafetyViolation>
127 128
    {
        // Check methods for violations.
129 130
        let mut violations: Vec<_> = self.associated_items(trait_def_id)
            .filter(|item| item.kind == ty::AssociatedKind::Method)
131
            .filter_map(|item| {
132 133
                self.object_safety_violation_for_method(trait_def_id, &item)
                    .map(|code| ObjectSafetyViolation::Method(item.name, code))
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
            }).filter(|violation| {
                if let ObjectSafetyViolation::Method(_,
                                MethodViolationCode::WhereClauseReferencesSelf(span)) = violation {
                    // Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
                    // It's also hard to get a use site span, so we use the method definition span.
                    self.lint_node_note(
                        lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
                        ast::CRATE_NODE_ID,
                        *span,
                        &format!("the trait `{}` cannot be made into an object",
                                self.item_path_str(trait_def_id)),
                        &violation.error_msg());
                    false
                } else {
                    true
                }
150
            }).collect();
151

152 153 154 155
        // Check the trait itself.
        if self.trait_has_sized_self(trait_def_id) {
            violations.push(ObjectSafetyViolation::SizedSelf);
        }
156
        if self.predicates_reference_self(trait_def_id, false) {
157 158
            violations.push(ObjectSafetyViolation::SupertraitSelf);
        }
159

160 161 162 163
        violations.extend(self.associated_items(trait_def_id)
            .filter(|item| item.kind == ty::AssociatedKind::Const)
            .map(|item| ObjectSafetyViolation::AssociatedConst(item.name)));

164 165 166
        debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
               trait_def_id,
               violations);
167

168 169
        violations
    }
170

171 172 173 174 175
    fn predicates_reference_self(
        self,
        trait_def_id: DefId,
        supertraits_only: bool) -> bool
    {
176
        let trait_ref = ty::Binder::dummy(ty::TraitRef {
177 178 179
            def_id: trait_def_id,
            substs: Substs::identity_for_item(self, trait_def_id)
        });
180
        let predicates = if supertraits_only {
181
            self.super_predicates_of(trait_def_id)
182
        } else {
183
            self.predicates_of(trait_def_id)
184
        };
185 186 187 188 189 190 191 192
        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.
193
                        data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
194 195 196 197 198 199 200
                    }
                    ty::Predicate::Projection(..) |
                    ty::Predicate::WellFormed(..) |
                    ty::Predicate::ObjectSafe(..) |
                    ty::Predicate::TypeOutlives(..) |
                    ty::Predicate::RegionOutlives(..) |
                    ty::Predicate::ClosureKind(..) |
N
Niko Matsakis 已提交
201
                    ty::Predicate::Subtype(..) |
202
                    ty::Predicate::ConstEvaluatable(..) => {
203 204
                        false
                    }
205
                }
206 207
            })
    }
208

209
    fn trait_has_sized_self(self, trait_def_id: DefId) -> bool {
210
        self.generics_require_sized_self(trait_def_id)
211
    }
212

213
    fn generics_require_sized_self(self, def_id: DefId) -> bool {
214
        let sized_def_id = match self.lang_items().sized_trait() {
215 216 217 218 219
            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.
220
        let predicates = self.predicates_of(def_id);
221
        let predicates = predicates.instantiate_identity(self).predicates;
222 223 224 225
        elaborate_predicates(self, predicates)
            .any(|predicate| {
                match predicate {
                    ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
226
                        trait_pred.skip_binder().self_ty().is_self()
227 228 229
                    }
                    ty::Predicate::Projection(..) |
                    ty::Predicate::Trait(..) |
N
Niko Matsakis 已提交
230
                    ty::Predicate::Subtype(..) |
231 232 233 234
                    ty::Predicate::RegionOutlives(..) |
                    ty::Predicate::WellFormed(..) |
                    ty::Predicate::ObjectSafe(..) |
                    ty::Predicate::ClosureKind(..) |
235 236
                    ty::Predicate::TypeOutlives(..) |
                    ty::Predicate::ConstEvaluatable(..) => {
237 238
                        false
                    }
239
                }
240 241 242 243 244 245
            })
    }

    /// Returns `Some(_)` if this method makes the containing trait not object safe.
    fn object_safety_violation_for_method(self,
                                          trait_def_id: DefId,
246
                                          method: &ty::AssociatedItem)
247 248 249 250
                                          -> Option<MethodViolationCode>
    {
        // Any method that has a `Self : Sized` requisite is otherwise
        // exempt from the regulations.
251
        if self.generics_require_sized_self(method.def_id) {
252 253
            return None;
        }
254

255
        self.virtual_call_violation_for_method(trait_def_id, method)
256 257
    }

258 259 260 261 262 263
    /// 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,
264
                                 method: &ty::AssociatedItem)
265 266
                                 -> bool
    {
267
        // Any method that has a `Self : Sized` requisite can't be called.
268
        if self.generics_require_sized_self(method.def_id) {
269 270 271
            return false;
        }

272 273 274 275
        match self.virtual_call_violation_for_method(trait_def_id, method) {
            None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true,
            Some(_) => false,
        }
276
    }
277

278 279 280 281 282 283
    /// 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,
284
                                         method: &ty::AssociatedItem)
285 286 287 288 289
                                         -> 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>`.
290 291
        if !method.method_has_self_argument {
            return Some(MethodViolationCode::StaticMethod);
292 293
        }

294 295 296 297 298 299 300 301
        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);
        }

302 303
        // The `Self` type is erased, so it should not appear in list of
        // arguments or return type apart from the receiver.
304
        for input_ty in &sig.skip_binder().inputs()[1..] {
305 306 307
            if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
                return Some(MethodViolationCode::ReferencesSelf);
            }
308
        }
309
        if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
310
            return Some(MethodViolationCode::ReferencesSelf);
311
        }
312 313

        // We can't monomorphize things like `fn foo<A>(...)`.
V
varkor 已提交
314
        if self.generics_of(method.def_id).own_counts().types != 0 {
315
            return Some(MethodViolationCode::Generic);
316 317
        }

318 319 320 321 322 323 324 325
        if self.predicates_of(method.def_id).predicates.into_iter()
                // A trait object can't claim to live more than the concrete type,
                // so outlives predicates will always hold.
                .filter(|p| p.to_opt_type_outlives().is_none())
                .collect::<Vec<_>>()
                // Do a shallow visit so that `contains_illegal_self_type_reference`
                // may apply it's custom visiting.
                .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) {
326 327
            let span = self.def_span(method.def_id);
            return Some(MethodViolationCode::WhereClauseReferencesSelf(span));
328 329
        }

330
        None
331 332
    }

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
    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) => {
382
                    if param_ty.is_self() {
383 384 385 386
                        error = true;
                    }

                    false // no contained types to walk
387 388
                }

389 390 391 392 393
                ty::TyProjection(ref data) => {
                    // This is a projected type `<Foo as SomeTrait>::X`.

                    // Compute supertraits of current trait lazily.
                    if supertraits.is_none() {
394
                        let trait_ref = ty::Binder::bind(ty::TraitRef {
395 396 397
                            def_id: trait_def_id,
                            substs: Substs::identity_for_item(self, trait_def_id)
                        });
398 399 400 401 402 403 404 405 406 407 408
                        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.
409
                    let projection_trait_ref = ty::Binder::bind(data.trait_ref(self));
410 411 412 413 414 415 416 417
                    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
                    }
418 419
                }

420
                _ => true, // walk contained types, if any
421
            }
422
        });
423

424 425
        error
    }
426
}
427 428

pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
V
varkor 已提交
429
                                                trait_def_id: DefId) -> bool {
430 431
    tcx.object_safety_violations(trait_def_id).is_empty()
}