rollup merge of #20341: nikomatsakis/impl-trait-for-trait-2

Conflicts:
	src/librustc/middle/traits/mod.rs
	src/libstd/io/mod.rs
	src/test/run-pass/builtin-superkinds-self-type.rs
This commit is contained in:
Alex Crichton 2015-01-02 10:58:10 -08:00
commit 4459b1dced
55 changed files with 1114 additions and 392 deletions

View File

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

View File

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

View File

@ -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<A> {
#[unstable = "new convention for extension traits"]
/// An extension trait providing numerous methods applicable to all iterators.
pub trait IteratorExt<A>: Iterator<A> {
pub trait IteratorExt<A>: Iterator<A> + 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<A, I> IteratorExt<A> for I where I: Iterator<A> {}
/// Extention trait for iterators of pairs.
#[unstable = "newly added trait, likely to be merged with IteratorExt"]
pub trait IteratorPairExt<A, B>: Iterator<(A, B)> {
pub trait IteratorPairExt<A, B>: 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<A>: Iterator<A> {
/// Extension methods for double-ended iterators.
#[unstable = "new extension trait convention"]
pub trait DoubleEndedIteratorExt<A>: DoubleEndedIterator<A> {
pub trait DoubleEndedIteratorExt<A>: DoubleEndedIterator<A> + Sized {
/// Change the direction of the iterator
///
/// The flipped iterator swaps the ends on an iterator that can already

View File

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

View File

@ -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<T>(dst: *mut T, src: T) {
/// Methods on raw pointers
#[stable]
pub trait PtrExt<T> {
pub trait PtrExt<T> : Sized {
/// Returns the null pointer.
#[deprecated = "call ptr::null instead"]
fn null() -> Self;

View File

@ -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<R: Rng>(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

View File

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

View File

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

View File

@ -31,20 +31,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;
@ -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<N>),
@ -247,6 +257,13 @@ pub struct VtableBuiltinData<N> {
pub nested: subst::VecPerParamSpace<N>
}
/// 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 @@ impl<'tcx, N> Vtable<'tcx, N> {
VtableFnPointer(..) => (&[]).iter(),
VtableUnboxedClosure(..) => (&[]).iter(),
VtableParam => (&[]).iter(),
VtableObject(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
}
}
@ -368,6 +386,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)),
}
}
@ -380,6 +399,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)),
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! "Object safety" refers to the ability for a trait to be converted
//! to an object. In general, traits may only be converted to an
//! object if all of their methods meet certain criteria. In particular,
//! they must:
//!
//! - have a suitable receiver from which we can extract a vtable;
//! - not reference the erased type `Self` except for in this receiver;
//! - not have generic type parameters
use super::supertraits;
use super::elaborate_predicates;
use middle::subst::{mod, SelfSpace};
use middle::traits;
use middle::ty::{mod, Ty};
use std::rc::Rc;
use syntax::ast;
use util::ppaux::Repr;
pub enum ObjectSafetyViolation<'tcx> {
/// Self : Sized declared on the trait
SizedSelf,
/// Method has someting illegal
Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
}
/// Reasons a method might not be object-safe.
#[deriving(Copy,Clone,Show)]
pub enum MethodViolationCode {
/// 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<A>()`
Generic,
}
pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
-> bool
{
// Because we query yes/no results frequently, we keep a cache:
let cached_result =
tcx.object_safety_cache.borrow().get(&trait_ref.def_id()).map(|&r| r);
let result =
cached_result.unwrap_or_else(|| {
let result = object_safety_violations(tcx, trait_ref.clone()).is_empty();
// Record just a yes/no result in the cache; this is what is
// queried most frequently. Note that this may overwrite a
// previous result, but always with the same thing.
tcx.object_safety_cache.borrow_mut().insert(trait_ref.def_id(), result);
result
});
debug!("is_object_safe({}) = {}", trait_ref.repr(tcx), result);
result
}
pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
sub_trait_ref: ty::PolyTraitRef<'tcx>)
-> Vec<ObjectSafetyViolation<'tcx>>
{
supertraits(tcx, sub_trait_ref)
.flat_map(|tr| object_safety_violations_for_trait(tcx, tr.def_id()).into_iter())
.collect()
}
fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
{
// Check methods for violations.
let mut violations: Vec<_> =
ty::trait_items(tcx, trait_def_id).iter()
.flat_map(|item| {
match *item {
ty::MethodTraitItem(ref m) => {
object_safety_violations_for_method(tcx, trait_def_id, &**m)
.map(|code| ObjectSafetyViolation::Method(m.clone(), code))
.into_iter()
}
ty::TypeTraitItem(_) => {
None.into_iter()
}
}
})
.collect();
// Check the trait itself.
if trait_has_sized_self(tcx, trait_def_id) {
violations.push(ObjectSafetyViolation::SizedSelf);
}
debug!("object_safety_violations_for_trait(trait_def_id={}) = {}",
trait_def_id.repr(tcx),
violations.repr(tcx));
violations
}
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId)
-> bool
{
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
let param_env = ty::construct_parameter_environment(tcx,
&trait_def.generics,
ast::DUMMY_NODE_ID);
let predicates = param_env.caller_bounds.predicates.as_slice().to_vec();
let sized_def_id = match tcx.lang_items.sized_trait() {
Some(def_id) => def_id,
None => { return false; /* No Sized trait, can't require it! */ }
};
// Search for a predicate like `Self : Sized` amongst the trait bounds.
elaborate_predicates(tcx, predicates)
.any(|predicate| {
match predicate {
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
let self_ty = trait_pred.0.self_ty();
match self_ty.sty {
ty::ty_param(ref data) => data.space == subst::SelfSpace,
_ => false,
}
}
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
ty::Predicate::Equate(..) |
ty::Predicate::RegionOutlives(..) |
ty::Predicate::TypeOutlives(..) => {
false
}
}
})
}
fn object_safety_violations_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId,
method: &ty::Method<'tcx>)
-> Option<MethodViolationCode>
{
// The method's first parameter must be something that derefs to
// `&self`. For now, we only accept `&self` and `Box<Self>`.
match method.explicit_self {
ty::ByValueExplicitSelfCategory => {
return Some(MethodViolationCode::ByValueSelf);
}
ty::StaticExplicitSelfCategory => {
return Some(MethodViolationCode::StaticMethod);
}
ty::ByReferenceExplicitSelfCategory(..) |
ty::ByBoxExplicitSelfCategory => {
}
}
// The `Self` type is erased, so it should not appear in list of
// arguments or return type apart from the receiver.
let ref sig = method.fty.sig;
for &input_ty in sig.0.inputs[1..].iter() {
if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
}
}
if let ty::FnConverging(result_type) = sig.0.output {
if contains_illegal_self_type_reference(tcx, trait_def_id, result_type) {
return Some(MethodViolationCode::ReferencesSelf);
}
}
// We can't monomorphize things like `fn foo<A>(...)`.
if !method.generics.types.is_empty_in(subst::FnSpace) {
return Some(MethodViolationCode::Generic);
}
None
}
fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId,
ty: Ty<'tcx>)
-> bool
{
// This is somewhat subtle. In general, we want to forbid
// references to `Self` in the argument and return types,
// since the value of `Self` is erased. However, there is one
// exception: it is ok to reference `Self` in order to access
// an associated type of the current trait, since we retain
// the value of those associated types in the object type
// itself.
//
// ```rust
// trait SuperTrait {
// type X;
// }
//
// trait Trait : SuperTrait {
// type Y;
// fn foo(&self, x: Self) // bad
// fn foo(&self) -> Self // bad
// fn foo(&self) -> Option<Self> // bad
// fn foo(&self) -> Self::Y // OK, desugars to next example
// fn foo(&self) -> <Self as Trait>::Y // OK
// fn foo(&self) -> Self::X // OK, desugars to next example
// fn foo(&self) -> <Self as SuperTrait>::X // OK
// }
// ```
//
// However, it is not as simple as allowing `Self` in a projected
// type, because there are illegal ways to use `Self` as well:
//
// ```rust
// trait Trait : SuperTrait {
// ...
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
// }
// ```
//
// Here we will not have the type of `X` recorded in the
// object type, and we cannot resolve `Self as SomeOtherTrait`
// without knowing what `Self` is.
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
let mut error = false;
ty::maybe_walk_ty(ty, |ty| {
match ty.sty {
ty::ty_param(ref param_ty) => {
if param_ty.space == SelfSpace {
error = true;
}
false // no contained types to walk
}
ty::ty_projection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazilly.
if supertraits.is_none() {
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
let trait_ref = ty::Binder(trait_def.trait_ref.clone());
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let projection_trait_ref = ty::Binder(data.trait_ref.clone());
let is_supertrait_of_current_trait =
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
if is_supertrait_of_current_trait {
false // do not walk contained types, do not report error, do collect $200
} else {
true // DO walk contained types, POSSIBLY reporting an error
}
}
_ => true, // walk contained types, if any
}
});
error
}
impl<'tcx> Repr<'tcx> for ObjectSafetyViolation<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
ObjectSafetyViolation::SizedSelf =>
format!("SizedSelf"),
ObjectSafetyViolation::Method(ref m, code) =>
format!("Method({},{})", m.repr(tcx), code),
}
}
}

