diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 5d84d0c7797ecfe5e20be75223be58fc107e0963..159c2a505d51b89c1b06b062b4b7d6ab70e41872 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -25,7 +25,7 @@ /// A common trait for cloning an object. #[stable] -pub trait Clone { +pub trait Clone : Sized { /// Returns a copy of the value. #[stable] fn clone(&self) -> Self; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index f2439d515b457c284d7d85a7e753f7d691299bb5..13fbf5232f8dc58dc41a0e96bae6ed5d7d2d3f36 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -74,7 +74,26 @@ pub trait Writer { /// /// This method should generally not be invoked manually, but rather through /// the `write!` macro itself. - fn write_fmt(&mut self, args: Arguments) -> Result { write(self, args) } + fn write_fmt(&mut self, args: Arguments) -> Result { + // This Adapter is needed to allow `self` (of type `&mut + // Self`) to be cast to a FormatWriter (below) without + // requiring a `Sized` bound. + struct Adapter<'a,Sized? T:'a>(&'a mut T); + + impl<'a, Sized? T> Writer for Adapter<'a, T> + where T: Writer + { + fn write_str(&mut self, s: &str) -> Result { + self.0.write_str(s) + } + + fn write_fmt(&mut self, args: Arguments) -> Result { + self.0.write_fmt(args) + } + } + + write(&mut Adapter(self), args) + } } /// A struct to represent both where to emit formatting strings to and how they @@ -579,9 +598,6 @@ fn fmt(&self, f: &mut Formatter) -> Result { (**self).fmt(f) } impl<'a, Sized? T: Show> Show for &'a mut T { fn fmt(&self, f: &mut Formatter) -> Result { (**self).fmt(f) } } -impl<'a> Show for &'a (Show+'a) { - fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) } -} impl Show for bool { fn fmt(&self, f: &mut Formatter) -> Result { diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 4a7a681255faa0972c5f141291d491cd45b9d900..53b5c61730041d5427add3d99adba55727ce9461 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -65,6 +65,7 @@ use ops::{Add, Deref, FnMut}; use option::Option; use option::Option::{Some, None}; +use std::kinds::Sized; use uint; #[deprecated = "renamed to Extend"] pub use self::Extend as Extendable; @@ -109,7 +110,7 @@ pub trait Extend { #[unstable = "new convention for extension traits"] /// An extension trait providing numerous methods applicable to all iterators. -pub trait IteratorExt: Iterator { +pub trait IteratorExt: Iterator + Sized { /// Chain this iterator with another, returning a new iterator that will /// finish iterating over the current iterator, and then iterate /// over the other specified iterator. @@ -692,7 +693,7 @@ impl IteratorExt for I where I: Iterator {} /// Extention trait for iterators of pairs. #[unstable = "newly added trait, likely to be merged with IteratorExt"] -pub trait IteratorPairExt: Iterator<(A, B)> { +pub trait IteratorPairExt: Iterator<(A, B)> + Sized { /// Converts an iterator of pairs into a pair of containers. /// /// Loops through the entire iterator, collecting the first component of @@ -738,7 +739,7 @@ pub trait DoubleEndedIterator: Iterator { /// Extension methods for double-ended iterators. #[unstable = "new extension trait convention"] -pub trait DoubleEndedIteratorExt: DoubleEndedIterator { +pub trait DoubleEndedIteratorExt: DoubleEndedIterator + Sized { /// Change the direction of the iterator /// /// The flipped iterator swaps the ends on an iterator that can already diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 0d2ce4f60718f8faba2e1a961c3e0c9cf8dc2fae..d16478dd6cc7ee290f5187dabff5905c3f9de72f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -980,7 +980,7 @@ fn to_f64(&self) -> Option { impl_to_primitive_float_to_float!($T, f64, *se /// A generic trait for converting a number to a value. #[experimental = "trait is likely to be removed"] -pub trait FromPrimitive { +pub trait FromPrimitive : ::kinds::Sized { /// Convert an `int` to return an optional value of this type. If the /// value cannot be represented by this value, the `None` is returned. #[inline] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index faf1d781465c76457b4d08ef731a0cd58fcec2c3..38e47a5ad334e92acd22f83c1ed9b045268103d0 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -92,7 +92,7 @@ use clone::Clone; use intrinsics; use option::Option::{mod, Some, None}; -use kinds::{Send, Sync}; +use kinds::{Send, Sized, Sync}; use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv}; use cmp::Ordering::{mod, Less, Equal, Greater}; @@ -243,7 +243,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Methods on raw pointers #[stable] -pub trait PtrExt { +pub trait PtrExt : Sized { /// Returns the null pointer. #[deprecated = "call ptr::null instead"] fn null() -> Self; diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 568d245911826cbe0a38bdc939515eb007646bf2..bbcd99afdea9331330a1349e565f19964ada79f4 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -52,14 +52,14 @@ mod rand_impls; /// A type that can be randomly generated using an `Rng`. -pub trait Rand { +pub trait Rand : Sized { /// Generates a random instance of this type using the specified source of /// randomness. fn rand(rng: &mut R) -> Self; } /// A random number generator. -pub trait Rng { +pub trait Rng : Sized { /// Return the next random u32. /// /// This rarely needs to be called directly, prefer `r.gen()` to diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index e0bcdfc6d8d9375627b5702d13e4411349553548..ab6f6b601f6d039c4afbee04ec68dd5e0cb5d802 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -57,7 +57,7 @@ use syntax::abi; use syntax::codemap::Span; -pub trait Combine<'tcx> { +pub trait Combine<'tcx> : Sized { fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>; fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx } fn tag(&self) -> String; diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 3c5459ff3bc754cf19a7032e540359978c418d82..97e74b9f6bbb9ecb8987db0c2534da9a5ba10e32 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -519,7 +519,7 @@ fn next(&mut self) -> Option<(ParamSpace, uint, &'a T)> { // `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when // there is more information available (for better errors). -pub trait Subst<'tcx> { +pub trait Subst<'tcx> : Sized { fn subst(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>) -> Self { self.subst_spanned(tcx, substs, None) } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index fc2eb43c8a5ffec84396136837659a89ddc0571e..c83898bcd8ade03d40abe184647606cf88ddef70 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -31,20 +31,27 @@ 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}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::util::elaborate_predicates; +pub use self::util::get_vtable_index_of_object_method; pub use self::util::trait_ref_for_builtin_bound; pub use self::util::supertraits; pub use self::util::Supertraits; pub use self::util::transitive_bounds; +pub use self::util::upcast; mod coherence; mod error_reporting; mod fulfill; mod project; +mod object_safety; mod select; mod util; @@ -212,6 +219,9 @@ pub enum Vtable<'tcx, N> { /// for some type parameter. VtableParam, + /// Virtual calls through an object + VtableObject(VtableObjectData<'tcx>), + /// Successful resolution for a builtin trait. VtableBuiltin(VtableBuiltinData), @@ -247,6 +257,13 @@ pub struct VtableBuiltinData { pub nested: subst::VecPerParamSpace } +/// A vtable for some object-safe trait `Foo` automatically derived +/// for the object type `Foo`. +#[deriving(PartialEq,Eq,Clone)] +pub struct VtableObjectData<'tcx> { + pub object_ty: Ty<'tcx>, +} + /// True if there exist types that satisfy both of the two given impls. pub fn overlapping_impls(infcx: &InferCtxt, impl1_def_id: ast::DefId, @@ -358,6 +375,7 @@ pub fn iter_nested(&self) -> Iter { VtableFnPointer(..) => (&[]).iter(), VtableUnboxedClosure(..) => (&[]).iter(), VtableParam => (&[]).iter(), + VtableObject(_) => (&[]).iter(), VtableBuiltin(ref i) => i.iter_nested(), } } @@ -368,6 +386,7 @@ pub fn map_nested(&self, op: F) -> Vtable<'tcx, M> where F: FnMut(&N) -> M VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()), VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()), VtableParam => VtableParam, + VtableObject(ref p) => VtableObject(p.clone()), VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)), } } @@ -380,6 +399,7 @@ pub fn map_move_nested(self, op: F) -> Vtable<'tcx, M> where VtableFnPointer(sig) => VtableFnPointer(sig), VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s), VtableParam => VtableParam, + VtableObject(p) => VtableObject(p), VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)), } } diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs new file mode 100644 index 0000000000000000000000000000000000000000..6b7bf82af929355c76e38504f6aa9d95ba192b1f --- /dev/null +++ b/src/librustc/middle/traits/object_safety.rs @@ -0,0 +1,301 @@ +// 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 or the MIT license +// , 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>, MethodViolationCode), +} + +/// Reasons a method might not be object-safe. +#[deriving(Copy,Clone,Show)] +pub enum MethodViolationCode { + /// e.g., `fn(self)` + ByValueSelf, + + /// e.g., `fn foo()` + StaticMethod, + + /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self` + ReferencesSelf, + + /// e.g., `fn foo()` + 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> +{ + 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> +{ + // 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 +{ + // The method's first parameter must be something that derefs to + // `&self`. For now, we only accept `&self` and `Box`. + 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(...)`. + 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 // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> ::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> ::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) -> ::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>> = 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 `::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), + } + } +} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index c84f31bf6c3bcad624c7c94a5f1aa1a58dab54b0..0544e32b62c6a7846bf165011c35886a67cdf448 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -377,20 +377,14 @@ fn project_type<'cx,'tcx>( ambiguous: false, }; - assemble_candidates_from_object_type(selcx, - obligation, - &mut candidates); - - if candidates.vec.is_empty() { - assemble_candidates_from_param_env(selcx, - obligation, - &mut candidates); - - if let Err(e) = assemble_candidates_from_impls(selcx, - obligation, - &mut candidates) { - return Err(ProjectionTyError::TraitSelectionError(e)); - } + assemble_candidates_from_param_env(selcx, + obligation, + &mut candidates); + + if let Err(e) = assemble_candidates_from_impls(selcx, + obligation, + &mut candidates) { + return Err(ProjectionTyError::TraitSelectionError(e)); } debug!("{} candidates, ambiguous={}", @@ -467,18 +461,22 @@ fn assemble_candidates_from_predicates<'cx,'tcx>( fn assemble_candidates_from_object_type<'cx,'tcx>( selcx: &mut SelectionContext<'cx,'tcx>, obligation: &ProjectionTyObligation<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>) + candidate_set: &mut ProjectionTyCandidateSet<'tcx>, + object_ty: Ty<'tcx>) { let infcx = selcx.infcx(); - let trait_ref = infcx.resolve_type_vars_if_possible(&obligation.predicate.trait_ref); - debug!("assemble_candidates_from_object_type(trait_ref={})", - trait_ref.repr(infcx.tcx)); - let self_ty = trait_ref.self_ty(); - let data = match self_ty.sty { + debug!("assemble_candidates_from_object_type(object_ty={})", + object_ty.repr(infcx.tcx)); + let data = match object_ty.sty { ty::ty_trait(ref data) => data, - _ => { return; } + _ => { + selcx.tcx().sess.span_bug( + obligation.cause.span, + format!("assemble_candidates_from_object_type called with non-object: {}", + object_ty.repr(selcx.tcx()))[]); + } }; - let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), self_ty); + let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); let env_predicates = projection_bounds.iter() .map(|p| p.as_predicate()) .collect(); @@ -515,6 +513,10 @@ fn assemble_candidates_from_impls<'cx,'tcx>( candidate_set.vec.push( ProjectionTyCandidate::Impl(data)); } + super::VtableObject(data) => { + assemble_candidates_from_object_type( + selcx, obligation, candidate_set, data.object_ty); + } super::VtableParam(..) => { // This case tell us nothing about the value of an // associated type. Consider: diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f9dced088f8c124b7d2ba2daa71576e4ee2cdb82..ca4bf7863be4fe7129965a57f8f389fe681e1d33 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -24,8 +24,10 @@ use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; use super::{SelectionResult}; -use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer}; -use super::{VtableImplData, VtableBuiltinData}; +use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, + VtableFnPointer, VtableObject}; +use super::{VtableImplData, VtableObjectData, VtableBuiltinData}; +use super::object_safety; use super::{util}; use middle::fast_reject; @@ -147,6 +149,8 @@ enum SelectionCandidate<'tcx> { /// types generated for a fn pointer type (e.g., `fn(int)->int`) FnPointerCandidate, + ObjectCandidate, + ErrorCandidate, } @@ -717,6 +721,7 @@ fn assemble_candidates<'o>(&mut self, try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates)); try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates)); try!(self.assemble_candidates_from_impls(obligation, &mut candidates.vec)); + self.assemble_candidates_from_object_ty(obligation, &mut candidates); } } @@ -878,7 +883,7 @@ fn assemble_candidates_from_caller_bounds(&mut self, let matching_bounds = all_bounds.filter( |bound| self.infcx.probe( - |_| self.match_where_clause(obligation, bound.clone())).is_ok()); + |_| self.match_poly_trait_ref(obligation, bound.clone())).is_ok()); let param_candidates = matching_bounds.map(|bound| ParamCandidate(bound)); @@ -945,7 +950,7 @@ fn assemble_fn_pointer_candidates(&mut self, let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); match self_ty.sty { - ty::ty_infer(..) => { + ty::ty_infer(ty::TyVar(_)) => { candidates.ambiguous = true; // could wind up being a fn() type } @@ -991,6 +996,62 @@ fn assemble_candidates_from_impls(&mut self, Ok(()) } + /// Search for impls that might apply to `obligation`. + fn assemble_candidates_from_object_ty(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + { + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + + debug!("assemble_candidates_from_object_ty(self_ty={})", + self_ty.repr(self.tcx())); + + // Object-safety candidates are only applicable to object-safe + // traits. Including this check is useful because it helps + // inference in cases of traits like `BorrowFrom`, which are + // not object-safe, and which rely on being able to infer the + // self-type from one of the other inputs. Without this check, + // these cases wind up being considered ambiguous due to a + // (spurious) ambiguity introduced here. + if !object_safety::is_object_safe(self.tcx(), obligation.predicate.to_poly_trait_ref()) { + return; + } + + let poly_trait_ref = match self_ty.sty { + ty::ty_trait(ref data) => { + data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) + } + ty::ty_infer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type + return; + } + _ => { + return; + } + }; + + debug!("assemble_candidates_from_object_ty: poly_trait_ref={}", + poly_trait_ref.repr(self.tcx())); + + // see whether the object trait can be upcast to the trait we are looking for + let obligation_def_id = obligation.predicate.def_id(); + let upcast_trait_ref = match util::upcast(self.tcx(), poly_trait_ref, obligation_def_id) { + Some(r) => r, + None => { return; } + }; + + debug!("assemble_candidates_from_object_ty: upcast_trait_ref={}", + upcast_trait_ref.repr(self.tcx())); + + // check whether the upcast version of the trait-ref matches what we are looking for + if let Ok(()) = self.infcx.probe(|_| self.match_poly_trait_ref(obligation, + upcast_trait_ref.clone())) { + debug!("assemble_candidates_from_object_ty: matched, pushing candidate"); + candidates.vec.push(ObjectCandidate); + } + } + /////////////////////////////////////////////////////////////////////////// // WINNOW // @@ -1544,6 +1605,11 @@ fn confirm_candidate(&mut self, Ok(VtableUnboxedClosure(closure_def_id, substs)) } + ObjectCandidate => { + let data = self.confirm_object_candidate(obligation); + Ok(VtableObject(data)) + } + FnPointerCandidate => { let fn_type = try!(self.confirm_fn_pointer_candidate(obligation)); @@ -1727,6 +1793,48 @@ fn vtable_impl(&mut self, nested: impl_predicates } } + fn confirm_object_candidate(&mut self, + obligation: &TraitObligation<'tcx>) + -> VtableObjectData<'tcx> + { + debug!("confirm_object_candidate({})", + obligation.repr(self.tcx())); + + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + let poly_trait_ref = match self_ty.sty { + ty::ty_trait(ref data) => { + data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) + } + _ => { + self.tcx().sess.span_bug(obligation.cause.span, + "object candidate with non-object"); + } + }; + + let obligation_def_id = obligation.predicate.def_id(); + let upcast_trait_ref = match util::upcast(self.tcx(), + poly_trait_ref.clone(), + obligation_def_id) { + Some(r) => r, + None => { + self.tcx().sess.span_bug(obligation.cause.span, + format!("unable to upcast from {} to {}", + poly_trait_ref.repr(self.tcx()), + obligation_def_id.repr(self.tcx())).as_slice()); + } + }; + + match self.match_poly_trait_ref(obligation, upcast_trait_ref) { + Ok(()) => { } + Err(()) => { + self.tcx().sess.span_bug(obligation.cause.span, + "failed to match trait refs"); + } + } + + VtableObjectData { object_ty: self_ty } + } + fn confirm_fn_pointer_candidate(&mut self, obligation: &TraitObligation<'tcx>) -> Result,SelectionError<'tcx>> @@ -1962,12 +2070,12 @@ fn fast_reject_trait_refs(&mut self, }) } - fn match_where_clause(&mut self, - obligation: &TraitObligation<'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result<(),()> + fn match_poly_trait_ref(&mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>) + -> Result<(),()> { - debug!("match_where_clause: obligation={} where_clause_trait_ref={}", + debug!("match_poly_trait_ref: obligation={} where_clause_trait_ref={}", obligation.repr(self.tcx()), where_clause_trait_ref.repr(self.tcx())); @@ -2161,6 +2269,9 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), ProjectionCandidate => format!("ProjectionCandidate"), FnPointerCandidate => format!("FnPointerCandidate"), + ObjectCandidate => { + format!("ObjectCandidate") + } UnboxedClosureCandidate(c, ref s) => { format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx)) } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 109810fc7eec3efacb5bea0a141b1087fafe8544..41a59d6a5d84679b63d9a3c056bb9463a457bb87 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -238,6 +238,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } +impl<'tcx> fmt::Show for super::VtableObjectData<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableObject(...)") + } +} + /// See `super::obligations_for_generics` pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>, cause: ObligationCause<'tcx>, @@ -291,6 +297,58 @@ pub fn predicate_for_builtin_bound<'tcx>( }) } +/// Cast a trait reference into a reference to one of its super +/// traits; returns `None` if `target_trait_def_id` is not a +/// supertrait. +pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>, + source_trait_ref: ty::PolyTraitRef<'tcx>, + target_trait_def_id: ast::DefId) + -> Option> +{ + if source_trait_ref.def_id() == target_trait_def_id { + return Some(source_trait_ref); // shorcut the most common case + } + + for super_trait_ref in supertraits(tcx, source_trait_ref) { + if super_trait_ref.def_id() == target_trait_def_id { + return Some(super_trait_ref); + } + } + + None +} + +/// Given an object of type `object_trait_ref`, returns the index of +/// the method `n_method` found in the trait `trait_def_id` (which +/// should be a supertrait of `object_trait_ref`) within the vtable +/// for `object_trait_ref`. +pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>, + object_trait_ref: ty::PolyTraitRef<'tcx>, + trait_def_id: ast::DefId, + method_index_in_trait: uint) -> uint { + // We need to figure the "real index" of the method in a + // listing of all the methods of an object. We do this by + // iterating down the supertraits of the object's trait until + // we find the trait the method came from, counting up the + // methods from them. + let mut method_count = 0; + ty::each_bound_trait_and_supertraits(tcx, &[object_trait_ref], |bound_ref| { + if bound_ref.def_id() == trait_def_id { + false + } else { + let trait_items = ty::trait_items(tcx, bound_ref.def_id()); + for trait_item in trait_items.iter() { + match *trait_item { + ty::MethodTraitItem(_) => method_count += 1, + ty::TypeTraitItem(_) => {} + } + } + true + } + }); + method_count + method_index_in_trait +} + impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("Obligation(predicate={},depth={})", @@ -314,6 +372,10 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("VtableFnPointer({})", d.repr(tcx)), + super::VtableObject(ref d) => + format!("VtableObject({})", + d.repr(tcx)), + super::VtableParam => format!("VtableParam"), @@ -339,6 +401,13 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { } } +impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> { + fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { + format!("VtableObject(object_ty={})", + self.object_ty.repr(tcx)) + } +} + impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 26a9cc5464e9549ff7bc6450a34b8d63c8535d5e..0a03a8e836b9221d73dc2475a484bf81af3baa60 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -828,6 +828,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,bool>>, + + /// Caches whether traits are object safe + pub object_safety_cache: RefCell>, } // Flags that we track on types. These flags are propagated upwards @@ -2385,6 +2388,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()), } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 83d2f6fb0e6d58909000c0c6171ea414a8f648f9..abbf530529bb2fd41959cb259c4dc90e5a04db15 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -56,7 +56,7 @@ pub trait TypeFoldable<'tcx> { /// default implementation that does an "identity" fold. Within each /// identity fold, it should invoke `foo.fold_with(self)` to fold each /// sub-item. -pub trait TypeFolder<'tcx> { +pub trait TypeFolder<'tcx> : Sized { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>; /// Invoked by the `super_*` routines when we enter a region @@ -503,6 +503,15 @@ fn fold_with>(&self, folder: &mut F) -> traits::Vtable<'tcx, } traits::VtableParam => traits::VtableParam, traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)), + traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { + fn fold_with>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> { + traits::VtableObjectData { + object_ty: self.object_ty.fold_with(folder) } } } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 773ea30d401fc361fdcb422017fd119983609875..a046d9d5d39c5e5323fc2c4e5fbfc6383173f269 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -154,7 +154,7 @@ trait PrinterSupport<'ast>: pprust::PpAnn { /// /// (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 @@ fn sess<'a>(&'a self) -> &'a Session { &self.sess } 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 @@ fn sess<'a>(&'a self) -> &'a Session { &self.sess } 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 @@ fn sess<'a>(&'a self) -> &'a Session { &self.sess } 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 @@ fn sess<'a>(&'a self) -> &'a Session { &self.analysis.ty_cx.sess } 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> { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 9535ffaec0e6a182b9b925387ac4ac4dd68bccc9..99624f1b1e7d8197a36e4a12e91a161a35c9c621 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +use arena::TypedArena; use back::abi; -use llvm; -use llvm::ValueRef; +use back::link; +use llvm::{mod, ValueRef, get_param}; use metadata::csearch; -use middle::subst::{Substs}; +use middle::subst::{Subst, Substs}; use middle::subst::VecPerParamSpace; use middle::subst; use middle::traits; @@ -370,6 +370,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty); Callee { bcx: bcx, data: Fn(llfn) } } + traits::VtableObject(ref data) => { + let llfn = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method); + Callee { bcx: bcx, data: Fn(llfn) } + } traits::VtableBuiltin(..) | traits::VtableParam(..) => { bcx.sess().bug( @@ -503,6 +507,137 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; } +/// Generate a shim function that allows an object type like `SomeTrait` to +/// implement the type `SomeTrait`. Imagine a trait definition: +/// +/// trait SomeTrait { fn get(&self) -> int; ... } +/// +/// And a generic bit of code: +/// +/// fn foo(t: &T) { +/// let x = SomeTrait::get; +/// x(t) +/// } +/// +/// What is the value of `x` when `foo` is invoked with `T=SomeTrait`? +/// The answer is that it it is a shim function generate by this +/// routine: +/// +/// fn shim(t: &SomeTrait) -> int { +/// // ... call t.get() virtually ... +/// } +/// +/// In fact, all virtual calls can be thought of as normal trait calls +/// that go through this shim function. +pub fn trans_object_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + object_ty: Ty<'tcx>, + trait_id: ast::DefId, + method_offset_in_trait: uint) + -> ValueRef +{ + let _icx = push_ctxt("trans_object_shim"); + let tcx = ccx.tcx(); + + debug!("trans_object_shim(object_ty={}, trait_id={}, n_method={})", + object_ty.repr(tcx), + trait_id.repr(tcx), + method_offset_in_trait); + + let object_trait_ref = + match object_ty.sty { + ty::ty_trait(ref data) => { + data.principal_trait_ref_with_self_ty(tcx, object_ty) + } + _ => { + tcx.sess.bug(format!("trans_object_shim() called on non-object: {}", + object_ty.repr(tcx)).as_slice()); + } + }; + + // Upcast to the trait in question and extract out the substitutions. + let upcast_trait_ref = traits::upcast(ccx.tcx(), object_trait_ref.clone(), trait_id).unwrap(); + let object_substs = upcast_trait_ref.substs().clone().erase_regions(); + debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx)); + + // Lookup the type of this method as deeclared in the trait and apply substitutions. + let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) { + ty::MethodTraitItem(method) => method, + ty::TypeTraitItem(_) => { + tcx.sess.bug("can't create a method shim for an associated type") + } + }; + let fty = method_ty.fty.subst(tcx, &object_substs); + let fty = tcx.mk_bare_fn(fty); + debug!("trans_object_shim: fty={}", fty.repr(tcx)); + + // + let method_bare_fn_ty = + ty::mk_bare_fn(tcx, None, fty); + let function_name = + link::mangle_internal_name_by_type_and_seq(ccx, method_bare_fn_ty, "object_shim"); + let llfn = + decl_internal_rust_fn(ccx, method_bare_fn_ty, function_name.as_slice()); + + // + let block_arena = TypedArena::new(); + let empty_substs = Substs::trans_empty(); + let fcx = new_fn_ctxt(ccx, + llfn, + ast::DUMMY_NODE_ID, + false, + fty.sig.0.output, + &empty_substs, + None, + &block_arena); + let mut bcx = init_function(&fcx, false, fty.sig.0.output); + + // the first argument (`self`) will be a trait object + let llobject = get_param(fcx.llfn, fcx.arg_pos(0) as u32); + + debug!("trans_object_shim: llobject={}", + bcx.val_to_string(llobject)); + + // the remaining arguments will be, well, whatever they are + let llargs: Vec<_> = + fty.sig.0.inputs[1..].iter() + .enumerate() + .map(|(i, _)| { + let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32); + debug!("trans_object_shim: input #{} == {}", + i, bcx.val_to_string(llarg)); + llarg + }) + .collect(); + assert!(!fcx.needs_ret_allocas); + + let dest = + fcx.llretslotptr.get().map( + |_| expr::SaveIn(fcx.get_ret_slot(bcx, fty.sig.0.output, "ret_slot"))); + + let method_offset_in_vtable = + traits::get_vtable_index_of_object_method(bcx.tcx(), + object_trait_ref.clone(), + trait_id, + method_offset_in_trait); + debug!("trans_object_shim: method_offset_in_vtable={}", + method_offset_in_vtable); + + bcx = trans_call_inner(bcx, + None, + method_bare_fn_ty, + |bcx, _| trans_trait_callee_from_llval(bcx, + method_bare_fn_ty, + method_offset_in_vtable, + llobject), + ArgVals(llargs.as_slice()), + dest).bcx; + + finish_fn(&fcx, bcx, fty.sig.0.output); + + llfn +} + /// Creates a returns a dynamic vtable for the given type and vtable origin. /// This is used only for objects. /// @@ -560,6 +695,14 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llfn = vec![trans_fn_pointer_shim(bcx.ccx(), bare_fn_ty)]; llfn.into_iter() } + traits::VtableObject(ref data) => { + // this would imply that the Self type being erased is + // an object type; this cannot happen because we + // cannot cast an unsized type into a trait object + bcx.sess().bug( + format!("cannot get vtable for an object type: {}", + data.repr(bcx.tcx())).as_slice()); + } traits::VtableParam => { bcx.sess().bug( format!("resolved vtable for {} to bad vtable {} in trans", diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a751b65a0f8c58233cacd91266082958ded4b931..ee859bbe8f52da9d88d5bec1cad4f9113df6f9dc 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -633,17 +633,16 @@ fn upcast(&mut self, target_trait_def_id: ast::DefId) -> ty::PolyTraitRef<'tcx> { - for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) { - if super_trait_ref.def_id() == target_trait_def_id { - return super_trait_ref; + match traits::upcast(self.tcx(), source_trait_ref.clone(), target_trait_def_id) { + Some(super_trait_ref) => super_trait_ref, + None => { + self.tcx().sess.span_bug( + self.span, + format!("cannot upcast `{}` to `{}`", + source_trait_ref.repr(self.tcx()), + target_trait_def_id.repr(self.tcx()))[]); } } - - self.tcx().sess.span_bug( - self.span, - format!("cannot upcast `{}` to `{}`", - source_trait_ref.repr(self.tcx()), - target_trait_def_id.repr(self.tcx()))[]); } fn replace_late_bound_regions_with_fresh_var(&self, value: &ty::Binder) -> T diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index b8920ffde589525289b14dc1df58d696d38155fb..52860abb6f938acbfd7e0be106e7774625bd1139 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -310,7 +310,10 @@ fn assemble_inherent_candidates_from_object(&mut self, let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty); self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| { let vtable_index = - get_method_index(tcx, &new_trait_ref, trait_ref.clone(), method_num); + traits::get_vtable_index_of_object_method(tcx, + trait_ref.clone(), + new_trait_ref.def_id(), + method_num); let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs()); @@ -999,35 +1002,6 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>, .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m))) } -// Determine the index of a method in the list of all methods belonging -// to a trait and its supertraits. -fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>, - subtrait: ty::PolyTraitRef<'tcx>, - n_method: uint) -> uint { - // We need to figure the "real index" of the method in a - // listing of all the methods of an object. We do this by - // iterating down the supertraits of the object's trait until - // we find the trait the method came from, counting up the - // methods from them. - let mut method_count = n_method; - ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| { - if bound_ref.def_id() == trait_ref.def_id() { - false - } else { - let trait_items = ty::trait_items(tcx, bound_ref.def_id()); - for trait_item in trait_items.iter() { - match *trait_item { - ty::MethodTraitItem(_) => method_count += 1, - ty::TypeTraitItem(_) => {} - } - } - true - } - }); - method_count -} - impl<'tcx> Candidate<'tcx> { fn to_unadjusted_pick(&self) -> Pick<'tcx> { Pick { diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index c85b542b6caeee105a456303eb4b94fa140839ee..1ef6c1140321846dc53f24970f355a5f0c57af51 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -9,8 +9,7 @@ // except according to those terms. 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 +132,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)); - } - } - 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); + if traits::is_object_safe(tcx, object_trait_ref.clone()) { + return; } - 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)) + 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())); + + 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::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 { - 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)) + 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::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::StaticMethod) => { + tcx.sess.span_note( + span, + format!("method `{}` has no receiver", + 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 - } - }; - 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); - } - } - if let ty::FnConverging(result_type) = sig.0.output { - if let Some(msg) = check_for_self_ty(result_type) { - 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()); } - } - - 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 // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> ::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> ::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) -> ::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>> = 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 `::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 + ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { + tcx.sess.span_note( + span, + format!("method `{}` has generic type parameters", + method.name.user_string(tcx)).as_slice()); } - }); - - error + } } } @@ -392,7 +230,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 +239,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"); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 9e184db3b84fec1ea943f578c037ae3e24f0d5fc..fe61b3de2cf6f0c5253620ed5521236c7466b87f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -843,6 +843,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let bounds = compute_bounds(ccx, self_param_ty.to_ty(ccx.tcx), bounds.as_slice(), + SizedByDefault::No, it.span); let associated_type_names: Vec<_> = @@ -1098,6 +1099,7 @@ fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let bounds = compute_bounds(ccx, assoc_ty, assoc_type_def.bounds.as_slice(), + SizedByDefault::Yes, assoc_type_def.span); ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter() @@ -1306,6 +1308,7 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, let bounds = compute_bounds(this, param_ty.to_ty(this.tcx()), param.bounds[], + SizedByDefault::Yes, param.span); let default = match param.default { None => None, @@ -1342,29 +1345,35 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, def } +enum SizedByDefault { Yes, No } + /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the /// built-in trait (formerly known as kind): Send. fn compute_bounds<'tcx,AC>(this: &AC, param_ty: ty::Ty<'tcx>, ast_bounds: &[ast::TyParamBound], + sized_by_default: SizedByDefault, span: Span) -> ty::ParamBounds<'tcx> - where AC: AstConv<'tcx> { + where AC: AstConv<'tcx> +{ let mut param_bounds = conv_param_bounds(this, span, param_ty, ast_bounds); - add_unsized_bound(this, - &mut param_bounds.builtin_bounds, - ast_bounds, - span); + if let SizedByDefault::Yes = sized_by_default { + add_unsized_bound(this, + &mut param_bounds.builtin_bounds, + ast_bounds, + span); - check_bounds_compatible(this.tcx(), - param_ty, - ¶m_bounds, - span); + check_bounds_compatible(this.tcx(), + param_ty, + ¶m_bounds, + span); + } param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 5623c0f0e535fb880b704cde3d6aeb8c91b9e12a..4f277cc868a1a04873ed3abbcbc2a04e57e689ae 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -12,7 +12,7 @@ use std::iter::Extend; use std::mem::{replace, swap}; -pub trait DocFolder { +pub trait DocFolder : Sized { fn fold_item(&mut self, item: Item) -> Option { self.fold_item_recur(item) } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 539fcb23bb05d0ba1721dc026f2e9a28552113bd..8f7de1c4dca8cab65c32a5e1169d03906bf9f591 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -232,6 +232,7 @@ use fmt; use int; use iter::{Iterator, IteratorExt}; +use kinds::Sized; use mem::transmute; use ops::FnOnce; use option::Option; @@ -1030,11 +1031,25 @@ fn flush(&mut self) -> IoResult<()> { Ok(()) } fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> { // Create a shim which translates a Writer to a fmt::Writer and saves // off I/O errors. instead of discarding them - struct Adaptor<'a, T:'a> { + struct Adaptor<'a, Sized? T:'a> { inner: &'a mut T, error: IoResult<()>, } + #[cfg(not(stage0))] + impl<'a, Sized? T: Writer> fmt::Writer for Adaptor<'a, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + #[cfg(stage0)] impl<'a, T: Writer> fmt::Writer for Adaptor<'a, T> { fn write_str(&mut self, s: &str) -> fmt::Result { match self.inner.write(s.as_bytes()) { @@ -1629,16 +1644,24 @@ fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { /// `Some`. The `Some` contains the `IoResult` representing whether the /// connection attempt was successful. A successful connection will be wrapped /// in `Ok`. A failed connection is represented as an `Err`. -pub struct IncomingConnections<'a, A:'a> { +pub struct IncomingConnections<'a, Sized? A:'a> { inc: &'a mut A, } +#[cfg(stage0)] impl<'a, T, A: Acceptor> Iterator> for IncomingConnections<'a, A> { fn next(&mut self) -> Option> { Some(self.inc.accept()) } } +#[cfg(not(stage0))] +impl<'a, T, Sized? A: Acceptor> Iterator> for IncomingConnections<'a, A> { + fn next(&mut self) -> Option> { + Some(self.inc.accept()) + } +} + /// Creates a standard error for a commonly used flavor of error. The `detail` /// field of the returned error will always be `None`. /// diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index c134b11a0eb9933ef6555f894c2bdb9c5addfab5..3d3068f6868c6a3c5c850a542e8a2445e5f55f1b 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -53,7 +53,7 @@ fn move_map(self, f: F) -> OwnedSlice where F: FnMut(T) -> T { } } -pub trait Folder { +pub trait Folder : Sized { // Any additions to this trait should happen in form // of a call to a public `noop_*` function that only calls // out to the folder again, not other `noop_*` functions. diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index e532c76347fa38332babce22698a9a0955fbdd27..a1fe63e3f6fcd27af7d9fb981c0f5d2bd7432f8e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -54,8 +54,7 @@ pub enum FnKind<'a> { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) -pub trait Visitor<'v> { - +pub trait Visitor<'v> : Sized { fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } diff --git a/src/test/auxiliary/method_self_arg2.rs b/src/test/auxiliary/method_self_arg2.rs index e1e79b59e3e443926edf30c942edb2560e7a03bb..eb4d62b01ad1a07189e9ef766b199ae1f156e1eb 100644 --- a/src/test/auxiliary/method_self_arg2.rs +++ b/src/test/auxiliary/method_self_arg2.rs @@ -32,7 +32,7 @@ pub fn run_trait(self) { } } -pub trait Bar { +pub trait Bar : Sized { fn foo1(&self); fn foo2(self); fn foo3(self: Box); diff --git a/src/test/compile-fail/dst-sized-trait-param.rs b/src/test/compile-fail/dst-sized-trait-param.rs index 750b475adb2bb847ef48e81234b3b669f01d4fa2..ea5becbf229c0e0aca0c1602e6e953783ac0b467 100644 --- a/src/test/compile-fail/dst-sized-trait-param.rs +++ b/src/test/compile-fail/dst-sized-trait-param.rs @@ -12,7 +12,7 @@ // parameter, the corresponding value must be sized. Also that the // self type must be sized if appropriate. -trait Foo { fn take(self, x: &T) { } } // Note: T is sized +trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized impl Foo<[int]> for uint { } //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `[int]` diff --git a/src/test/compile-fail/issue-18959.rs b/src/test/compile-fail/issue-18959.rs index 3d126790335a87f08d8c956c0d9efbc1c27dff2e..1a792eb6e76aedacc37ded3d389835d73f060221 100644 --- a/src/test/compile-fail/issue-18959.rs +++ b/src/test/compile-fail/issue-18959.rs @@ -21,6 +21,6 @@ fn foo(&self, _: &T) {} 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); } diff --git a/src/test/compile-fail/issue-5543.rs b/src/test/compile-fail/issue-5543.rs index bbd41b28f03616a83da48c484031df58d3ff64de..f970cdb1b8304c6b797ae3f3333ea231d9331470 100644 --- a/src/test/compile-fail/issue-5543.rs +++ b/src/test/compile-fail/issue-5543.rs @@ -15,5 +15,4 @@ fn main() { let r: Box = box 5; let _m: Box = r as Box; //~^ ERROR `core::kinds::Sized` is not implemented for the type `Foo` - //~| ERROR `Foo` is not implemented for the type `Foo` } diff --git a/src/test/compile-fail/object-safety-by-value-self.rs b/src/test/compile-fail/object-safety-by-value-self.rs new file mode 100644 index 0000000000000000000000000000000000000000..5ebcc8516ca0516610c34ab2d470b2674c8c7136 --- /dev/null +++ b/src/test/compile-fail/object-safety-by-value-self.rs @@ -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 or the MIT license +// , 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: &T) -> &Bar { + t + //~^ ERROR `Bar` is not object-safe + //~| NOTE method `bar` has a receiver type of `Self` +} + +fn make_bar_explicit(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: &T) -> &Baz { + t + //~^ ERROR `Baz` is not object-safe + //~| NOTE method `baz` has a receiver type of `Self` +} + +fn make_baz_explicit(t: &T) -> &Baz { + t as &Baz + //~^ ERROR `Baz` is not object-safe + //~| NOTE method `baz` has a receiver type of `Self` +} + +fn main() { +} diff --git a/src/test/run-pass/issue-7320.rs b/src/test/compile-fail/object-safety-generics.rs similarity index 50% rename from src/test/run-pass/issue-7320.rs rename to src/test/compile-fail/object-safety-generics.rs index c7087f8e3a8ca5982663b681e72850ff75d27f26..0ca706404c1f309028b36775d7d3d16daa237841 100644 --- a/src/test/run-pass/issue-7320.rs +++ b/src/test/compile-fail/object-safety-generics.rs @@ -8,11 +8,24 @@ // 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 generic methods. -trait Foo { - fn foo(self: Box) { bar(self as Box); } +trait Bar { + fn bar(&self, t: T); } -fn bar(_b: Box) { } +fn make_bar(t: &T) -> &Bar { + t + //~^ ERROR `Bar` is not object-safe + //~| NOTE method `bar` has generic type parameters +} + +fn make_bar_explicit(t: &T) -> &Bar { + t as &Bar + //~^ ERROR `Bar` is not object-safe + //~| NOTE method `bar` has generic type parameters +} -fn main() {} +fn main() { +} diff --git a/src/test/compile-fail/object-safety-mentions-Self.rs b/src/test/compile-fail/object-safety-mentions-Self.rs new file mode 100644 index 0000000000000000000000000000000000000000..df0f44c1391580898084e7484bf3d06e75686225 --- /dev/null +++ b/src/test/compile-fail/object-safety-mentions-Self.rs @@ -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 or the MIT license +// , 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: &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: &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: &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: &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() { +} diff --git a/src/test/compile-fail/object-safety-no-static.rs b/src/test/compile-fail/object-safety-no-static.rs new file mode 100644 index 0000000000000000000000000000000000000000..6a010d49692d26450a4d95225eb3695c4509b0cd --- /dev/null +++ b/src/test/compile-fail/object-safety-no-static.rs @@ -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 or the MIT license +// , 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(b: Box) -> Box { + b + //~^ ERROR cannot convert to a trait object + //~| NOTE method `foo` has no receiver +} + +fn foo_explicit(b: Box) -> Box { + b as Box + //~^ ERROR cannot convert to a trait object + //~| NOTE method `foo` has no receiver +} + +fn main() { +} diff --git a/src/test/compile-fail/object-safety-sized-2.rs b/src/test/compile-fail/object-safety-sized-2.rs new file mode 100644 index 0000000000000000000000000000000000000000..3a02461bbb223c177d43599f8d74abf380e1cb01 --- /dev/null +++ b/src/test/compile-fail/object-safety-sized-2.rs @@ -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 or the MIT license +// , 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(&self, t: T); +} + +fn make_bar(t: &T) -> &Bar { + t + //~^ ERROR `Bar` is not object-safe + //~| NOTE the trait cannot require that `Self : Sized` +} + +fn make_bar_explicit(t: &T) -> &Bar { + t as &Bar + //~^ ERROR `Bar` is not object-safe + //~| NOTE the trait cannot require that `Self : Sized` +} + +fn main() { +} diff --git a/src/test/compile-fail/object-safety-sized.rs b/src/test/compile-fail/object-safety-sized.rs new file mode 100644 index 0000000000000000000000000000000000000000..bc214f6f3d9623ca30c1fcc8257b5cb68143c810 --- /dev/null +++ b/src/test/compile-fail/object-safety-sized.rs @@ -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 or the MIT license +// , 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(&self, t: T); +} + +fn make_bar(t: &T) -> &Bar { + t + //~^ ERROR `Bar` is not object-safe + //~| NOTE the trait cannot require that `Self : Sized` +} + +fn make_bar_explicit(t: &T) -> &Bar { + t as &Bar + //~^ ERROR `Bar` is not object-safe + //~| NOTE the trait cannot require that `Self : Sized` +} + +fn main() { +} diff --git a/src/test/compile-fail/regions-infer-bound-from-trait-self.rs b/src/test/compile-fail/regions-infer-bound-from-trait-self.rs index 25fd20b6ec5654428494206c10ff02e09aa71a13..aeb003ca5d091047daa90fbc0e7bb007c9bfb46a 100644 --- a/src/test/compile-fail/regions-infer-bound-from-trait-self.rs +++ b/src/test/compile-fail/regions-infer-bound-from-trait-self.rs @@ -23,12 +23,12 @@ fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } // In these case, `Self` inherits `'static`. -trait InheritsFromStatic : 'static { +trait InheritsFromStatic : Sized + 'static { fn foo1<'a>(self, x: Inv<'a>) { check_bound(x, self) } } -trait InheritsFromStaticIndirectly : Static { +trait InheritsFromStaticIndirectly : Sized + Static { fn foo1<'a>(self, x: Inv<'a>) { check_bound(x, self) } @@ -37,13 +37,13 @@ fn foo1<'a>(self, x: Inv<'a>) { // In these case, `Self` inherits `'a`. -trait InheritsFromIs<'a> : 'a { +trait InheritsFromIs<'a> : Sized + 'a { fn foo(self, x: Inv<'a>) { check_bound(x, self) } } -trait InheritsFromIsIndirectly<'a> : Is<'a> { +trait InheritsFromIsIndirectly<'a> : Sized + Is<'a> { fn foo(self, x: Inv<'a>) { check_bound(x, self) } @@ -51,7 +51,7 @@ fn foo(self, x: Inv<'a>) { // In this case, `Self` inherits nothing. -trait InheritsFromNothing<'a> { +trait InheritsFromNothing<'a> : Sized { fn foo(self, x: Inv<'a>) { check_bound(x, self) //~^ ERROR parameter type `Self` may not live long enough diff --git a/src/test/compile-fail/trait-matching-lifetimes.rs b/src/test/compile-fail/trait-matching-lifetimes.rs index f1b30166b5e31231b0a9ee2da8b5bb9ccb6d89c2..333730e0c4b802c62bf7d3a341a2f6ea17594cfe 100644 --- a/src/test/compile-fail/trait-matching-lifetimes.rs +++ b/src/test/compile-fail/trait-matching-lifetimes.rs @@ -16,7 +16,7 @@ struct Foo<'a,'b> { y: &'b int, } -trait Tr { +trait Tr : Sized { fn foo(x: Self) {} } diff --git a/src/test/compile-fail/trait-objects.rs b/src/test/compile-fail/trait-objects.rs deleted file mode 100644 index 88b907a5cb965538e59ece6e7977b932861b1016..0000000000000000000000000000000000000000 --- a/src/test/compile-fail/trait-objects.rs +++ /dev/null @@ -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 or the MIT license -// , 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(&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(&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 -} diff --git a/src/test/compile-fail/trait-safety-fn-body.rs b/src/test/compile-fail/trait-safety-fn-body.rs index d174092e4d0ac898312f7e7ab12473db9422df31..f894e2ee28e2f9327fa8ae8eb3ec522d99bd3f46 100644 --- a/src/test/compile-fail/trait-safety-fn-body.rs +++ b/src/test/compile-fail/trait-safety-fn-body.rs @@ -11,7 +11,7 @@ // Check that an unsafe impl does not imply that unsafe actions are // legal in the methods. -unsafe trait UnsafeTrait { +unsafe trait UnsafeTrait : Sized { fn foo(self) { } } diff --git a/src/test/compile-fail/type-params-in-different-spaces-2.rs b/src/test/compile-fail/type-params-in-different-spaces-2.rs index 9be64bf534679722fda892ec2665cb4217dbd2b3..3a4cc9e874e7d2d0f91da799ebfb9f2d4cc570dd 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-2.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-2.rs @@ -11,7 +11,7 @@ // Test static calls to make sure that we align the Self and input // type parameters on a trait correctly. -trait Tr { +trait Tr : Sized { fn op(T) -> Self; } diff --git a/src/test/compile-fail/type-params-in-different-spaces-3.rs b/src/test/compile-fail/type-params-in-different-spaces-3.rs index a3d69d53ba9c0b7e3bbbcb51b4da327597395d8b..c113e1b7815212a6f39bd9433095aee0d77c91c8 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-3.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-3.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Tr { +trait Tr : Sized { fn test(u: X) -> Self { u //~ ERROR mismatched types } diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs index 0537fc1f94ad77dfaef5aa2fa7389501da7773e0..f9ece8e6843db8756d0c6cbd4a80d4d28d229577 100644 --- a/src/test/compile-fail/unsized4.rs +++ b/src/test/compile-fail/unsized4.rs @@ -10,8 +10,7 @@ // Test that bounds are sized-compatible. -trait T {} - +trait T : Sized {} fn f() { //~^ERROR incompatible bounds on `Y`, bound `T` does not allow unsized type } diff --git a/src/test/debuginfo/issue7712.rs b/src/test/debuginfo/issue7712.rs index 948048ec2727db281a4225ec9326357a07d691b2..94458a7fb4bccbce7c95a7d20f8d1fb78dc27502 100644 --- a/src/test/debuginfo/issue7712.rs +++ b/src/test/debuginfo/issue7712.rs @@ -11,7 +11,7 @@ // compile-flags:--debuginfo=1 // min-lldb-version: 310 -pub trait TraitWithDefaultMethod { +pub trait TraitWithDefaultMethod : Sized { fn method(self) { () } diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index f8ef5b3d2fcf9411cfe493eaccd8c5172cf40c19..87884d2f95629b41ae0afa6ea0451e2fcf9bff01 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -118,7 +118,7 @@ struct Struct { x: int } -trait Trait { +trait Trait : Sized { fn self_by_ref(&self, arg1: int, arg2: int) -> int { zzz(); // #break arg1 + arg2 diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index c2594df7d351c1da129e3e56bccad819dbbd2819..62b5e6872ee4986d567b0525a21a185210262507 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -118,7 +118,7 @@ struct Struct { x: int } -trait Trait { +trait Trait : Sized { fn self_by_ref(&self, arg1: int, arg2: T) -> int { zzz(); // #break diff --git a/src/test/run-pass/associated-types-impl-redirect.rs b/src/test/run-pass/associated-types-impl-redirect.rs index a28cf34633684565ab299b732baea4b8a7ae6d76..ce7f5dde2ad194e355052db804eef23f90ccde09 100644 --- a/src/test/run-pass/associated-types-impl-redirect.rs +++ b/src/test/run-pass/associated-types-impl-redirect.rs @@ -19,6 +19,7 @@ #![feature(associated_types, lang_items, unboxed_closures)] #![no_implicit_prelude] +use std::kinds::Sized; use std::option::Option::{None, Some, mod}; trait Iterator { @@ -27,7 +28,7 @@ trait Iterator { fn next(&mut self) -> Option; } -trait IteratorExt: Iterator { +trait IteratorExt: Iterator + Sized { fn by_ref(&mut self) -> ByRef { ByRef(self) } diff --git a/src/test/run-pass/associated-types-projection-bound-in-supertraits.rs b/src/test/run-pass/associated-types-projection-bound-in-supertraits.rs index 83686d92a7cd9e16ba330a298a2d6a33d618efe4..92daee5225d01729edcd8fc88f28e658fa65f47c 100644 --- a/src/test/run-pass/associated-types-projection-bound-in-supertraits.rs +++ b/src/test/run-pass/associated-types-projection-bound-in-supertraits.rs @@ -21,7 +21,7 @@ trait Not { fn not(self) -> Self::Result; } -trait Int: Not { +trait Int: Not + Sized { fn count_ones(self) -> uint; fn count_zeros(self) -> uint { // neither works diff --git a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs index 062d37556ec29c9370b687934484b77e31d2d68d..7afaf290424af80ee490be278535a62b3eecf59d 100644 --- a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs +++ b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs @@ -19,6 +19,7 @@ #![feature(associated_types, lang_items, unboxed_closures)] #![no_implicit_prelude] +use std::kinds::Sized; use std::option::Option::{None, Some, mod}; trait Iterator { @@ -27,7 +28,7 @@ trait Iterator { fn next(&mut self) -> Option; } -trait IteratorExt: Iterator { +trait IteratorExt: Iterator + Sized { fn by_ref(&mut self) -> ByRef { ByRef(self) } diff --git a/src/test/run-pass/bug-7183-generics.rs b/src/test/run-pass/bug-7183-generics.rs index 8c4d10a2d598cf1b5a656af78821b73da861bc97..bf8d303f34174941d2281a97bb9f5abafd77a654 100644 --- a/src/test/run-pass/bug-7183-generics.rs +++ b/src/test/run-pass/bug-7183-generics.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Speak { +trait Speak : Sized { fn say(&self, s:&str) -> String; fn hi(&self) -> String { hello(self) } } diff --git a/src/test/run-pass/builtin-superkinds-self-type.rs b/src/test/run-pass/builtin-superkinds-self-type.rs index bf06bf8b8c65ae7f39b99322c795860066506e97..d0db2542ccc60593c19bce89d0386bc5ff12c327 100644 --- a/src/test/run-pass/builtin-superkinds-self-type.rs +++ b/src/test/run-pass/builtin-superkinds-self-type.rs @@ -13,7 +13,7 @@ use std::sync::mpsc::{Sender, channel}; -trait Foo : Send { +trait Foo : Send + Sized { fn foo(self, tx: Sender) { tx.send(self).unwrap(); } diff --git a/src/test/run-pass/default-method-supertrait-vtable.rs b/src/test/run-pass/default-method-supertrait-vtable.rs index 1b2b17f99171bc6731ca5f56b00e23fd5a5d5ee0..727cada21fa66549304cf788e1fbed9b4c3841d5 100644 --- a/src/test/run-pass/default-method-supertrait-vtable.rs +++ b/src/test/run-pass/default-method-supertrait-vtable.rs @@ -21,7 +21,7 @@ trait Y { } -trait Z: Y { +trait Z: Y + Sized { fn x(self) -> int { require_y(self) } diff --git a/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs b/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs index aaf2ecb71292eb768b170910600935ce00130bf1..3238c24163e17578ae572e570ae4ad02a3e779b6 100644 --- a/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs +++ b/src/test/run-pass/issue-8171-default-method-self-inherit-builtin-trait.rs @@ -16,7 +16,7 @@ fn require_send(_: T){} -trait TragicallySelfIsNotSend: Send { +trait TragicallySelfIsNotSend: Send + Sized { fn x(self) { require_send(self); } diff --git a/src/test/run-pass/method-self-arg-trait.rs b/src/test/run-pass/method-self-arg-trait.rs index 36dfe83a9ebae13080e0eaebbc2b7f7da3da59e1..29d100beb064f7c2161b9f69f59c2a044fb6e3b2 100644 --- a/src/test/run-pass/method-self-arg-trait.rs +++ b/src/test/run-pass/method-self-arg-trait.rs @@ -16,7 +16,7 @@ impl Copy for Foo {} -trait Bar { +trait Bar : Sized { fn foo1(&self); fn foo2(self); fn foo3(self: Box); diff --git a/src/test/run-pass/self-in-mut-slot-default-method.rs b/src/test/run-pass/self-in-mut-slot-default-method.rs index b4a46f34015a2455e78c0a27b74ff7e08d9550ea..bced8012b683245de468dd792897230d304dffa8 100644 --- a/src/test/run-pass/self-in-mut-slot-default-method.rs +++ b/src/test/run-pass/self-in-mut-slot-default-method.rs @@ -13,7 +13,7 @@ struct X { a: int } -trait Changer { +trait Changer : Sized { fn change(mut self) -> Self { self.set_to(55); self diff --git a/src/test/run-pass/trait-object-safety.rs b/src/test/run-pass/unboxed-closures-call-sugar-object.rs similarity index 56% rename from src/test/run-pass/trait-object-safety.rs rename to src/test/run-pass/unboxed-closures-call-sugar-object.rs index ed7284a8353651d26c1bf2fc09bbe3ae662e73b7..2dec53cc13afb8a216a3474f49c81e3b6646a6f3 100644 --- a/src/test/run-pass/trait-object-safety.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,19 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that object-safe methods are identified as such. +#![feature(unboxed_closures)] -trait Tr { - fn foo(&self); -} - -struct St; +use std::ops::FnMut; -impl Tr for St { - fn foo(&self) {} +fn make_adder(x: int) -> Boxint + 'static> { + box move |y| { x + y } } -fn main() { - let s: &Tr = &St; - s.foo(); +pub fn main() { + let mut adder = make_adder(3); + let z = (*adder)(2); + println!("{}", z); + assert_eq!(z, 5); } +