diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs
index 5d84d0c7797ec..159c2a505d51b 100644
--- a/src/libcore/clone.rs
+++ b/src/libcore/clone.rs
@@ -25,7 +25,7 @@ use kinds::Sized;
/// 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 87fcb12e29f9c..c0f8eb59fce86 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -74,7 +74,26 @@ pub trait FormatWriter {
///
/// 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> FormatWriter for Adapter<'a, T>
+ where T: FormatWriter
+ {
+ fn write(&mut self, bytes: &[u8]) -> Result {
+ self.0.write(bytes)
+ }
+
+ 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
@@ -586,9 +605,6 @@ impl<'a, Sized? T: Show> Show for &'a T {
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 7c53503b1ceb7..229777f684311 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -65,6 +65,7 @@ use num::{ToPrimitive, Int};
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 0d2ce4f60718f..d16478dd6cc7e 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -980,7 +980,7 @@ impl_to_primitive_float! { f64 }
/// 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 faf1d781465c7..38e47a5ad334e 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -92,7 +92,7 @@ use mem;
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 568d245911826..bbcd99afdea93 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -52,14 +52,14 @@ pub mod reseeding;
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 e0bcdfc6d8d93..ab6f6b601f6d0 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -57,7 +57,7 @@ use syntax::ast;
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 3c5459ff3bc75..97e74b9f6bbb9 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -519,7 +519,7 @@ impl<'a,T> Iterator<(ParamSpace, uint, &'a T)> for EnumeratedItems<'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 b10dfa5b71813..41028292da8f7 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -29,20 +29,27 @@ 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};
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;
@@ -210,6 +217,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),
@@ -245,6 +255,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 neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl
/// of a trait, not an inherent impl.
pub fn is_orphan_impl(tcx: &ty::ctxt,
@@ -365,6 +382,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
VtableFnPointer(..) => (&[]).iter(),
VtableUnboxedClosure(..) => (&[]).iter(),
VtableParam => (&[]).iter(),
+ VtableObject(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
}
}
@@ -375,6 +393,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
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)),
}
}
@@ -387,6 +406,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
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 0000000000000..6b7bf82af9293
--- /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 c84f31bf6c3bc..0544e32b62c6a 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 f9dced088f8c1..ca4bf7863be4f 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -24,8 +24,10 @@ use super::{ObligationCauseCode, BuiltinDerivedObligation};
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
})
}
- 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 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
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 109810fc7eec3..41a59d6a5d846 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -238,6 +238,12 @@ impl<'tcx, N> fmt::Show for VtableImplData<'tcx, N> {
}
}
+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 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
format!("VtableFnPointer({})",
d.repr(tcx)),
+ super::VtableObject(ref d) =>
+ format!("VtableObject({})",
+ d.repr(tcx)),
+
super::VtableParam =>
format!("VtableParam"),
@@ -339,6 +401,13 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData {
}
}
+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 7bc5d3d070894..89a2f94aa0442 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -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,bool>>,
+
+ /// Caches whether traits are object safe
+ pub object_safety_cache: RefCell>,
}
// 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()),
}
}
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 83d2f6fb0e6d5..abbf530529bb2 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 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
}
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 773ea30d401fc..a046d9d5d39c5 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 @@ 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> {
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 9535ffaec0e6a..99624f1b1e7d8 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 a751b65a0f8c5..ee859bbe8f52d 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -633,17 +633,16 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
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 f00e3e2d4527a..257d11cc84a5e 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -308,7 +308,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
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());
@@ -996,35 +999,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 c85b542b6caee..1ef6c11403218 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 9e184db3b84fe..fe61b3de2cf6f 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 ty_generics_for_trait<'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 5623c0f0e535f..4f277cc868a1a 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -12,7 +12,7 @@ use clean::*;
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 e8b852ee492b9..cc8a67249d4cf 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -232,6 +232,7 @@ use error::{FromError, Error};
use fmt;
use int;
use iter::{Iterator, IteratorExt};
+use kinds::Sized;
use mem::transmute;
use ops::{BitOr, BitXor, BitAnd, Sub, Not, FnOnce};
use option::Option;
@@ -1030,11 +1031,25 @@ pub trait Writer {
fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> {
// Create a shim which translates a Writer to a FormatWriter 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::FormatWriter for Adaptor<'a, T> {
+ fn write(&mut self, bytes: &[u8]) -> fmt::Result {
+ match self.inner.write(bytes) {
+ Ok(()) => Ok(()),
+ Err(e) => {
+ self.error = Err(e);
+ Err(fmt::Error)
+ }
+ }
+ }
+ }
+
+ #[cfg(stage0)]
impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
fn write(&mut self, bytes: &[u8]) -> fmt::Result {
match self.inner.write(bytes) {
@@ -1629,16 +1644,24 @@ pub trait Acceptor {
/// `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 4f0169e31f229..5234837a456c8 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -53,7 +53,7 @@ impl MoveMap for OwnedSlice {
}
}
-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 40ca6354ca6d1..0b4a1fbdd2294 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 e1e79b59e3e44..eb4d62b01ad1a 100644
--- a/src/test/auxiliary/method_self_arg2.rs
+++ b/src/test/auxiliary/method_self_arg2.rs
@@ -32,7 +32,7 @@ impl Foo {
}
}
-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 750b475adb2bb..ea5becbf229c0 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 3d126790335a8..1a792eb6e76ae 100644
--- a/src/test/compile-fail/issue-18959.rs
+++ b/src/test/compile-fail/issue-18959.rs
@@ -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);
}
diff --git a/src/test/compile-fail/issue-5543.rs b/src/test/compile-fail/issue-5543.rs
index bbd41b28f0361..f970cdb1b8304 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 0000000000000..5ebcc8516ca05
--- /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 c7087f8e3a8ca..0ca706404c1f3 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 0000000000000..df0f44c139158
--- /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 0000000000000..6a010d49692d2
--- /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 0000000000000..3a02461bbb223
--- /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 0000000000000..bc214f6f3d962
--- /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 25fd20b6ec565..aeb003ca5d091 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 @@ trait InheritsFromStaticIndirectly : Static {
// 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 @@ trait InheritsFromIsIndirectly<'a> : Is<'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 f1b30166b5e31..333730e0c4b80 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 88b907a5cb965..0000000000000
--- 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 d174092e4d0ac..f894e2ee28e2f 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 9be64bf534679..3a4cc9e874e7d 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 a3d69d53ba9c0..c113e1b781521 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 0537fc1f94ad7..f9ece8e6843db 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 948048ec2727d..94458a7fb4bcc 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 f8ef5b3d2fcf9..87884d2f95629 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 c2594df7d351c..62b5e6872ee49 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 a28cf34633684..ce7f5dde2ad19 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 83686d92a7cd9..92daee5225d01 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 062d37556ec29..7afaf290424af 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 8c4d10a2d598c..bf8d303f34174 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 1c156f6551c8d..ab775132dde44 100644
--- a/src/test/run-pass/builtin-superkinds-self-type.rs
+++ b/src/test/run-pass/builtin-superkinds-self-type.rs
@@ -11,7 +11,7 @@
// Tests the ability for the Self type in default methods to use
// capabilities granted by builtin kinds as supertraits.
-trait Foo : Send {
+trait Foo : Send + Sized {
fn foo(self, tx: Sender) {
tx.send(self);
}
diff --git a/src/test/run-pass/default-method-supertrait-vtable.rs b/src/test/run-pass/default-method-supertrait-vtable.rs
index 1b2b17f99171b..727cada21fa66 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 aaf2ecb71292e..3238c24163e17 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 36dfe83a9ebae..29d100beb064f 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 @@ struct Foo;
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 b4a46f34015a2..bced8012b6832 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 ed7284a835365..2dec53cc13afb 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);
}
+