View File

@ -377,20 +377,14 @@ fn project_type<'cx,'tcx>(
ambiguous: false,
};
assemble_candidates_from_object_type(selcx,
obligation,
&mut candidates);
assemble_candidates_from_param_env(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));
}
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:

View File

@ -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<ty::Ty<'tcx>,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))
}

View File

@ -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<ty::PolyTraitRef<'tcx>>
{
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<N> {
}
}
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 {

View File

@ -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<HashMap<Ty<'tcx>,bool>>,
/// Caches whether traits are object safe
pub object_safety_cache: RefCell<DefIdMap<bool>>,
}
// Flags that we track on types. These flags are propagated upwards
@ -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()),
}
}

View File

@ -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<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableObjectData<'tcx> {
traits::VtableObjectData {
object_ty: self.object_ty.fold_with(folder)
}
}
}

View File

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

View File

@ -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:SomeTrait>(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",

View File

@ -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<T>(&self, value: &ty::Binder<T>) -> T

View File

@ -310,7 +310,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());
@ -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 {

View File

@ -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));
}
if traits::is_object_safe(tcx, object_trait_ref.clone()) {
return;
}
for projection_bound in object_trait.bounds.projection_bounds.iter() {
let pair = (projection_bound.0.projection_ty.trait_ref.def_id,
projection_bound.0.projection_ty.item_name);
associated_types.remove(&pair);
}
span_err!(tcx.sess, span, E0038,
"cannot convert to a trait object because trait `{}` is not object-safe",
ty::item_path_str(tcx, object_trait_ref.def_id()));
for (trait_def_id, name) in associated_types.into_iter() {
tcx.sess.span_err(
span,
format!("the value of the associated type `{}` (from the trait `{}`) must be specified",
name.user_string(tcx),
ty::item_path_str(tcx, trait_def_id)).as_slice());
}
}
fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
object_trait: &ty::PolyTraitRef<'tcx>,
span: Span) {
let trait_items = ty::trait_items(tcx, object_trait.def_id());
let mut errors = Vec::new();
for item in trait_items.iter() {
match *item {
ty::MethodTraitItem(ref m) => {
errors.push(check_object_safety_of_method(tcx, object_trait, &**m))
}
ty::TypeTraitItem(_) => {}
}
}
let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
if errors.peek().is_some() {
let trait_name = ty::item_path_str(tcx, object_trait.def_id());
span_err!(tcx.sess, span, E0038,
"cannot convert to a trait object because trait `{}` is not object-safe",
trait_name);
for msg in errors {
tcx.sess.note(msg[]);
}
}
/// Returns a vec of error messages. If the vec is empty - no errors!
///
/// There are some limitations to calling functions through an object, because (a) the self
/// type is not known (that's the whole point of a trait instance, after all, to obscure the
/// self type), (b) the call must go through a vtable and hence cannot be monomorphized and
/// (c) the trait contains static methods which can't be called because we don't know the
/// concrete type.
fn check_object_safety_of_method<'tcx>(tcx: &ty::ctxt<'tcx>,
object_trait: &ty::PolyTraitRef<'tcx>,
method: &ty::Method<'tcx>)
-> Vec<String> {
let mut msgs = Vec::new();
let method_name = method.name.repr(tcx);
match method.explicit_self {
ty::ByValueExplicitSelfCategory => { // reason (a) above
msgs.push(format!("cannot call a method (`{}`) with a by-value \
receiver through a trait object", method_name))
let violations = traits::object_safety_violations(tcx, object_trait_ref.clone());
for violation in violations.into_iter() {
match violation {
ObjectSafetyViolation::SizedSelf => {
tcx.sess.span_note(
span,
"the trait cannot require that `Self : Sized`");
}
ty::StaticExplicitSelfCategory => {
// Static methods are never object safe (reason (c)).
msgs.push(format!("cannot call a static method (`{}`) \
through a trait object",
method_name));
return msgs;
ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
tcx.sess.span_note(
span,
format!("method `{}` has a receiver type of `Self`, \
which cannot be used with a trait object",
method.name.user_string(tcx)).as_slice());
}
ty::ByReferenceExplicitSelfCategory(..) |
ty::ByBoxExplicitSelfCategory => {}
}
// reason (a) above
let check_for_self_ty = |&: ty| {
if contains_illegal_self_type_reference(tcx, object_trait.def_id(), ty) {
Some(format!(
"cannot call a method (`{}`) whose type contains \
a self-type (`{}`) through a trait object",
method_name, ty.user_string(tcx)))
} else {
None
ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
tcx.sess.span_note(
span,
format!("method `{}` has no receiver",
method.name.user_string(tcx)).as_slice());
}
};
let ref sig = method.fty.sig;
for &input_ty in sig.0.inputs[1..].iter() {
if let Some(msg) = check_for_self_ty(input_ty) {
msgs.push(msg);
ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => {
tcx.sess.span_note(
span,
format!("method `{}` references the `Self` type \
in its arguments or return type",
method.name.user_string(tcx)).as_slice());
}
ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => {
tcx.sess.span_note(
span,
format!("method `{}` has generic type parameters",
method.name.user_string(tcx)).as_slice());
}
}
if let ty::FnConverging(result_type) = sig.0.output {
if let Some(msg) = check_for_self_ty(result_type) {
msgs.push(msg);
}
}
if method.generics.has_type_params(FnSpace) {
// reason (b) above
msgs.push(format!("cannot call a generic method (`{}`) through a trait object",
method_name));
}
msgs
}
fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId,
ty: Ty<'tcx>)
-> bool
{
// This is somewhat subtle. In general, we want to forbid
// references to `Self` in the argument and return types,
// since the value of `Self` is erased. However, there is one
// exception: it is ok to reference `Self` in order to access
// an associated type of the current trait, since we retain
// the value of those associated types in the object type
// itself.
//
// ```rust
// trait SuperTrait {
// type X;
// }
//
// trait Trait : SuperTrait {
// type Y;
// fn foo(&self, x: Self) // bad
// fn foo(&self) -> Self // bad
// fn foo(&self) -> Option<Self> // bad
// fn foo(&self) -> Self::Y // OK, desugars to next example
// fn foo(&self) -> <Self as Trait>::Y // OK
// fn foo(&self) -> Self::X // OK, desugars to next example
// fn foo(&self) -> <Self as SuperTrait>::X // OK
// }
// ```
//
// However, it is not as simple as allowing `Self` in a projected
// type, because there are illegal ways to use `Self` as well:
//
// ```rust
// trait Trait : SuperTrait {
// ...
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
// }
// ```
//
// Here we will not have the type of `X` recorded in the
// object type, and we cannot resolve `Self as SomeOtherTrait`
// without knowing what `Self` is.
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
let mut error = false;
ty::maybe_walk_ty(ty, |ty| {
match ty.sty {
ty::ty_param(ref param_ty) => {
if param_ty.space == SelfSpace {
error = true;
}
false // no contained types to walk
}
ty::ty_projection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazilly.
if supertraits.is_none() {
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
let trait_ref = ty::Binder(trait_def.trait_ref.clone());
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
}
// Determine whether the trait reference `Foo as
// SomeTrait` is in fact a supertrait of the
// current trait. In that case, this type is
// legal, because the type `X` will be specified
// in the object type. Note that we can just use
// direct equality here because all of these types
// are part of the formal parameter listing, and
// hence there should be no inference variables.
let projection_trait_ref = ty::Binder(data.trait_ref.clone());
let is_supertrait_of_current_trait =
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
if is_supertrait_of_current_trait {
false // do not walk contained types, do not report error, do collect $200
} else {
true // DO walk contained types, POSSIBLY reporting an error
}
}
_ => true, // walk contained types, if any
}
});
error
}
}
@ -392,7 +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");

View File

@ -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,
&param_bounds,
span);
check_bounds_compatible(this.tcx(),
param_ty,
&param_bounds,
span);
}
param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));

