mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Refactor object-safety into its own (cached) module so that we can
check it more easily; also extend object safety to cover sized types as well as static methods. This makes it sufficient so that we can always ensure that `Foo : Foo` holds for any trait `Foo`.
This commit is contained in:
parent
2c1d7a7caa
commit
19dcecb225
@ -29,6 +29,10 @@ pub use self::fulfill::{FulfillmentContext, RegionObligation};
|
|||||||
pub use self::project::MismatchedProjectionTypes;
|
pub use self::project::MismatchedProjectionTypes;
|
||||||
pub use self::project::normalize;
|
pub use self::project::normalize;
|
||||||
pub use self::project::Normalized;
|
pub use self::project::Normalized;
|
||||||
|
pub use self::object_safety::is_object_safe;
|
||||||
|
pub use self::object_safety::object_safety_violations;
|
||||||
|
pub use self::object_safety::ObjectSafetyViolation;
|
||||||
|
pub use self::object_safety::MethodViolationCode;
|
||||||
pub use self::select::SelectionContext;
|
pub use self::select::SelectionContext;
|
||||||
pub use self::select::SelectionCache;
|
pub use self::select::SelectionCache;
|
||||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||||
@ -45,6 +49,7 @@ mod coherence;
|
|||||||
mod error_reporting;
|
mod error_reporting;
|
||||||
mod fulfill;
|
mod fulfill;
|
||||||
mod project;
|
mod project;
|
||||||
|
mod object_safety;
|
||||||
mod select;
|
mod select;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
302
src/librustc/middle/traits/object_safety.rs
Normal file
302
src/librustc/middle/traits/object_safety.rs
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
// 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::supertraits;
|
||||||
|
use super::elaborate_predicates;
|
||||||
|
|
||||||
|
use middle::subst::{mod, SelfSpace};
|
||||||
|
use middle::traits;
|
||||||
|
use middle::ty::{mod, Ty};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use syntax::ast;
|
||||||
|
use util::ppaux::Repr;
|
||||||
|
|
||||||
|
pub enum ObjectSafetyViolation<'tcx> {
|
||||||
|
/// Self : Sized declared on the trait
|
||||||
|
SizedSelf,
|
||||||
|
|
||||||
|
/// Method has someting illegal
|
||||||
|
Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reasons a method might not be object-safe.
|
||||||
|
#[deriving(Copy,Clone,Show)]
|
||||||
|
pub enum MethodViolationCode {
|
||||||
|
/// fn(self),
|
||||||
|
ByValueSelf,
|
||||||
|
|
||||||
|
// fn foo()
|
||||||
|
StaticMethod,
|
||||||
|
|
||||||
|
// fn foo(&self, x: Self)
|
||||||
|
// fn foo(&self) -> Self
|
||||||
|
ReferencesSelf,
|
||||||
|
|
||||||
|
// fn foo<A>(),
|
||||||
|
Generic,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
// Because we query yes/no results frequently, we keep a cache:
|
||||||
|
let cached_result =
|
||||||
|
tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).map(|&r| r);
|
||||||
|
|
||||||
|
let result =
|
||||||
|
cached_result.unwrap_or_else(|| {
|
||||||
|
let result = object_safety_violations(tcx, trait_ref.clone()).is_empty();
|
||||||
|
|
||||||
|
// Record just a yes/no result in the cache; this is what is
|
||||||
|
// queried most frequently. Note that this may overwrite a
|
||||||
|
// previous result, but always with the same thing.
|
||||||
|
tcx.object_safety_cache.borrow_mut().insert(trait_ref.def_id(), result);
|
||||||
|
|
||||||
|
result
|
||||||
|
});
|
||||||
|
|
||||||
|
debug!("is_object_safe({}) = {}", trait_ref.repr(tcx), result);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
sub_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||||
|
-> Vec<ObjectSafetyViolation<'tcx>>
|
||||||
|
{
|
||||||
|
supertraits(tcx, sub_trait_ref)
|
||||||
|
.flat_map(|tr| object_safety_violations_for_trait(tcx, tr.def_id()).into_iter())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
trait_def_id: ast::DefId)
|
||||||
|
-> Vec<ObjectSafetyViolation<'tcx>>
|
||||||
|
{
|
||||||
|
// Check methods for violations.
|
||||||
|
let mut violations: Vec<_> =
|
||||||
|
ty::trait_items(tcx, trait_def_id).iter()
|
||||||
|
.flat_map(|item| {
|
||||||
|
match *item {
|
||||||
|
ty::MethodTraitItem(ref m) => {
|
||||||
|
object_safety_violations_for_method(tcx, trait_def_id, &**m)
|
||||||
|
.map(|code| ObjectSafetyViolation::Method(m.clone(), code))
|
||||||
|
.into_iter()
|
||||||
|
}
|
||||||
|
ty::TypeTraitItem(_) => {
|
||||||
|
None.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Check the trait itself.
|
||||||
|
if trait_has_sized_self(tcx, trait_def_id) {
|
||||||
|
violations.push(ObjectSafetyViolation::SizedSelf);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("object_safety_violations_for_trait(trait_def_id={}) = {}",
|
||||||
|
trait_def_id.repr(tcx),
|
||||||
|
violations.repr(tcx));
|
||||||
|
|
||||||
|
violations
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
trait_def_id: ast::DefId)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||||
|
let param_env = ty::construct_parameter_environment(tcx,
|
||||||
|
&trait_def.generics,
|
||||||
|
ast::DUMMY_NODE_ID);
|
||||||
|
let predicates = param_env.caller_bounds.predicates.as_slice().to_vec();
|
||||||
|
let sized_def_id = match tcx.lang_items.sized_trait() {
|
||||||
|
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.
|
||||||
|
elaborate_predicates(tcx, predicates)
|
||||||
|
.any(|predicate| {
|
||||||
|
match predicate {
|
||||||
|
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
|
||||||
|
let self_ty = trait_pred.0.self_ty();
|
||||||
|
match self_ty.sty {
|
||||||
|
ty::ty_param(ref data) => data.space == subst::SelfSpace,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Predicate::Projection(..) |
|
||||||
|
ty::Predicate::Trait(..) |
|
||||||
|
ty::Predicate::Equate(..) |
|
||||||
|
ty::Predicate::RegionOutlives(..) |
|
||||||
|
ty::Predicate::TypeOutlives(..) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_safety_violations_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
trait_def_id: ast::DefId,
|
||||||
|
method: &ty::Method<'tcx>)
|
||||||
|
-> Option<MethodViolationCode>
|
||||||
|
{
|
||||||
|
// The method's first parameter must be something that derefs to
|
||||||
|
// `&self`. For now, we only accept `&self` and `Box<Self>`.
|
||||||
|
match method.explicit_self {
|
||||||
|
ty::ByValueExplicitSelfCategory => {
|
||||||
|
return Some(MethodViolationCode::ByValueSelf);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::StaticExplicitSelfCategory => {
|
||||||
|
return Some(MethodViolationCode::StaticMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::ByReferenceExplicitSelfCategory(..) |
|
||||||
|
ty::ByBoxExplicitSelfCategory => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The `Self` type is erased, so it should not appear in list of
|
||||||
|
// arguments or return type apart from the receiver.
|
||||||
|
let ref sig = method.fty.sig;
|
||||||
|
for &input_ty in sig.0.inputs[1..].iter() {
|
||||||
|
if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
|
||||||
|
return Some(MethodViolationCode::ReferencesSelf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let ty::FnConverging(result_type) = sig.0.output {
|
||||||
|
if contains_illegal_self_type_reference(tcx, trait_def_id, result_type) {
|
||||||
|
return Some(MethodViolationCode::ReferencesSelf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't monomorphize things like `fn foo<A>(...)`.
|
||||||
|
if !method.generics.types.is_empty_in(subst::FnSpace) {
|
||||||
|
return Some(MethodViolationCode::Generic);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
trait_def_id: ast::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(ty, |ty| {
|
||||||
|
match ty.sty {
|
||||||
|
ty::ty_param(ref param_ty) => {
|
||||||
|
if param_ty.space == SelfSpace {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false // no contained types to walk
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::ty_projection(ref data) => {
|
||||||
|
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||||
|
|
||||||
|
// Compute supertraits of current trait lazilly.
|
||||||
|
if supertraits.is_none() {
|
||||||
|
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||||
|
let trait_ref = ty::Binder(trait_def.trait_ref.clone());
|
||||||
|
supertraits = Some(traits::supertraits(tcx, 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.
|
||||||
|
let projection_trait_ref = ty::Binder(data.trait_ref.clone());
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => true, // walk contained types, if any
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
error
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Repr<'tcx> for ObjectSafetyViolation<'tcx> {
|
||||||
|
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||||
|
match *self {
|
||||||
|
ObjectSafetyViolation::SizedSelf =>
|
||||||
|
format!("SizedSelf"),
|
||||||
|
ObjectSafetyViolation::Method(ref m, code) =>
|
||||||
|
format!("Method({},{})", m.repr(tcx), code),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -827,6 +827,9 @@ pub struct ctxt<'tcx> {
|
|||||||
/// parameters are never placed into this cache, because their
|
/// parameters are never placed into this cache, because their
|
||||||
/// results are dependent on the parameter environment.
|
/// results are dependent on the parameter environment.
|
||||||
pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
|
pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
|
||||||
|
|
||||||
|
/// Caches whether traits are object safe
|
||||||
|
pub object_safety_cache: RefCell<DefIdMap<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flags that we track on types. These flags are propagated upwards
|
// Flags that we track on types. These flags are propagated upwards
|
||||||
@ -2384,6 +2387,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||||||
repr_hint_cache: RefCell::new(DefIdMap::new()),
|
repr_hint_cache: RefCell::new(DefIdMap::new()),
|
||||||
type_impls_copy_cache: RefCell::new(HashMap::new()),
|
type_impls_copy_cache: RefCell::new(HashMap::new()),
|
||||||
type_impls_sized_cache: RefCell::new(HashMap::new()),
|
type_impls_sized_cache: RefCell::new(HashMap::new()),
|
||||||
|
object_safety_cache: RefCell::new(DefIdMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ impl PpSourceMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PrinterSupport<'ast>: pprust::PpAnn + Sized {
|
trait PrinterSupport<'ast>: pprust::PpAnn {
|
||||||
/// Provides a uniform interface for re-extracting a reference to a
|
/// Provides a uniform interface for re-extracting a reference to a
|
||||||
/// `Session` from a value that now owns it.
|
/// `Session` from a value that now owns it.
|
||||||
fn sess<'a>(&'a self) -> &'a Session;
|
fn sess<'a>(&'a self) -> &'a Session;
|
||||||
@ -154,7 +154,7 @@ trait PrinterSupport<'ast>: pprust::PpAnn + Sized {
|
|||||||
///
|
///
|
||||||
/// (Rust does not yet support upcasting from a trait object to
|
/// (Rust does not yet support upcasting from a trait object to
|
||||||
/// an object for one of its super-traits.)
|
/// an object for one of its super-traits.)
|
||||||
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
|
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NoAnn<'ast> {
|
struct NoAnn<'ast> {
|
||||||
@ -168,6 +168,8 @@ impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
|
|||||||
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
|
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
|
||||||
self.ast_map.as_ref()
|
self.ast_map.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
|
impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
|
||||||
@ -183,6 +185,8 @@ impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
|
|||||||
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
|
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
|
||||||
self.ast_map.as_ref()
|
self.ast_map.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> {
|
impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> {
|
||||||
@ -232,6 +236,8 @@ impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> {
|
|||||||
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
|
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
|
||||||
self.ast_map.as_ref()
|
self.ast_map.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
|
impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
|
||||||
@ -265,6 +271,8 @@ impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> {
|
|||||||
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> {
|
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> {
|
||||||
Some(&self.analysis.ty_cx.map)
|
Some(&self.analysis.ty_cx.map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {
|
impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
use check::{FnCtxt, structurally_resolved_type};
|
use check::{FnCtxt, structurally_resolved_type};
|
||||||
use middle::subst::{FnSpace, SelfSpace};
|
use middle::subst::{FnSpace, SelfSpace};
|
||||||
use middle::traits;
|
use middle::traits::{mod, ObjectSafetyViolation, MethodViolationCode};
|
||||||
use middle::traits::{Obligation, ObligationCause};
|
use middle::traits::{Obligation, ObligationCause};
|
||||||
use middle::traits::report_fulfillment_errors;
|
use middle::traits::report_fulfillment_errors;
|
||||||
use middle::ty::{mod, Ty, AsPredicate};
|
use middle::ty::{mod, Ty, AsPredicate};
|
||||||
@ -133,217 +133,56 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||||||
object_trait: &ty::TyTrait<'tcx>,
|
object_trait: &ty::TyTrait<'tcx>,
|
||||||
span: Span)
|
span: Span)
|
||||||
{
|
{
|
||||||
// Also check that the type `object_trait` specifies all
|
|
||||||
// associated types for all supertraits.
|
|
||||||
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = FnvHashSet::new();
|
|
||||||
|
|
||||||
let object_trait_ref =
|
let object_trait_ref =
|
||||||
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
|
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
|
||||||
for tr in traits::supertraits(tcx, object_trait_ref.clone()) {
|
|
||||||
check_object_safety_inner(tcx, &tr, span);
|
|
||||||
|
|
||||||
let trait_def = ty::lookup_trait_def(tcx, object_trait_ref.def_id());
|
if traits::is_object_safe(tcx, object_trait_ref.clone()) {
|
||||||
for &associated_type_name in trait_def.associated_type_names.iter() {
|
return;
|
||||||
associated_types.insert((object_trait_ref.def_id(), associated_type_name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for projection_bound in object_trait.bounds.projection_bounds.iter() {
|
span_err!(tcx.sess, span, E0038,
|
||||||
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
|
"cannot convert to a trait object because trait `{}` is not object-safe",
|
||||||
projection_bound.0.projection_ty.item_name);
|
ty::item_path_str(tcx, object_trait_ref.def_id()));
|
||||||
associated_types.remove(&pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (trait_def_id, name) in associated_types.into_iter() {
|
let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
|
||||||
tcx.sess.span_err(
|
for violation in violations.into_iter() {
|
||||||
span,
|
match violation {
|
||||||
format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
|
ObjectSafetyViolation::SizedSelf => {
|
||||||
name.user_string(tcx),
|
tcx.sess.span_note(
|
||||||
ty::item_path_str(tcx, trait_def_id)).as_slice());
|
span,
|
||||||
}
|
"the trait cannot require that `Self : Sized`");
|
||||||
}
|
|
||||||
|
|
||||||
fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|
||||||
object_trait: &ty::PolyTraitRef<'tcx>,
|
|
||||||
span: Span) {
|
|
||||||
let trait_items = ty::trait_items(tcx, object_trait.def_id());
|
|
||||||
|
|
||||||
let mut errors = Vec::new();
|
|
||||||
for item in trait_items.iter() {
|
|
||||||
match *item {
|
|
||||||
ty::MethodTraitItem(ref m) => {
|
|
||||||
errors.push(check_object_safety_of_method(tcx, object_trait, &**m))
|
|
||||||
}
|
|
||||||
ty::TypeTraitItem(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
|
|
||||||
if errors.peek().is_some() {
|
|
||||||
let trait_name = ty::item_path_str(tcx, object_trait.def_id());
|
|
||||||
span_err!(tcx.sess, span, E0038,
|
|
||||||
"cannot convert to a trait object because trait `{}` is not object-safe",
|
|
||||||
trait_name);
|
|
||||||
|
|
||||||
for msg in errors {
|
|
||||||
tcx.sess.note(msg[]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a vec of error messages. If the vec is empty - no errors!
|
|
||||||
///
|
|
||||||
/// There are some limitations to calling functions through an object, because (a) the self
|
|
||||||
/// type is not known (that's the whole point of a trait instance, after all, to obscure the
|
|
||||||
/// self type), (b) the call must go through a vtable and hence cannot be monomorphized and
|
|
||||||
/// (c) the trait contains static methods which can't be called because we don't know the
|
|
||||||
/// concrete type.
|
|
||||||
fn check_object_safety_of_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|
||||||
object_trait: &ty::PolyTraitRef<'tcx>,
|
|
||||||
method: &ty::Method<'tcx>)
|
|
||||||
-> Vec<String> {
|
|
||||||
let mut msgs = Vec::new();
|
|
||||||
|
|
||||||
let method_name = method.name.repr(tcx);
|
|
||||||
|
|
||||||
match method.explicit_self {
|
|
||||||
ty::ByValueExplicitSelfCategory => { // reason (a) above
|
|
||||||
msgs.push(format!("cannot call a method (`{}`) with a by-value \
|
|
||||||
receiver through a trait object", method_name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::StaticExplicitSelfCategory => {
|
ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
|
||||||
// Static methods are never object safe (reason (c)).
|
tcx.sess.span_note(
|
||||||
msgs.push(format!("cannot call a static method (`{}`) \
|
span,
|
||||||
through a trait object",
|
format!("method `{}` has a receiver type of `Self`, \
|
||||||
method_name));
|
which cannot be used with a trait object",
|
||||||
return msgs;
|
method.name.user_string(tcx)).as_slice());
|
||||||
}
|
}
|
||||||
ty::ByReferenceExplicitSelfCategory(..) |
|
|
||||||
ty::ByBoxExplicitSelfCategory => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reason (a) above
|
ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
|
||||||
let check_for_self_ty = |&: ty| {
|
tcx.sess.span_note(
|
||||||
if contains_illegal_self_type_reference(tcx, object_trait.def_id(), ty) {
|
span,
|
||||||
Some(format!(
|
format!("method `{}` has no receiver",
|
||||||
"cannot call a method (`{}`) whose type contains \
|
method.name.user_string(tcx)).as_slice());
|
||||||
a self-type (`{}`) through a trait object",
|
|
||||||
method_name, ty.user_string(tcx)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let ref sig = method.fty.sig;
|
ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
|
||||||
for &input_ty in sig.0.inputs[1..].iter() {
|
tcx.sess.span_note(
|
||||||
if let Some(msg) = check_for_self_ty(input_ty) {
|
span,
|
||||||
msgs.push(msg);
|
format!("method `{}` references the `Self` type \
|
||||||
|
in its arguments or return type",
|
||||||
|
method.name.user_string(tcx)).as_slice());
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
|
||||||
|
tcx.sess.span_note(
|
||||||
|
span,
|
||||||
|
format!("method `{}` has generic type parameters",
|
||||||
|
method.name.user_string(tcx)).as_slice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let ty::FnConverging(result_type) = sig.0.output {
|
|
||||||
if let Some(msg) = check_for_self_ty(result_type) {
|
|
||||||
msgs.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if method.generics.has_type_params(FnSpace) {
|
|
||||||
// reason (b) above
|
|
||||||
msgs.push(format!("cannot call a generic method (`{}`) through a trait object",
|
|
||||||
method_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|
||||||
trait_def_id: ast::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(ty, |ty| {
|
|
||||||
match ty.sty {
|
|
||||||
ty::ty_param(ref param_ty) => {
|
|
||||||
if param_ty.space == SelfSpace {
|
|
||||||
error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false // no contained types to walk
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::ty_projection(ref data) => {
|
|
||||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
|
||||||
|
|
||||||
// Compute supertraits of current trait lazilly.
|
|
||||||
if supertraits.is_none() {
|
|
||||||
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
|
||||||
let trait_ref = ty::Binder(trait_def.trait_ref.clone());
|
|
||||||
supertraits = Some(traits::supertraits(tcx, 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.
|
|
||||||
let projection_trait_ref = ty::Binder(data.trait_ref.clone());
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => true, // walk contained types, if any
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,7 +231,7 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
cause.clone());
|
cause.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, create obligations for the projection predicates.
|
// Create obligations for the projection predicates.
|
||||||
let projection_bounds =
|
let projection_bounds =
|
||||||
object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
|
object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
|
||||||
for projection_bound in projection_bounds.iter() {
|
for projection_bound in projection_bounds.iter() {
|
||||||
@ -401,9 +240,47 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||||||
fcx.register_predicate(projection_obligation);
|
fcx.register_predicate(projection_obligation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finally, check that there IS a projection predicate for every associated type.
|
||||||
|
check_object_type_binds_all_associated_types(fcx.tcx(),
|
||||||
|
span,
|
||||||
|
object_trait);
|
||||||
|
|
||||||
object_trait_ref
|
object_trait_ref
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
object_trait: &ty::TyTrait<'tcx>)
|
||||||
|
{
|
||||||
|
let object_trait_ref =
|
||||||
|
object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
|
||||||
|
|
||||||
|
let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> =
|
||||||
|
traits::supertraits(tcx, object_trait_ref.clone())
|
||||||
|
.flat_map(|tr| {
|
||||||
|
let trait_def = ty::lookup_trait_def(tcx, tr.def_id());
|
||||||
|
trait_def.associated_type_names
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.map(move |associated_type_name| (tr.def_id(), associated_type_name))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for projection_bound in object_trait.bounds.projection_bounds.iter() {
|
||||||
|
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
|
||||||
|
projection_bound.0.projection_ty.item_name);
|
||||||
|
associated_types.remove(&pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (trait_def_id, name) in associated_types.into_iter() {
|
||||||
|
tcx.sess.span_err(
|
||||||
|
span,
|
||||||
|
format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
|
||||||
|
name.user_string(tcx),
|
||||||
|
ty::item_path_str(tcx, trait_def_id)).as_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
|
pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
|
||||||
debug!("select_all_fcx_obligations_or_error");
|
debug!("select_all_fcx_obligations_or_error");
|
||||||
|
|
||||||
|
@ -21,6 +21,6 @@ impl Foo for Thing {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut thing = Thing;
|
let mut thing = Thing;
|
||||||
let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object because trait `Foo`
|
let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object
|
||||||
foo(test);
|
foo(test);
|
||||||
}
|
}
|
||||||
|
47
src/test/compile-fail/object-safety-by-value-self.rs
Normal file
47
src/test/compile-fail/object-safety-by-value-self.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// from traits with a `fn(self)` method.
|
||||||
|
|
||||||
|
trait Bar {
|
||||||
|
fn bar(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Baz {
|
||||||
|
fn baz(self: Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE method `bar` has a receiver type of `Self`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t as &Bar
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE method `bar` has a receiver type of `Self`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_baz<T:Baz>(t: &T) -> &Baz {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Baz` is not object-safe
|
||||||
|
//~| NOTE method `baz` has a receiver type of `Self`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
|
||||||
|
t as &Baz
|
||||||
|
//~^ ERROR `Baz` is not object-safe
|
||||||
|
//~| NOTE method `baz` has a receiver type of `Self`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
@ -8,19 +8,24 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// Check that object-safe methods are identified as such.
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// from traits with generic methods.
|
||||||
|
|
||||||
trait Tr {
|
trait Bar {
|
||||||
fn foo(&self);
|
fn bar<T>(&self, t: T);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct St;
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE method `bar` has generic type parameters
|
||||||
|
}
|
||||||
|
|
||||||
impl Tr for St {
|
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
|
||||||
fn foo(&self) {}
|
t as &Bar
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE method `bar` has generic type parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let s: &Tr = &St;
|
|
||||||
s.foo();
|
|
||||||
}
|
}
|
47
src/test/compile-fail/object-safety-mentions-Self.rs
Normal file
47
src/test/compile-fail/object-safety-mentions-Self.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// form traits that make use of `Self` in an argument or return position.
|
||||||
|
|
||||||
|
trait Bar {
|
||||||
|
fn bar(&self, x: &Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Baz {
|
||||||
|
fn bar(&self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE method `bar` references the `Self` type in its arguments or return type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t as &Bar
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE method `bar` references the `Self` type in its arguments or return type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_baz<T:Baz>(t: &T) -> &Baz {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Baz` is not object-safe
|
||||||
|
//~| NOTE method `bar` references the `Self` type in its arguments or return type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
|
||||||
|
t as &Baz
|
||||||
|
//~^ ERROR `Baz` is not object-safe
|
||||||
|
//~| NOTE method `bar` references the `Self` type in its arguments or return type
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
31
src/test/compile-fail/object-safety-no-static.rs
Normal file
31
src/test/compile-fail/object-safety-no-static.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// from traits with static methods.
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
fn foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_implicit<T:Foo+'static>(b: Box<T>) -> Box<Foo+'static> {
|
||||||
|
b
|
||||||
|
//~^ ERROR cannot convert to a trait object
|
||||||
|
//~| NOTE method `foo` has no receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_explicit<T:Foo+'static>(b: Box<T>) -> Box<Foo+'static> {
|
||||||
|
b as Box<Foo>
|
||||||
|
//~^ ERROR cannot convert to a trait object
|
||||||
|
//~| NOTE method `foo` has no receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
33
src/test/compile-fail/object-safety-sized-2.rs
Normal file
33
src/test/compile-fail/object-safety-sized-2.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// from traits where `Self : Sized`.
|
||||||
|
|
||||||
|
trait Bar
|
||||||
|
where Self : Sized
|
||||||
|
{
|
||||||
|
fn bar<T>(&self, t: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE the trait cannot require that `Self : Sized`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t as &Bar
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE the trait cannot require that `Self : Sized`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
31
src/test/compile-fail/object-safety-sized.rs
Normal file
31
src/test/compile-fail/object-safety-sized.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Check that we correctly prevent users from making trait objects
|
||||||
|
// from traits where `Self : Sized`.
|
||||||
|
|
||||||
|
trait Bar : Sized {
|
||||||
|
fn bar<T>(&self, t: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE the trait cannot require that `Self : Sized`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
|
||||||
|
t as &Bar
|
||||||
|
//~^ ERROR `Bar` is not object-safe
|
||||||
|
//~| NOTE the trait cannot require that `Self : Sized`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
trait Foo {
|
|
||||||
fn foo(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Bar {
|
|
||||||
fn bar(&self, x: &Self);
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Baz {
|
|
||||||
fn baz<T>(&self, x: &T);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Foo for int {
|
|
||||||
fn foo(self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Bar for int {
|
|
||||||
fn bar(&self, _x: &int) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Baz for int {
|
|
||||||
fn baz<T>(&self, _x: &T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let _: &Foo = &42i; //~ ERROR cannot convert to a trait object
|
|
||||||
let _: &Bar = &42i; //~ ERROR cannot convert to a trait object
|
|
||||||
let _: &Baz = &42i; //~ ERROR cannot convert to a trait object
|
|
||||||
|
|
||||||
let _ = &42i as &Foo; //~ ERROR cannot convert to a trait object
|
|
||||||
let _ = &42i as &Bar; //~ ERROR cannot convert to a trait object
|
|
||||||
let _ = &42i as &Baz; //~ ERROR cannot convert to a trait object
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
|
|
||||||
trait Foo : Sized {
|
|
||||||
fn foo(self: Box<Self>) { bar(self as Box<Foo>); }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bar(_b: Box<Foo>) { }
|
|
||||||
|
|
||||||
fn main() {}
|
|
Loading…
Reference in New Issue
Block a user