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:
Niko Matsakis 2014-12-15 21:11:09 -05:00
parent 2c1d7a7caa
commit 19dcecb225
14 changed files with 601 additions and 272 deletions

View File

@ -29,6 +29,10 @@ pub use self::fulfill::{FulfillmentContext, RegionObligation};
pub use self::project::MismatchedProjectionTypes;
pub use self::project::normalize;
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::SelectionCache;
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
@ -45,6 +49,7 @@ mod coherence;
mod error_reporting;
mod fulfill;
mod project;
mod object_safety;
mod select;
mod util;

View 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),
}
}
}

View File

@ -827,6 +827,9 @@ pub struct ctxt<'tcx> {
/// parameters are never placed into this cache, because their
/// results are dependent on the parameter environment.
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
@ -2384,6 +2387,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
repr_hint_cache: RefCell::new(DefIdMap::new()),
type_impls_copy_cache: RefCell::new(HashMap::new()),
type_impls_sized_cache: RefCell::new(HashMap::new()),
object_safety_cache: RefCell::new(DefIdMap::new()),
}
}

View File

@ -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
/// `Session` from a value that now owns it.
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
/// 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> {
@ -168,6 +168,8 @@ impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'ast>> {
self.ast_map.as_ref()
}
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
}
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>> {
self.ast_map.as_ref()
}
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
}
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>> {
self.ast_map.as_ref()
}
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
}
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>> {
Some(&self.analysis.ty_cx.map)
}
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
}
impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {

View File

@ -10,7 +10,7 @@
use check::{FnCtxt, structurally_resolved_type};
use middle::subst::{FnSpace, SelfSpace};
use middle::traits;
use middle::traits::{mod, ObjectSafetyViolation, MethodViolationCode};
use middle::traits::{Obligation, ObligationCause};
use middle::traits::report_fulfillment_errors;
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>,
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 =
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());
for &associated_type_name in trait_def.associated_type_names.iter() {
associated_types.insert((object_trait_ref.def_id(), associated_type_name));
}
if traits::is_object_safe(tcx, object_trait_ref.clone()) {
return;
}
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);
}
span_err!(tcx.sess, span, E0038,
"cannot convert to a trait object because trait `{}` is not object-safe",
ty::item_path_str(tcx, object_trait_ref.def_id()));
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());
}
}
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))
let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
for violation in violations.into_iter() {
match violation {
ObjectSafetyViolation::SizedSelf => {
tcx.sess.span_note(
span,
"the trait cannot require that `Self : Sized`");
}
ty::StaticExplicitSelfCategory => {
// Static methods are never object safe (reason (c)).
msgs.push(format!("cannot call a static method (`{}`) \
through a trait object",
method_name));
return msgs;
ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
tcx.sess.span_note(
span,
format!("method `{}` has a receiver type of `Self`, \
which cannot be used with a trait object",
method.name.user_string(tcx)).as_slice());
}
ty::ByReferenceExplicitSelfCategory(..) |
ty::ByBoxExplicitSelfCategory => {}
}
// reason (a) above
let check_for_self_ty = |&: ty| {
if contains_illegal_self_type_reference(tcx, object_trait.def_id(), ty) {
Some(format!(
"cannot call a method (`{}`) whose type contains \
a self-type (`{}`) through a trait object",
method_name, ty.user_string(tcx)))
} else {
None
ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
tcx.sess.span_note(
span,
format!("method `{}` has no receiver",
method.name.user_string(tcx)).as_slice());
}
};
let ref sig = method.fty.sig;
for &input_ty in sig.0.inputs[1..].iter() {
if let Some(msg) = check_for_self_ty(input_ty) {
msgs.push(msg);
ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
tcx.sess.span_note(
span,
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());
}
// Finally, create obligations for the projection predicates.
// Create obligations for the projection predicates.
let projection_bounds =
object_trait.projection_bounds_with_self_ty(fcx.tcx(), referent_ty);
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);
}
// 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
}
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) {
debug!("select_all_fcx_obligations_or_error");

View File

@ -21,6 +21,6 @@ impl Foo for Thing {
fn main() {
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);
}

View 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() {
}

View File

@ -8,19 +8,24 @@
// option. This file may not be copied, modified, or distributed
// 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 {
fn foo(&self);
trait Bar {
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 foo(&self) {}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
t as &Bar
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` has generic type parameters
}
fn main() {
let s: &Tr = &St;
s.foo();
}

View 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() {
}

View 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() {
}

View 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() {
}

View 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() {
}

View File

@ -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
}

View File

@ -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() {}