View File

@ -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<Item> {
self.fold_item_recur(item)
}

View File

@ -232,6 +232,7 @@ use error::{FromError, Error};
use fmt;
use int;
use iter::{Iterator, IteratorExt};
use kinds::Sized;
use mem::transmute;
use ops::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 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 @@ pub trait Acceptor<T> {
/// `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<T>> Iterator<IoResult<T>> for IncomingConnections<'a, A> {
fn next(&mut self) -> Option<IoResult<T>> {
Some(self.inc.accept())
}
}
#[cfg(not(stage0))]
impl<'a, T, Sized? A: Acceptor<T>> Iterator<IoResult<T>> for IncomingConnections<'a, A> {
fn next(&mut self) -> Option<IoResult<T>> {
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`.
///

View File

@ -53,7 +53,7 @@ impl<T> MoveMap<T> for OwnedSlice<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.

View File

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

View File

@ -32,7 +32,7 @@ impl Foo {
}
}
pub trait Bar {
pub trait Bar : Sized {
fn foo1(&self);
fn foo2(self);
fn foo3(self: Box<Self>);

View File

@ -12,7 +12,7 @@
// parameter, the corresponding value must be sized. Also that the
// self type must be sized if appropriate.
trait Foo<T> { fn take(self, x: &T) { } } // Note: T is sized
trait Foo<T> : 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]`

View File

@ -21,6 +21,6 @@ impl Foo for Thing {
fn main() {
let mut thing = Thing;
let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object because trait `Foo`
let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object
foo(test);
}

View File

@ -15,5 +15,4 @@ fn main() {
let r: Box<Foo> = box 5;
let _m: Box<Foo> = r as Box<Foo>;
//~^ ERROR `core::kinds::Sized` is not implemented for the type `Foo`
//~| ERROR `Foo` is not implemented for the type `Foo`
}

View File

@ -0,0 +1,47 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that we correctly prevent users from making trait objects
// from traits with a `fn(self)` method.
trait Bar {
fn bar(self);
}
trait Baz {
fn baz(self: Self);
}
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` has a receiver type of `Self`
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
t as &Bar
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` has a receiver type of `Self`
}
fn make_baz<T:Baz>(t: &T) -> &Baz {
t
//~^ ERROR `Baz` is not object-safe
//~| NOTE method `baz` has a receiver type of `Self`
}
fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
t as &Baz
//~^ ERROR `Baz` is not object-safe
//~| NOTE method `baz` has a receiver type of `Self`
}
fn main() {
}

View File

@ -8,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<Self>) { bar(self as Box<Foo>); }
trait Bar {
fn bar<T>(&self, t: T);
}
fn bar(_b: Box<Foo>) { }
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` has generic type parameters
}
fn main() {}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
t as &Bar
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` has generic type parameters
}
fn main() {
}

