auto merge of #7354 : bblum/rust/trait-bounds, r=pcwalton
r? @nikomatsakis
This commit is contained in:
commit
36d7f601d8
@ -10,6 +10,7 @@
|
||||
|
||||
use core::io::{Reader, BytesReader};
|
||||
use core::io;
|
||||
use core::cast;
|
||||
|
||||
/// An implementation of the io::Reader interface which reads a buffer of bytes
|
||||
pub struct BufReader {
|
||||
@ -29,10 +30,13 @@ impl BufReader {
|
||||
}
|
||||
|
||||
fn as_bytes_reader<A>(&self, f: &fn(&BytesReader) -> A) -> A {
|
||||
// XXX FIXME(#5723)
|
||||
let bytes = ::core::util::id::<&[u8]>(self.buf);
|
||||
let bytes: &'static [u8] = unsafe { cast::transmute(bytes) };
|
||||
// Recreating the BytesReader state every call since
|
||||
// I can't get the borrowing to work correctly
|
||||
let bytes_reader = BytesReader {
|
||||
bytes: ::core::util::id::<&[u8]>(self.buf),
|
||||
bytes: bytes,
|
||||
pos: @mut *self.pos
|
||||
};
|
||||
|
||||
|
@ -423,7 +423,7 @@ type MonitorMsg = (TestDesc, TestResult);
|
||||
|
||||
fn run_tests(opts: &TestOpts,
|
||||
tests: ~[TestDescAndFn],
|
||||
callback: @fn(e: TestEvent)) {
|
||||
callback: &fn(e: TestEvent)) {
|
||||
|
||||
let filtered_tests = filter_tests(opts, tests);
|
||||
let filtered_descs = filtered_tests.map(|t| copy t.desc);
|
||||
|
@ -959,7 +959,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
encode_attributes(ebml_w, item.attrs);
|
||||
match ty.node {
|
||||
ast::ty_path(path, bounds, _) if path.idents.len() == 1 => {
|
||||
assert!(bounds.is_empty());
|
||||
assert!(bounds.is_none());
|
||||
encode_impl_type_basename(ecx, ebml_w,
|
||||
ast_util::path_to_ident(path));
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ fn check_item(item: @item, (cx, visitor): (Context, visit::vt<Context>)) {
|
||||
// Yes, it's a destructor.
|
||||
match self_type.node {
|
||||
ty_path(_, bounds, path_node_id) => {
|
||||
assert!(bounds.is_empty());
|
||||
assert!(bounds.is_none());
|
||||
let struct_def = cx.tcx.def_map.get_copy(
|
||||
&path_node_id);
|
||||
let struct_did =
|
||||
@ -169,10 +169,6 @@ fn with_appropriate_checker(cx: Context, id: node_id,
|
||||
let id = ast_util::def_id_of_def(fv.def).node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
|
||||
// FIXME(#3569): Once closure capabilities are restricted based on their
|
||||
// incoming bounds, make this check conditional based on the bounds.
|
||||
if !check_owned(cx, var_t, fv.span) { return; }
|
||||
|
||||
// check that only immutable variables are implicitly copied in
|
||||
check_imm_free_var(cx, fv.def, fv.span);
|
||||
|
||||
@ -184,10 +180,6 @@ fn with_appropriate_checker(cx: Context, id: node_id,
|
||||
let id = ast_util::def_id_of_def(fv.def).node;
|
||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
||||
|
||||
// FIXME(#3569): Once closure capabilities are restricted based on their
|
||||
// incoming bounds, make this check conditional based on the bounds.
|
||||
if !check_durable(cx.tcx, var_t, fv.span) { return; }
|
||||
|
||||
// check that only immutable variables are implicitly copied in
|
||||
check_imm_free_var(cx, fv.def, fv.span);
|
||||
|
||||
@ -293,9 +285,9 @@ pub fn check_expr(e: @expr, (cx, v): (Context, visit::vt<Context>)) {
|
||||
expr_cast(source, _) => {
|
||||
check_cast_for_escaping_regions(cx, source, e);
|
||||
match ty::get(ty::expr_ty(cx.tcx, e)).sty {
|
||||
ty::ty_trait(_, _, store, _, bounds) => {
|
||||
ty::ty_trait(_, _, _, _, bounds) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, source);
|
||||
check_trait_cast_bounds(cx, e.span, source_ty, bounds, store)
|
||||
check_trait_cast_bounds(cx, e.span, source_ty, bounds)
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
@ -391,7 +383,7 @@ pub fn check_freevar_bounds(cx: Context, sp: span, ty: ty::t,
|
||||
}
|
||||
|
||||
pub fn check_trait_cast_bounds(cx: Context, sp: span, ty: ty::t,
|
||||
bounds: ty::BuiltinBounds, store: ty::TraitStore) {
|
||||
bounds: ty::BuiltinBounds) {
|
||||
do check_builtin_bounds(cx, ty, bounds) |missing| {
|
||||
cx.tcx.sess.span_err(sp,
|
||||
fmt!("cannot pack type `%s`, which does not fulfill \
|
||||
@ -399,11 +391,6 @@ pub fn check_trait_cast_bounds(cx: Context, sp: span, ty: ty::t,
|
||||
ty_to_str(cx.tcx, ty), missing.user_string(cx.tcx),
|
||||
bounds.user_string(cx.tcx)));
|
||||
}
|
||||
// FIXME(#3569): Remove this check when the corresponding restriction
|
||||
// is made with type contents.
|
||||
if store == ty::UniqTraitStore && !ty::type_is_owned(cx.tcx, ty) {
|
||||
cx.tcx.sess.span_err(sp, "uniquely-owned trait objects must be sendable");
|
||||
}
|
||||
}
|
||||
|
||||
fn is_nullary_variant(cx: Context, ex: @expr) -> bool {
|
||||
|
@ -4195,15 +4195,19 @@ impl Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
for bounds.iter().advance |bound| {
|
||||
self.resolve_type_parameter_bound(bound, visitor);
|
||||
}
|
||||
do bounds.map |bound_vec| {
|
||||
for bound_vec.iter().advance |bound| {
|
||||
self.resolve_type_parameter_bound(bound, visitor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ty_closure(c) => {
|
||||
for c.bounds.iter().advance |bound| {
|
||||
self.resolve_type_parameter_bound(bound, visitor);
|
||||
}
|
||||
do c.bounds.map |bounds| {
|
||||
for bounds.iter().advance |bound| {
|
||||
self.resolve_type_parameter_bound(bound, visitor);
|
||||
}
|
||||
};
|
||||
visit_ty(ty, ((), visitor));
|
||||
}
|
||||
|
||||
|
@ -2063,20 +2063,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
TC_MANAGED + statically_sized(nonowned(tc_mt(cx, mt, cache)))
|
||||
}
|
||||
|
||||
ty_trait(_, _, UniqTraitStore, _, _bounds) => {
|
||||
// FIXME(#3569): Make this conditional on the trait's bounds.
|
||||
TC_NONCOPY_TRAIT + TC_OWNED_POINTER
|
||||
}
|
||||
|
||||
ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => {
|
||||
match mutbl {
|
||||
ast::m_mutbl => TC_MANAGED + TC_MUTABLE,
|
||||
_ => TC_MANAGED
|
||||
}
|
||||
}
|
||||
|
||||
ty_trait(_, _, RegionTraitStore(r), mutbl, _bounds) => {
|
||||
borrowed_contents(r, mutbl)
|
||||
ty_trait(_, _, store, mutbl, bounds) => {
|
||||
trait_contents(store, mutbl, bounds)
|
||||
}
|
||||
|
||||
ty_rptr(r, mt) => {
|
||||
@ -2261,16 +2249,23 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
}
|
||||
|
||||
fn closure_contents(cty: &ClosureTy) -> TypeContents {
|
||||
// Closure contents are just like trait contents, but with potentially
|
||||
// even more stuff.
|
||||
let st = match cty.sigil {
|
||||
ast::BorrowedSigil => TC_BORROWED_POINTER,
|
||||
ast::ManagedSigil => TC_MANAGED,
|
||||
ast::OwnedSigil => if cty.bounds.contains_elem(BoundCopy) {
|
||||
TC_OWNED_POINTER
|
||||
} else {
|
||||
TC_OWNED_POINTER + TC_NONCOPY_TRAIT
|
||||
}
|
||||
ast::BorrowedSigil =>
|
||||
trait_contents(RegionTraitStore(cty.region), m_imm, cty.bounds)
|
||||
+ TC_BORROWED_POINTER, // might be an env packet even if static
|
||||
ast::ManagedSigil =>
|
||||
trait_contents(BoxTraitStore, m_imm, cty.bounds),
|
||||
ast::OwnedSigil =>
|
||||
trait_contents(UniqTraitStore, m_imm, cty.bounds),
|
||||
};
|
||||
// FIXME(#3569): This borrowed_contents call should be taken care of in
|
||||
// trait_contents, after ~Traits and @Traits can have region bounds too.
|
||||
// This one here is redundant for &fns but important for ~fns and @fns.
|
||||
let rt = borrowed_contents(cty.region, m_imm);
|
||||
// This also prohibits "@once fn" from being copied, which allows it to
|
||||
// be called. Neither way really makes much sense.
|
||||
let ot = match cty.onceness {
|
||||
ast::Once => TC_ONCE_CLOSURE,
|
||||
ast::Many => TC_NONE
|
||||
@ -2278,6 +2273,35 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
|
||||
st + rt + ot
|
||||
}
|
||||
|
||||
fn trait_contents(store: TraitStore, mutbl: ast::mutability,
|
||||
bounds: BuiltinBounds) -> TypeContents {
|
||||
let st = match store {
|
||||
UniqTraitStore => TC_OWNED_POINTER,
|
||||
BoxTraitStore => TC_MANAGED,
|
||||
RegionTraitStore(r) => borrowed_contents(r, mutbl),
|
||||
};
|
||||
let mt = match mutbl { ast::m_mutbl => TC_MUTABLE, _ => TC_NONE };
|
||||
// We get additional "special type contents" for each bound that *isn't*
|
||||
// on the trait. So iterate over the inverse of the bounds that are set.
|
||||
// This is like with typarams below, but less "pessimistic" and also
|
||||
// dependent on the trait store.
|
||||
let mut bt = TC_NONE;
|
||||
for (AllBuiltinBounds() - bounds).each |bound| {
|
||||
bt = bt + match bound {
|
||||
BoundCopy if store == UniqTraitStore
|
||||
=> TC_NONCOPY_TRAIT,
|
||||
BoundCopy => TC_NONE, // @Trait/&Trait are copyable either way
|
||||
BoundStatic if bounds.contains_elem(BoundOwned)
|
||||
=> TC_NONE, // Owned bound implies static bound.
|
||||
BoundStatic => TC_BORROWED_POINTER, // Useful for "@Trait:'static"
|
||||
BoundOwned => TC_NON_OWNED,
|
||||
BoundConst => TC_MUTABLE,
|
||||
BoundSized => TC_NONE, // don't care if interior is sized
|
||||
};
|
||||
}
|
||||
st + mt + bt
|
||||
}
|
||||
|
||||
fn type_param_def_to_contents(cx: ctxt,
|
||||
type_param_def: &TypeParameterDef) -> TypeContents
|
||||
{
|
||||
@ -4497,7 +4521,9 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) {
|
||||
};
|
||||
let trait_lang_item = tcx.lang_items.ty_visitor();
|
||||
let trait_ref = @TraitRef { def_id: trait_lang_item, substs: substs };
|
||||
let mut static_trait_bound = EmptyBuiltinBounds();
|
||||
static_trait_bound.add(BoundStatic);
|
||||
(trait_ref,
|
||||
mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs,
|
||||
BoxTraitStore, ast::m_imm, EmptyBuiltinBounds()))
|
||||
BoxTraitStore, ast::m_imm, static_trait_bound))
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
|
||||
ty::BoxTraitStore
|
||||
}
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(), bounds);
|
||||
let bounds = conv_builtin_bounds(this.tcx(), bounds, trait_store);
|
||||
return ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
copy result.substs,
|
||||
@ -386,7 +386,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
|
||||
bf.abis, &bf.lifetimes, &bf.decl))
|
||||
}
|
||||
ast::ty_closure(ref f) => {
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds);
|
||||
let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
ast::BorrowedSigil => ty::RegionTraitStore(ty::re_empty), // dummy region
|
||||
ast::OwnedSigil => ty::UniqTraitStore,
|
||||
ast::ManagedSigil => ty::BoxTraitStore,
|
||||
});
|
||||
let fn_decl = ty_of_closure(this,
|
||||
rscope,
|
||||
f.sigil,
|
||||
@ -411,7 +417,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>(
|
||||
match a_def {
|
||||
// But don't emit the error if the user meant to do a trait anyway.
|
||||
ast::def_trait(*) => { },
|
||||
_ if !bounds.is_empty() =>
|
||||
_ if bounds.is_some() =>
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
"kind bounds can only be used on trait types"),
|
||||
_ => { },
|
||||
@ -741,8 +747,8 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>(
|
||||
}
|
||||
}
|
||||
|
||||
fn conv_builtin_bounds(tcx: ty::ctxt,
|
||||
ast_bounds: &OptVec<ast::TyParamBound>)
|
||||
fn conv_builtin_bounds(tcx: ty::ctxt, ast_bounds: &Option<OptVec<ast::TyParamBound>>,
|
||||
store: ty::TraitStore)
|
||||
-> ty::BuiltinBounds {
|
||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
||||
//! struct. Reports an error if any of the bounds that appear
|
||||
@ -750,32 +756,51 @@ fn conv_builtin_bounds(tcx: ty::ctxt,
|
||||
//! like `Copy` or `Owned`. Used to translate the bounds that
|
||||
//! appear in closure and trait types, where only builtin bounds are
|
||||
//! legal.
|
||||
//! If no bounds were specified, we choose a "default" bound based on
|
||||
//! the allocation type of the fn/trait, as per issue #7264. The user can
|
||||
//! override this with an empty bounds list, e.g. "~fn:()" or "~Trait:".
|
||||
|
||||
let mut builtin_bounds = ty::EmptyBuiltinBounds();
|
||||
for ast_bounds.iter().advance |ast_bound| {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(b) => {
|
||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
||||
ast::def_trait(trait_did) => {
|
||||
if try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
&mut builtin_bounds) {
|
||||
loop; // success
|
||||
match (ast_bounds, store) {
|
||||
(&Some(ref bound_vec), _) => {
|
||||
let mut builtin_bounds = ty::EmptyBuiltinBounds();
|
||||
for bound_vec.iter().advance |ast_bound| {
|
||||
match *ast_bound {
|
||||
ast::TraitTyParamBound(b) => {
|
||||
match lookup_def_tcx(tcx, b.path.span, b.ref_id) {
|
||||
ast::def_trait(trait_did) => {
|
||||
if try_add_builtin_trait(tcx,
|
||||
trait_did,
|
||||
&mut builtin_bounds) {
|
||||
loop; // success
|
||||
}
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
tcx.sess.span_fatal(
|
||||
b.path.span,
|
||||
fmt!("only the builtin traits can be used \
|
||||
as closure or object bounds"));
|
||||
}
|
||||
ast::RegionTyParamBound => {
|
||||
builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
tcx.sess.span_fatal(
|
||||
b.path.span,
|
||||
fmt!("only the builtin traits can be used \
|
||||
as closure or object bounds"));
|
||||
}
|
||||
ast::RegionTyParamBound => {
|
||||
builtin_bounds.add(ty::BoundStatic);
|
||||
}
|
||||
builtin_bounds
|
||||
},
|
||||
// ~Trait is sugar for ~Trait:Owned.
|
||||
(&None, ty::UniqTraitStore) => {
|
||||
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundOwned); set
|
||||
}
|
||||
// @Trait is sugar for @Trait:'static.
|
||||
// &'static Trait is sugar for &'static Trait:'static.
|
||||
(&None, ty::BoxTraitStore) |
|
||||
(&None, ty::RegionTraitStore(ty::re_static)) => {
|
||||
let mut set = ty::EmptyBuiltinBounds(); set.add(ty::BoundStatic); set
|
||||
}
|
||||
// &'r Trait is sugar for &'r Trait:<no-bounds>.
|
||||
(&None, ty::RegionTraitStore(*)) => ty::EmptyBuiltinBounds(),
|
||||
}
|
||||
builtin_bounds
|
||||
}
|
||||
|
||||
pub fn try_add_builtin_trait(tcx: ty::ctxt,
|
||||
|
@ -1042,12 +1042,14 @@ pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
|
||||
|
||||
|
||||
// Byte readers
|
||||
pub struct BytesReader<'self> {
|
||||
bytes: &'self [u8],
|
||||
pub struct BytesReader {
|
||||
// FIXME(#5723) see other FIXME below
|
||||
// FIXME(#7268) this should also be parameterized over <'self>
|
||||
bytes: &'static [u8],
|
||||
pos: @mut uint
|
||||
}
|
||||
|
||||
impl<'self> Reader for BytesReader<'self> {
|
||||
impl Reader for BytesReader {
|
||||
fn read(&self, bytes: &mut [u8], len: uint) -> uint {
|
||||
let count = uint::min(len, self.bytes.len() - *self.pos);
|
||||
|
||||
@ -1084,6 +1086,10 @@ impl<'self> Reader for BytesReader<'self> {
|
||||
}
|
||||
|
||||
pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T {
|
||||
// XXX XXX XXX this is glaringly unsound
|
||||
// FIXME(#5723) Use a &Reader for the callback's argument. Should be:
|
||||
// fn with_bytes_reader<'r, T>(bytes: &'r [u8], f: &fn(&'r Reader) -> T) -> T
|
||||
let bytes: &'static [u8] = unsafe { cast::transmute(bytes) };
|
||||
f(@BytesReader {
|
||||
bytes: bytes,
|
||||
pos: @mut 0
|
||||
@ -1091,6 +1097,7 @@ pub fn with_bytes_reader<T>(bytes: &[u8], f: &fn(@Reader) -> T) -> T {
|
||||
}
|
||||
|
||||
pub fn with_str_reader<T>(s: &str, f: &fn(@Reader) -> T) -> T {
|
||||
// FIXME(#5723): As above.
|
||||
with_bytes_reader(s.as_bytes(), f)
|
||||
}
|
||||
|
||||
|
@ -771,7 +771,11 @@ pub struct TyClosure {
|
||||
purity: purity,
|
||||
onceness: Onceness,
|
||||
decl: fn_decl,
|
||||
bounds: OptVec<TyParamBound>
|
||||
// Optional optvec distinguishes between "fn()" and "fn:()" so we can
|
||||
// implement issue #7264. None means "fn()", which means infer a default
|
||||
// bound based on pointer sigil during typeck. Some(Empty) means "fn:()",
|
||||
// which means use no bounds (e.g., not even Owned on a ~fn()).
|
||||
bounds: Option<OptVec<TyParamBound>>,
|
||||
}
|
||||
|
||||
#[deriving(Eq, Encodable, Decodable)]
|
||||
@ -795,7 +799,7 @@ pub enum ty_ {
|
||||
ty_closure(@TyClosure),
|
||||
ty_bare_fn(@TyBareFn),
|
||||
ty_tup(~[@Ty]),
|
||||
ty_path(@Path, @OptVec<TyParamBound>, node_id),
|
||||
ty_path(@Path, @Option<OptVec<TyParamBound>>, node_id), // for #7264; see above
|
||||
ty_mac(mac),
|
||||
// ty_infer means the type should be inferred instead of it having been
|
||||
// specified. This should only appear at the "top level" of a type and not
|
||||
|
@ -46,7 +46,7 @@ pub trait AstBuilder {
|
||||
fn ty_mt(&self, ty: @ast::Ty, mutbl: ast::mutability) -> ast::mt;
|
||||
|
||||
fn ty(&self, span: span, ty: ast::ty_) -> @ast::Ty;
|
||||
fn ty_path(&self, @ast::Path, @OptVec<ast::TyParamBound>) -> @ast::Ty;
|
||||
fn ty_path(&self, @ast::Path, @Option<OptVec<ast::TyParamBound>>) -> @ast::Ty;
|
||||
fn ty_ident(&self, span: span, idents: ast::ident) -> @ast::Ty;
|
||||
|
||||
fn ty_rptr(&self, span: span,
|
||||
@ -265,7 +265,7 @@ impl AstBuilder for @ExtCtxt {
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_path(&self, path: @ast::Path, bounds: @OptVec<ast::TyParamBound>)
|
||||
fn ty_path(&self, path: @ast::Path, bounds: @Option<OptVec<ast::TyParamBound>>)
|
||||
-> @ast::Ty {
|
||||
self.ty(path.span,
|
||||
ast::ty_path(path, bounds, self.next_id()))
|
||||
@ -275,7 +275,7 @@ impl AstBuilder for @ExtCtxt {
|
||||
// to generate a bounded existential trait type.
|
||||
fn ty_ident(&self, span: span, ident: ast::ident)
|
||||
-> @ast::Ty {
|
||||
self.ty_path(self.path_ident(span, ident), @opt_vec::Empty)
|
||||
self.ty_path(self.path_ident(span, ident), @None)
|
||||
}
|
||||
|
||||
fn ty_rptr(&self,
|
||||
@ -306,7 +306,7 @@ impl AstBuilder for @ExtCtxt {
|
||||
],
|
||||
None,
|
||||
~[ ty ]),
|
||||
@opt_vec::Empty)
|
||||
@None)
|
||||
}
|
||||
|
||||
fn ty_field_imm(&self, span: span, name: ident, ty: @ast::Ty) -> ast::ty_field {
|
||||
@ -344,7 +344,7 @@ impl AstBuilder for @ExtCtxt {
|
||||
fn ty_vars_global(&self, ty_params: &OptVec<ast::TyParam>) -> ~[@ast::Ty] {
|
||||
opt_vec::take_vec(
|
||||
ty_params.map(|p| self.ty_path(
|
||||
self.path_global(dummy_sp(), ~[p.ident]), @opt_vec::Empty)))
|
||||
self.path_global(dummy_sp(), ~[p.ident]), @None)))
|
||||
}
|
||||
|
||||
fn strip_bounds(&self, generics: &Generics) -> Generics {
|
||||
|
@ -357,7 +357,7 @@ impl<'self> TraitDef<'self> {
|
||||
// Create the type of `self`.
|
||||
let self_type = cx.ty_path(cx.path_all(span, false, ~[ type_ident ], self_lifetime,
|
||||
opt_vec::take_vec(self_ty_params)),
|
||||
@opt_vec::Empty);
|
||||
@None);
|
||||
|
||||
let doc_attr = cx.attribute(
|
||||
span,
|
||||
|
@ -63,7 +63,7 @@ impl<'self> Path<'self> {
|
||||
self_generics: &Generics)
|
||||
-> @ast::Ty {
|
||||
cx.ty_path(self.to_path(cx, span,
|
||||
self_ty, self_generics), @opt_vec::Empty)
|
||||
self_ty, self_generics), @None)
|
||||
}
|
||||
pub fn to_path(&self,
|
||||
cx: @ExtCtxt,
|
||||
@ -143,7 +143,7 @@ impl<'self> Ty<'self> {
|
||||
Literal(ref p) => { p.to_ty(cx, span, self_ty, self_generics) }
|
||||
Self => {
|
||||
cx.ty_path(self.to_path(cx, span, self_ty, self_generics),
|
||||
@opt_vec::Empty)
|
||||
@None)
|
||||
}
|
||||
Tuple(ref fields) => {
|
||||
let ty = if fields.is_empty() {
|
||||
|
@ -59,7 +59,7 @@ impl gen_send for message {
|
||||
|
||||
let pipe_ty = cx.ty_path(
|
||||
path(~[this.data_name()], span)
|
||||
.add_tys(cx.ty_vars(&this.generics.ty_params)), @opt_vec::Empty);
|
||||
.add_tys(cx.ty_vars(&this.generics.ty_params)), @None);
|
||||
let args_ast = vec::append(
|
||||
~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)],
|
||||
args_ast);
|
||||
@ -115,7 +115,7 @@ impl gen_send for message {
|
||||
|
||||
let mut rty = cx.ty_path(path(~[next.data_name()],
|
||||
span)
|
||||
.add_tys(copy next_state.tys), @opt_vec::Empty);
|
||||
.add_tys(copy next_state.tys), @None);
|
||||
if try {
|
||||
rty = cx.ty_option(rty);
|
||||
}
|
||||
@ -144,7 +144,7 @@ impl gen_send for message {
|
||||
cx.ty_path(
|
||||
path(~[this.data_name()], span)
|
||||
.add_tys(cx.ty_vars(
|
||||
&this.generics.ty_params)), @opt_vec::Empty))],
|
||||
&this.generics.ty_params)), @None))],
|
||||
args_ast);
|
||||
|
||||
let message_args = if arg_names.len() == 0 {
|
||||
@ -190,7 +190,7 @@ impl gen_send for message {
|
||||
|
||||
fn to_ty(&mut self, cx: @ExtCtxt) -> @ast::Ty {
|
||||
cx.ty_path(path(~[cx.ident_of(self.name())], self.span())
|
||||
.add_tys(cx.ty_vars(&self.get_generics().ty_params)), @opt_vec::Empty)
|
||||
.add_tys(cx.ty_vars(&self.get_generics().ty_params)), @None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +224,7 @@ impl to_type_decls for state {
|
||||
cx.ty_path(
|
||||
path(~[cx.ident_of(dir),
|
||||
cx.ident_of(next_name)], span)
|
||||
.add_tys(copy next_state.tys), @opt_vec::Empty))
|
||||
.add_tys(copy next_state.tys), @None))
|
||||
}
|
||||
None => tys
|
||||
};
|
||||
@ -277,8 +277,8 @@ impl to_type_decls for state {
|
||||
self.data_name()],
|
||||
dummy_sp())
|
||||
.add_tys(cx.ty_vars(
|
||||
&self.generics.ty_params)), @opt_vec::Empty)),
|
||||
@opt_vec::Empty),
|
||||
&self.generics.ty_params)), @None)),
|
||||
@None),
|
||||
cx.strip_bounds(&self.generics)));
|
||||
}
|
||||
else {
|
||||
@ -297,8 +297,8 @@ impl to_type_decls for state {
|
||||
self.data_name()],
|
||||
dummy_sp())
|
||||
.add_tys(cx.ty_vars_global(
|
||||
&self.generics.ty_params)), @opt_vec::Empty),
|
||||
self.proto.buffer_ty_path(cx)]), @opt_vec::Empty),
|
||||
&self.generics.ty_params)), @None),
|
||||
self.proto.buffer_ty_path(cx)]), @None),
|
||||
cx.strip_bounds(&self.generics)));
|
||||
};
|
||||
items
|
||||
@ -383,7 +383,7 @@ impl gen_init for protocol {
|
||||
cx.ty_path(path(~[cx.ident_of("super"),
|
||||
cx.ident_of("__Buffer")],
|
||||
copy self.span)
|
||||
.add_tys(cx.ty_vars_global(¶ms)), @opt_vec::Empty)
|
||||
.add_tys(cx.ty_vars_global(¶ms)), @None)
|
||||
}
|
||||
|
||||
fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item {
|
||||
|
@ -13,7 +13,6 @@ use codemap::span;
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::build::AstBuilder;
|
||||
use ext::pipes::ast_builder::{append_types, path};
|
||||
use opt_vec;
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum direction { send, recv }
|
||||
@ -100,7 +99,7 @@ impl state_ {
|
||||
pub fn to_ty(&self, cx: @ExtCtxt) -> @ast::Ty {
|
||||
cx.ty_path
|
||||
(path(~[cx.ident_of(self.name)],self.span).add_tys(
|
||||
cx.ty_vars(&self.generics.ty_params)), @opt_vec::Empty)
|
||||
cx.ty_vars(&self.generics.ty_params)), @None)
|
||||
}
|
||||
|
||||
/// Iterate over the states that can be reached in one message
|
||||
|
@ -651,6 +651,12 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
|
||||
span: fld.new_span(f.span),
|
||||
}
|
||||
}
|
||||
fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
|
||||
-> Option<OptVec<TyParamBound>> {
|
||||
do b.map |bounds| {
|
||||
do bounds.map |bound| { fold_ty_param_bound(bound, fld) }
|
||||
}
|
||||
}
|
||||
match *t {
|
||||
ty_nil | ty_bot | ty_infer => copy *t,
|
||||
ty_box(ref mt) => ty_box(fold_mt(mt, fld)),
|
||||
@ -664,7 +670,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
|
||||
purity: f.purity,
|
||||
region: f.region,
|
||||
onceness: f.onceness,
|
||||
bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)),
|
||||
bounds: fold_opt_bounds(&f.bounds, fld),
|
||||
decl: fold_fn_decl(&f.decl, fld),
|
||||
lifetimes: copy f.lifetimes,
|
||||
})
|
||||
@ -679,8 +685,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
|
||||
}
|
||||
ty_tup(ref tys) => ty_tup(tys.map(|ty| fld.fold_ty(*ty))),
|
||||
ty_path(path, bounds, id) =>
|
||||
ty_path(fld.fold_path(path),
|
||||
@bounds.map(|x| fold_ty_param_bound(x, fld)), fld.new_id(id)),
|
||||
ty_path(fld.fold_path(path), @fold_opt_bounds(bounds, fld), fld.new_id(id)),
|
||||
ty_fixed_length_vec(ref mt, e) => {
|
||||
ty_fixed_length_vec(
|
||||
fold_mt(mt, fld),
|
||||
|
@ -490,7 +490,7 @@ mod test {
|
||||
idents:~[str_to_ident("int")],
|
||||
rp: None,
|
||||
types: ~[]},
|
||||
@opt_vec::Empty, 2),
|
||||
@None, 2),
|
||||
span:sp(4,7)},
|
||||
pat: @ast::pat{id:1,
|
||||
node: ast::pat_ident(ast::bind_infer,
|
||||
@ -526,7 +526,7 @@ mod test {
|
||||
idents:~[str_to_ident("int")],
|
||||
rp: None,
|
||||
types: ~[]},
|
||||
@opt_vec::Empty, 2),
|
||||
@None, 2),
|
||||
span:sp(10,13)},
|
||||
pat: @ast::pat{id:1, // fixme
|
||||
node: ast::pat_ident(
|
||||
|
@ -1047,8 +1047,8 @@ impl Parser {
|
||||
|
||||
// Like the above, but can also parse kind bounds in the case of a
|
||||
// path to be used as a type that might be a trait.
|
||||
pub fn parse_type_path(&self) -> (@ast::Path, OptVec<TyParamBound>) {
|
||||
let mut bounds = opt_vec::Empty;
|
||||
pub fn parse_type_path(&self) -> (@ast::Path, Option<OptVec<TyParamBound>>) {
|
||||
let mut bounds = None;
|
||||
let path = self.parse_bounded_path_with_tps(false, Some(|| {
|
||||
// Note: this closure might not even get called in the case of a
|
||||
// macro-generated path. But that's the macro parser's job.
|
||||
@ -2884,9 +2884,13 @@ impl Parser {
|
||||
// matches optbounds = ( ( : ( boundseq )? )? )
|
||||
// where boundseq = ( bound + boundseq ) | bound
|
||||
// and bound = 'static | ty
|
||||
fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> {
|
||||
// Returns "None" if there's no colon (e.g. "T");
|
||||
// Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:")
|
||||
// Returns "Some(stuff)" otherwise (e.g. "T:stuff").
|
||||
// NB: The None/Some distinction is important for issue #7264.
|
||||
fn parse_optional_ty_param_bounds(&self) -> Option<OptVec<TyParamBound>> {
|
||||
if !self.eat(&token::COLON) {
|
||||
return opt_vec::Empty;
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut result = opt_vec::Empty;
|
||||
@ -2935,13 +2939,15 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
// matches typaram = IDENT optbounds
|
||||
fn parse_ty_param(&self) -> TyParam {
|
||||
let ident = self.parse_ident();
|
||||
let bounds = @self.parse_optional_ty_param_bounds();
|
||||
let opt_bounds = self.parse_optional_ty_param_bounds();
|
||||
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
|
||||
let bounds = @opt_bounds.get_or_default(opt_vec::Empty);
|
||||
ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds }
|
||||
}
|
||||
|
||||
@ -3288,7 +3294,7 @@ impl Parser {
|
||||
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
|
||||
// New-style trait. Reinterpret the type as a trait.
|
||||
let opt_trait_ref = match ty.node {
|
||||
ty_path(path, @opt_vec::Empty, node_id) => {
|
||||
ty_path(path, @None, node_id) => {
|
||||
Some(@trait_ref {
|
||||
path: path,
|
||||
ref_id: node_id
|
||||
|
@ -410,14 +410,14 @@ pub fn print_type(s: @ps, ty: @ast::Ty) {
|
||||
let generics = ast::Generics {lifetimes: copy f.lifetimes,
|
||||
ty_params: opt_vec::Empty};
|
||||
print_ty_fn(s, Some(f.abis), None, None,
|
||||
f.purity, ast::Many, &f.decl, None,
|
||||
f.purity, ast::Many, &f.decl, None, &None,
|
||||
Some(&generics), None);
|
||||
}
|
||||
ast::ty_closure(f) => {
|
||||
let generics = ast::Generics {lifetimes: copy f.lifetimes,
|
||||
ty_params: opt_vec::Empty};
|
||||
print_ty_fn(s, None, Some(f.sigil), f.region,
|
||||
f.purity, f.onceness, &f.decl, None,
|
||||
f.purity, f.onceness, &f.decl, None, &f.bounds,
|
||||
Some(&generics), None);
|
||||
}
|
||||
ast::ty_path(path, bounds, _) => print_bounded_path(s, path, bounds),
|
||||
@ -806,7 +806,7 @@ pub fn print_ty_method(s: @ps, m: &ast::ty_method) {
|
||||
maybe_print_comment(s, m.span.lo);
|
||||
print_outer_attributes(s, m.attrs);
|
||||
print_ty_fn(s, None, None, None, m.purity, ast::Many,
|
||||
&m.decl, Some(m.ident), Some(&m.generics),
|
||||
&m.decl, Some(m.ident), &None, Some(&m.generics),
|
||||
Some(/*bad*/ copy m.explicit_self.node));
|
||||
word(s.s, ";");
|
||||
}
|
||||
@ -1488,7 +1488,7 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) {
|
||||
}
|
||||
|
||||
fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
|
||||
opt_bounds: Option<@OptVec<ast::TyParamBound>>) {
|
||||
opt_bounds: &Option<OptVec<ast::TyParamBound>>) {
|
||||
maybe_print_comment(s, path.span.lo);
|
||||
if path.global { word(s.s, "::"); }
|
||||
let mut first = true;
|
||||
@ -1496,8 +1496,8 @@ fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
|
||||
if first { first = false; } else { word(s.s, "::"); }
|
||||
print_ident(s, *id);
|
||||
}
|
||||
do opt_bounds.map_consume |bounds| {
|
||||
print_bounds(s, bounds);
|
||||
do opt_bounds.map |bounds| {
|
||||
print_bounds(s, bounds, true);
|
||||
};
|
||||
if path.rp.is_some() || !path.types.is_empty() {
|
||||
if colons_before_params { word(s.s, "::"); }
|
||||
@ -1520,12 +1520,12 @@ fn print_path_(s: @ps, path: @ast::Path, colons_before_params: bool,
|
||||
}
|
||||
|
||||
pub fn print_path(s: @ps, path: @ast::Path, colons_before_params: bool) {
|
||||
print_path_(s, path, colons_before_params, None)
|
||||
print_path_(s, path, colons_before_params, &None)
|
||||
}
|
||||
|
||||
pub fn print_bounded_path(s: @ps, path: @ast::Path,
|
||||
bounds: @OptVec<ast::TyParamBound>) {
|
||||
print_path_(s, path, false, Some(bounds))
|
||||
bounds: &Option<OptVec<ast::TyParamBound>>) {
|
||||
print_path_(s, path, false, bounds)
|
||||
}
|
||||
|
||||
pub fn print_irrefutable_pat(s: @ps, pat: @ast::pat) {
|
||||
@ -1737,7 +1737,8 @@ pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) {
|
||||
maybe_print_comment(s, decl.output.span.lo);
|
||||
}
|
||||
|
||||
pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) {
|
||||
pub fn print_bounds(s: @ps, bounds: &OptVec<ast::TyParamBound>,
|
||||
print_colon_anyway: bool) {
|
||||
if !bounds.is_empty() {
|
||||
word(s.s, ":");
|
||||
let mut first = true;
|
||||
@ -1754,6 +1755,8 @@ pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) {
|
||||
RegionTyParamBound => word(s.s, "'static"),
|
||||
}
|
||||
}
|
||||
} else if print_colon_anyway {
|
||||
word(s.s, ":");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1774,7 +1777,7 @@ pub fn print_generics(s: @ps, generics: &ast::Generics) {
|
||||
let idx = idx - generics.lifetimes.len();
|
||||
let param = generics.ty_params.get(idx);
|
||||
print_ident(s, param.ident);
|
||||
print_bounds(s, param.bounds);
|
||||
print_bounds(s, param.bounds, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1917,6 +1920,7 @@ pub fn print_ty_fn(s: @ps,
|
||||
onceness: ast::Onceness,
|
||||
decl: &ast::fn_decl,
|
||||
id: Option<ast::ident>,
|
||||
opt_bounds: &Option<OptVec<ast::TyParamBound>>,
|
||||
generics: Option<&ast::Generics>,
|
||||
opt_explicit_self: Option<ast::explicit_self_>) {
|
||||
ibox(s, indent_unit);
|
||||
@ -1930,6 +1934,7 @@ pub fn print_ty_fn(s: @ps,
|
||||
print_onceness(s, onceness);
|
||||
word(s.s, "fn");
|
||||
match id { Some(id) => { word(s.s, " "); print_ident(s, id); } _ => () }
|
||||
do opt_bounds.map |bounds| { print_bounds(s, bounds, true); };
|
||||
match generics { Some(g) => print_generics(s, g), _ => () }
|
||||
zerobreak(s.s);
|
||||
|
||||
|
@ -246,7 +246,9 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) {
|
||||
ty_closure(ref f) => {
|
||||
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
|
||||
(v.visit_ty)(f.decl.output, (copy e, v));
|
||||
visit_ty_param_bounds(&f.bounds, (e, v));
|
||||
do f.bounds.map |bounds| {
|
||||
visit_ty_param_bounds(bounds, (copy e, v));
|
||||
};
|
||||
},
|
||||
ty_bare_fn(ref f) => {
|
||||
for f.decl.inputs.iter().advance |a| { (v.visit_ty)(a.ty, (copy e, v)); }
|
||||
@ -254,7 +256,9 @@ pub fn visit_ty<E: Copy>(t: @Ty, (e, v): (E, vt<E>)) {
|
||||
},
|
||||
ty_path(p, bounds, _) => {
|
||||
visit_path(p, (copy e, v));
|
||||
visit_ty_param_bounds(bounds, (e, v));
|
||||
do bounds.map |bounds| {
|
||||
visit_ty_param_bounds(bounds, (copy e, v));
|
||||
};
|
||||
},
|
||||
ty_fixed_length_vec(ref mt, ex) => {
|
||||
(v.visit_ty)(mt.ty, (copy e, v));
|
||||
|
@ -12,7 +12,7 @@ struct X {
|
||||
field: @fn:Copy(),
|
||||
}
|
||||
|
||||
fn foo(blk: @fn()) -> X {
|
||||
fn foo(blk: @fn:()) -> X {
|
||||
return X { field: blk }; //~ ERROR expected bounds `Copy` but found no bounds
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
fn take_any(_: &fn()) {
|
||||
fn take_any(_: &fn:()) {
|
||||
}
|
||||
|
||||
fn take_copyable(_: &fn:Copy()) {
|
||||
@ -11,7 +11,7 @@ fn take_copyable_owned(_: &fn:Copy+Owned()) {
|
||||
fn take_const_owned(_: &fn:Const+Owned()) {
|
||||
}
|
||||
|
||||
fn give_any(f: &fn()) {
|
||||
fn give_any(f: &fn:()) {
|
||||
take_any(f);
|
||||
take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds
|
||||
take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds
|
||||
|
@ -12,7 +12,7 @@ fn foo(_x: @uint) {}
|
||||
|
||||
fn main() {
|
||||
let x = @3u;
|
||||
let _: ~fn() = || foo(x); //~ ERROR value has non-owned type `@uint`
|
||||
let _: ~fn() = || foo(x); //~ ERROR value has non-owned type `@uint`
|
||||
let _: ~fn() = || foo(x); //~ ERROR value has non-owned type `@uint`
|
||||
let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Owned`
|
||||
let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Owned`
|
||||
let _: ~fn() = || foo(x); //~ ERROR does not fulfill `Owned`
|
||||
}
|
||||
|
@ -11,7 +11,9 @@
|
||||
trait foo { fn foo(&self); }
|
||||
|
||||
fn to_foo<T:Copy + foo>(t: T) -> @foo {
|
||||
@t as @foo //~ ERROR value may contain borrowed pointers; add `'static` bound
|
||||
@t as @foo
|
||||
//~^ ERROR value may contain borrowed pointers; add `'static` bound
|
||||
//~^^ ERROR cannot pack type
|
||||
}
|
||||
|
||||
fn to_foo2<T:Copy + foo + 'static>(t: T) -> @foo {
|
||||
|
@ -9,8 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn copy1<T:Copy>(t: T) -> @fn() -> T {
|
||||
let result: @fn() -> T = || copy t;
|
||||
//~^ ERROR value may contain borrowed pointers
|
||||
let result: @fn() -> T = || copy t; //~ ERROR does not fulfill `'static`
|
||||
result
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ fn main() {
|
||||
let x = Cell::new(foo(Port(@())));
|
||||
|
||||
do task::spawn {
|
||||
let y = x.take(); //~ ERROR value has non-owned type
|
||||
let y = x.take(); //~ ERROR does not fulfill `Owned`
|
||||
error!(y);
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ fn c(x: ~Foo:Const+Owned) {
|
||||
b(x); //~ ERROR expected bounds `Copy+Owned`
|
||||
}
|
||||
|
||||
fn d(x: ~Foo) {
|
||||
fn d(x: ~Foo:) {
|
||||
a(x); //~ ERROR found no bounds
|
||||
}
|
||||
|
||||
|
37
src/test/compile-fail/trait-bounds-sugar.rs
Normal file
37
src/test/compile-fail/trait-bounds-sugar.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// Tests for "default" bounds inferred for traits with no bounds list.
|
||||
|
||||
trait Foo {
|
||||
}
|
||||
|
||||
fn a(_x: ~Foo) { // should be same as ~Foo:Owned
|
||||
}
|
||||
|
||||
fn b(_x: @Foo) { // should be same as ~Foo:'static
|
||||
}
|
||||
|
||||
fn c(_x: &'static Foo) { // should be same as &'static Foo:'static
|
||||
}
|
||||
|
||||
fn d(x: ~Foo:Const) {
|
||||
a(x); //~ ERROR expected bounds `Owned`
|
||||
}
|
||||
|
||||
fn e(x: @Foo:Const) {
|
||||
b(x); //~ ERROR expected bounds `'static`
|
||||
}
|
||||
|
||||
fn f(x: &'static Foo:Const) {
|
||||
c(x); //~ ERROR expected bounds `'static`
|
||||
}
|
||||
|
||||
fn main() { }
|
@ -8,11 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-pretty
|
||||
|
||||
// Tests correct copying of heap closures' environments.
|
||||
|
||||
fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
|
||||
fn foo(x: ~fn:Copy()) -> (~fn:(), ~fn:()) {
|
||||
(copy x, x)
|
||||
}
|
||||
fn main() {
|
||||
|
@ -8,14 +8,12 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// xfail-pretty
|
||||
|
||||
// Tests correct copying of heap closures' environments.
|
||||
|
||||
fn bar<T: Copy>(x: T) -> (T, T) {
|
||||
(copy x, x)
|
||||
}
|
||||
fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) {
|
||||
fn foo(x: ~fn:Copy()) -> (~fn:(), ~fn:()) {
|
||||
bar(x)
|
||||
}
|
||||
fn main() {
|
||||
|
@ -14,9 +14,9 @@ impl<A:Copy> repeat<A> for @A {
|
||||
fn get(&self) -> A { copy **self }
|
||||
}
|
||||
|
||||
fn repeater<A:Copy>(v: @A) -> @repeat<A> {
|
||||
fn repeater<A:Copy>(v: @A) -> @repeat:<A> {
|
||||
// Note: owned kind is not necessary as A appears in the trait type
|
||||
@v as @repeat<A> // No
|
||||
@v as @repeat:<A> // No
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
@ -22,7 +22,7 @@ impl<'self> get_ctxt<'self> for HasCtxt<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_v(gc: @get_ctxt) -> uint {
|
||||
fn get_v(gc: @get_ctxt:) -> uint {
|
||||
gc.get_ctxt().v
|
||||
}
|
||||
|
||||
@ -30,5 +30,5 @@ pub fn main() {
|
||||
let ctxt = Ctxt { v: 22 };
|
||||
let hc = HasCtxt { c: &ctxt };
|
||||
|
||||
assert_eq!(get_v(@hc as @get_ctxt), 22);
|
||||
assert_eq!(get_v(@hc as @get_ctxt:), 22);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
trait Foo {
|
||||
}
|
||||
|
||||
fn a(_x: ~Foo) {
|
||||
fn a(_x: ~Foo:) {
|
||||
}
|
||||
|
||||
fn b(_x: ~Foo:Owned) {
|
||||
@ -25,4 +25,8 @@ fn d(x: ~Foo:Owned+Copy) {
|
||||
b(x);
|
||||
}
|
||||
|
||||
fn e(x: ~Foo) { // sugar for ~Foo:Owned
|
||||
b(x);
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
103
src/test/run-pass/trait-bounds-in-arc.rs
Normal file
103
src/test/run-pass/trait-bounds-in-arc.rs
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// Tests that a heterogeneous list of existential types can be put inside an ARC
|
||||
// and shared between tasks as long as all types fulfill Const+Owned.
|
||||
|
||||
// xfail-fast
|
||||
|
||||
extern mod extra;
|
||||
use extra::arc;
|
||||
use std::comm;
|
||||
use std::task;
|
||||
use std::cell;
|
||||
|
||||
trait Pet {
|
||||
fn name(&self, blk: &fn(&str));
|
||||
fn num_legs(&self) -> uint;
|
||||
fn of_good_pedigree(&self) -> bool;
|
||||
}
|
||||
|
||||
struct Catte {
|
||||
num_whiskers: uint,
|
||||
name: ~str,
|
||||
}
|
||||
|
||||
struct Dogge {
|
||||
bark_decibels: uint,
|
||||
tricks_known: uint,
|
||||
name: ~str,
|
||||
}
|
||||
|
||||
struct Goldfyshe {
|
||||
swim_speed: uint,
|
||||
name: ~str,
|
||||
}
|
||||
|
||||
impl Pet for Catte {
|
||||
fn name(&self, blk: &fn(&str)) { blk(self.name) }
|
||||
fn num_legs(&self) -> uint { 4 }
|
||||
fn of_good_pedigree(&self) -> bool { self.num_whiskers >= 4 }
|
||||
}
|
||||
impl Pet for Dogge {
|
||||
fn name(&self, blk: &fn(&str)) { blk(self.name) }
|
||||
fn num_legs(&self) -> uint { 4 }
|
||||
fn of_good_pedigree(&self) -> bool {
|
||||
self.bark_decibels < 70 || self.tricks_known > 20
|
||||
}
|
||||
}
|
||||
impl Pet for Goldfyshe {
|
||||
fn name(&self, blk: &fn(&str)) { blk(self.name) }
|
||||
fn num_legs(&self) -> uint { 0 }
|
||||
fn of_good_pedigree(&self) -> bool { self.swim_speed >= 500 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let catte = Catte { num_whiskers: 7, name: ~"alonzo_church" };
|
||||
let dogge1 = Dogge { bark_decibels: 100, tricks_known: 42, name: ~"alan_turing" };
|
||||
let dogge2 = Dogge { bark_decibels: 55, tricks_known: 11, name: ~"albert_einstein" };
|
||||
let fishe = Goldfyshe { swim_speed: 998, name: ~"alec_guinness" };
|
||||
let arc = arc::ARC(~[~catte as ~Pet:Const+Owned,
|
||||
~dogge1 as ~Pet:Const+Owned,
|
||||
~fishe as ~Pet:Const+Owned,
|
||||
~dogge2 as ~Pet:Const+Owned]);
|
||||
let (p1,c1) = comm::stream();
|
||||
let arc1 = cell::Cell::new(arc.clone());
|
||||
do task::spawn { check_legs(arc1.take()); c1.send(()); }
|
||||
let (p2,c2) = comm::stream();
|
||||
let arc2 = cell::Cell::new(arc.clone());
|
||||
do task::spawn { check_names(arc2.take()); c2.send(()); }
|
||||
let (p3,c3) = comm::stream();
|
||||
let arc3 = cell::Cell::new(arc.clone());
|
||||
do task::spawn { check_pedigree(arc3.take()); c3.send(()); }
|
||||
p1.recv();
|
||||
p2.recv();
|
||||
p3.recv();
|
||||
}
|
||||
|
||||
fn check_legs(arc: arc::ARC<~[~Pet:Const+Owned]>) {
|
||||
let mut legs = 0;
|
||||
for arc.get().iter().advance |pet| {
|
||||
legs += pet.num_legs();
|
||||
}
|
||||
assert!(legs == 12);
|
||||
}
|
||||
fn check_names(arc: arc::ARC<~[~Pet:Const+Owned]>) {
|
||||
for arc.get().iter().advance |pet| {
|
||||
do pet.name |name| {
|
||||
assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn check_pedigree(arc: arc::ARC<~[~Pet:Const+Owned]>) {
|
||||
for arc.get().iter().advance |pet| {
|
||||
assert!(pet.of_good_pedigree());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user