View File

@ -0,0 +1,47 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that we correctly prevent users from making trait objects
// form traits that make use of `Self` in an argument or return position.
trait Bar {
fn bar(&self, x: &Self);
}
trait Baz {
fn bar(&self) -> Self;
}
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` references the `Self` type in its arguments or return type
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
t as &Bar
//~^ ERROR `Bar` is not object-safe
//~| NOTE method `bar` references the `Self` type in its arguments or return type
}
fn make_baz<T:Baz>(t: &T) -> &Baz {
t
//~^ ERROR `Baz` is not object-safe
//~| NOTE method `bar` references the `Self` type in its arguments or return type
}
fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
t as &Baz
//~^ ERROR `Baz` is not object-safe
//~| NOTE method `bar` references the `Self` type in its arguments or return type
}
fn main() {
}

View File

@ -0,0 +1,31 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that we correctly prevent users from making trait objects
// from traits with static methods.
trait Foo {
fn foo();
}
fn foo_implicit<T:Foo+'static>(b: Box<T>) -> Box<Foo+'static> {
b
//~^ ERROR cannot convert to a trait object
//~| NOTE method `foo` has no receiver
}
fn foo_explicit<T:Foo+'static>(b: Box<T>) -> Box<Foo+'static> {
b as Box<Foo>
//~^ ERROR cannot convert to a trait object
//~| NOTE method `foo` has no receiver
}
fn main() {
}

View File

@ -0,0 +1,33 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that we correctly prevent users from making trait objects
// from traits where `Self : Sized`.
trait Bar
where Self : Sized
{
fn bar<T>(&self, t: T);
}
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE the trait cannot require that `Self : Sized`
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
t as &Bar
//~^ ERROR `Bar` is not object-safe
//~| NOTE the trait cannot require that `Self : Sized`
}
fn main() {
}

View File

@ -0,0 +1,31 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that we correctly prevent users from making trait objects
// from traits where `Self : Sized`.
trait Bar : Sized {
fn bar<T>(&self, t: T);
}
fn make_bar<T:Bar>(t: &T) -> &Bar {
t
//~^ ERROR `Bar` is not object-safe
//~| NOTE the trait cannot require that `Self : Sized`
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
t as &Bar
//~^ ERROR `Bar` is not object-safe
//~| NOTE the trait cannot require that `Self : Sized`
}
fn main() {
}

View File

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

View File

@ -16,7 +16,7 @@ struct Foo<'a,'b> {
y: &'b int,
}
trait Tr {
trait Tr : Sized {
fn foo(x: Self) {}
}

View File

@ -1,43 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait Foo {
fn foo(self);
}
trait Bar {
fn bar(&self, x: &Self);
}
trait Baz {
fn baz<T>(&self, x: &T);
}
impl Foo for int {
fn foo(self) {}
}
impl Bar for int {
fn bar(&self, _x: &int) {}
}
impl Baz for int {
fn baz<T>(&self, _x: &T) {}
}
fn main() {
let _: &Foo = &42i; //~ ERROR cannot convert to a trait object
let _: &Bar = &42i; //~ ERROR cannot convert to a trait object
let _: &Baz = &42i; //~ ERROR cannot convert to a trait object
let _ = &42i as &Foo; //~ ERROR cannot convert to a trait object
let _ = &42i as &Bar; //~ ERROR cannot convert to a trait object
let _ = &42i as &Baz; //~ ERROR cannot convert to a trait object
}

View File

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

View File

@ -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<T> {
trait Tr<T> : Sized {
fn op(T) -> Self;
}

View File

@ -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<X>(u: X) -> Self {
u //~ ERROR mismatched types
}

View File

@ -10,8 +10,7 @@
// Test that bounds are sized-compatible.
trait T {}
trait T : Sized {}
fn f<Sized? Y: T>() {
//~^ERROR incompatible bounds on `Y`, bound `T` does not allow unsized type
}

View File

@ -11,7 +11,7 @@
// compile-flags:--debuginfo=1
// min-lldb-version: 310
pub trait TraitWithDefaultMethod {
pub trait TraitWithDefaultMethod : Sized {
fn method(self) {
()
}

View File

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

View File

@ -118,7 +118,7 @@ struct Struct {
x: int
}
trait Trait {
trait Trait : Sized {
fn self_by_ref<T>(&self, arg1: int, arg2: T) -> int {
zzz(); // #break

View File

@ -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<Self::Item>;
}
trait IteratorExt: Iterator {
trait IteratorExt: Iterator + Sized {
fn by_ref(&mut self) -> ByRef<Self> {
ByRef(self)
}

View File

@ -21,7 +21,7 @@ trait Not {
fn not(self) -> Self::Result;
}
trait Int: Not<Result=Self> {
trait Int: Not<Result=Self> + Sized {
fn count_ones(self) -> uint;
fn count_zeros(self) -> uint {
// neither works

View File

@ -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<Self::Item>;
}
trait IteratorExt: Iterator {
trait IteratorExt: Iterator + Sized {
fn by_ref(&mut self) -> ByRef<Self> {
ByRef(self)
}

View File

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

View File

@ -13,7 +13,7 @@
use std::sync::mpsc::{Sender, channel};
trait Foo : Send {
trait Foo : Send + Sized {
fn foo(self, tx: Sender<Self>) {
tx.send(self).unwrap();
}

View File

@ -21,7 +21,7 @@ trait Y {
}
trait Z: Y {
trait Z: Y + Sized {
fn x(self) -> int {
require_y(self)
}

View File

@ -16,7 +16,7 @@
fn require_send<T: Send>(_: T){}
trait TragicallySelfIsNotSend: Send {
trait TragicallySelfIsNotSend: Send + Sized {
fn x(self) {
require_send(self);
}

View File

@ -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<Self>);

View File

@ -13,7 +13,7 @@ struct X {
a: int
}
trait Changer {
trait Changer : Sized {
fn change(mut self) -> Self {
self.set_to(55);
self

View File

@ -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);
use std::ops::FnMut;
fn make_adder(x: int) -> Box<FnMut(int)->int + 'static> {
box move |y| { x + y }
}
struct St;
impl Tr for St {
fn foo(&self) {}
pub fn main() {
let mut adder = make_adder(3);
let z = (*adder)(2);
println!("{}", z);
assert_eq!(z, 5);
}
fn main() {
let s: &Tr = &St;
s.foo();
}