auto merge of #13686 : alexcrichton/rust/issue-12224, r=nikomatsakis

This alters the borrow checker's requirements on invoking closures from
requiring an immutable borrow to requiring a unique immutable borrow. This means 
that it is illegal to invoke a closure through a `&` pointer because there is no 
guarantee that is not aliased. This does not mean that a closure is required to
be in a mutable location, but rather a location which can be proven to be
unique (often through a mutable pointer).
                                                                                 
For example, the following code is unsound and is no longer allowed:             
                                                                                 
    type Fn<'a> = ||:'a;                                                         
                                                                                 
    fn call(f: |Fn|) {                                                           
        f(|| {                                                                   
            f(|| {})                                                             
        });                                                                      
    }                                                                            
                                                                                 
    fn main() {                                                                  
        call(|a| {                                                               
            a();                                                                 
        });                                                                      
    }                                                                            
                                                                                 
There is no replacement for this pattern. For all closures which are stored in
structures, it was previously allowed to invoke the closure through `&self` but
it now requires invocation through `&mut self`.

The standard library has a good number of violations of this new rule, but the
fixes will be separated into multiple breaking change commits.
                                                                                 
Closes #12224
This commit is contained in:
bors 2014-04-23 12:01:53 -07:00
commit 6beb376b5c
38 changed files with 360 additions and 194 deletions

View File

@ -632,7 +632,7 @@ impl<'a> RandomAccessIterator<bool> for Bits<'a> {
}
#[inline]
fn idx(&self, index: uint) -> Option<bool> {
fn idx(&mut self, index: uint) -> Option<bool> {
if index >= self.indexable() {
None
} else {

View File

@ -272,7 +272,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
fn indexable(&self) -> uint { self.rindex - self.index }
#[inline]
fn idx(&self, j: uint) -> Option<&'a T> {
fn idx(&mut self, j: uint) -> Option<&'a T> {
if j >= self.indexable() {
None
} else {

View File

@ -672,7 +672,7 @@ impl ToStrRadix for BigUint {
s.push_str("0".repeat(l - ss.len()));
s.push_str(ss);
}
s.as_slice().trim_left_chars(&'0').to_owned()
s.as_slice().trim_left_chars('0').to_owned()
}
}
}

View File

@ -47,7 +47,7 @@ pub fn strip_items(krate: ast::Crate,
ctxt.fold_crate(krate)
}
fn filter_view_item<'r>(cx: &Context, view_item: &'r ast::ViewItem)
fn filter_view_item<'r>(cx: &mut Context, view_item: &'r ast::ViewItem)
-> Option<&'r ast::ViewItem> {
if view_item_in_cfg(cx, view_item) {
Some(view_item)
@ -72,7 +72,7 @@ fn fold_mod(cx: &mut Context, m: &ast::Mod) -> ast::Mod {
}
}
fn filter_foreign_item(cx: &Context, item: @ast::ForeignItem)
fn filter_foreign_item(cx: &mut Context, item: @ast::ForeignItem)
-> Option<@ast::ForeignItem> {
if foreign_item_in_cfg(cx, item) {
Some(item)
@ -144,7 +144,7 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
fold::noop_fold_item_underscore(&item, cx)
}
fn fold_struct(cx: &Context, def: &ast::StructDef) -> @ast::StructDef {
fn fold_struct(cx: &mut Context, def: &ast::StructDef) -> @ast::StructDef {
let mut fields = def.fields.iter().map(|c| c.clone()).filter(|m| {
(cx.in_cfg)(m.node.attrs.as_slice())
});
@ -156,7 +156,7 @@ fn fold_struct(cx: &Context, def: &ast::StructDef) -> @ast::StructDef {
}
}
fn retain_stmt(cx: &Context, stmt: @ast::Stmt) -> bool {
fn retain_stmt(cx: &mut Context, stmt: @ast::Stmt) -> bool {
match stmt.node {
ast::StmtDecl(decl, _) => {
match decl.node {
@ -189,23 +189,23 @@ fn fold_block(cx: &mut Context, b: ast::P<ast::Block>) -> ast::P<ast::Block> {
})
}
fn item_in_cfg(cx: &Context, item: &ast::Item) -> bool {
fn item_in_cfg(cx: &mut Context, item: &ast::Item) -> bool {
return (cx.in_cfg)(item.attrs.as_slice());
}
fn foreign_item_in_cfg(cx: &Context, item: &ast::ForeignItem) -> bool {
fn foreign_item_in_cfg(cx: &mut Context, item: &ast::ForeignItem) -> bool {
return (cx.in_cfg)(item.attrs.as_slice());
}
fn view_item_in_cfg(cx: &Context, item: &ast::ViewItem) -> bool {
fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
return (cx.in_cfg)(item.attrs.as_slice());
}
fn method_in_cfg(cx: &Context, meth: &ast::Method) -> bool {
fn method_in_cfg(cx: &mut Context, meth: &ast::Method) -> bool {
return (cx.in_cfg)(meth.attrs.as_slice());
}
fn trait_method_in_cfg(cx: &Context, meth: &ast::TraitMethod) -> bool {
fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitMethod) -> bool {
match *meth {
ast::Required(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
ast::Provided(meth) => (cx.in_cfg)(meth.attrs.as_slice())

View File

@ -84,7 +84,7 @@ pub struct EncodeContext<'a> {
pub non_inlineable_statics: &'a RefCell<NodeSet>,
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: EncodeInlinedItem<'a>,
pub encode_inlined_item: RefCell<EncodeInlinedItem<'a>>,
pub type_abbrevs: tyencode::abbrev_map,
}
@ -765,8 +765,8 @@ fn encode_info_for_method(ecx: &EncodeContext,
if num_params > 0u ||
is_default_impl ||
should_inline(ast_method.attrs.as_slice()) {
(ecx.encode_inlined_item)(
ecx, ebml_w, IIMethodRef(local_def(parent_id), false, ast_method));
encode_inlined_item(ecx, ebml_w,
IIMethodRef(local_def(parent_id), false, ast_method));
} else {
encode_symbol(ecx, ebml_w, m.def_id.node);
}
@ -775,6 +775,14 @@ fn encode_info_for_method(ecx: &EncodeContext,
ebml_w.end_tag();
}
fn encode_inlined_item(ecx: &EncodeContext,
ebml_w: &mut Encoder,
ii: InlinedItemRef) {
let mut eii = ecx.encode_inlined_item.borrow_mut();
let eii: &mut EncodeInlinedItem = &mut *eii;
(*eii)(ecx, ebml_w, ii)
}
fn style_fn_family(s: FnStyle) -> char {
match s {
UnsafeFn => 'u',
@ -880,7 +888,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
let inlineable = !ecx.non_inlineable_statics.borrow().contains(&item.id);
if inlineable {
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
}
encode_visibility(ebml_w, vis);
ebml_w.end_tag();
@ -896,7 +904,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_path(ebml_w, path);
encode_attributes(ebml_w, item.attrs.as_slice());
if tps_len > 0u || should_inline(item.attrs.as_slice()) {
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
} else {
encode_symbol(ecx, ebml_w, item.id);
}
@ -954,7 +962,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
for v in (*enum_definition).variants.iter() {
encode_variant_id(ebml_w, local_def(v.node.id));
}
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
encode_path(ebml_w, path);
// Encode inherent implementations for this enumeration.
@ -1002,7 +1010,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
needs to know*/
encode_struct_fields(ebml_w, fields.as_slice(), def_id);
(ecx.encode_inlined_item)(ecx, ebml_w, IIItemRef(item));
encode_inlined_item(ecx, ebml_w, IIItemRef(item));
// Encode inherent implementations for this structure.
encode_inherent_implementations(ecx, ebml_w, def_id);
@ -1175,8 +1183,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_bounds_and_type(ebml_w, ecx, &tpt);
}
encode_method_sort(ebml_w, 'p');
(ecx.encode_inlined_item)(
ecx, ebml_w, IIMethodRef(def_id, true, m));
encode_inlined_item(ecx, ebml_w,
IIMethodRef(def_id, true, m));
}
}
@ -1212,7 +1220,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
&lookup_item_type(ecx.tcx,local_def(nitem.id)));
encode_name(ebml_w, nitem.ident.name);
if abi == abi::RustIntrinsic {
(ecx.encode_inlined_item)(ecx, ebml_w, IIForeignRef(nitem));
encode_inlined_item(ecx, ebml_w, IIForeignRef(nitem));
} else {
encode_symbol(ecx, ebml_w, nitem.id);
}
@ -1544,12 +1552,12 @@ fn encode_macro_registrar_fn(ecx: &EncodeContext, ebml_w: &mut Encoder) {
}
}
struct MacroDefVisitor<'a, 'b> {
ecx: &'a EncodeContext<'a>,
ebml_w: &'a mut Encoder<'b>
struct MacroDefVisitor<'a, 'b, 'c> {
ecx: &'a EncodeContext<'b>,
ebml_w: &'a mut Encoder<'c>
}
impl<'a, 'b> Visitor<()> for MacroDefVisitor<'a, 'b> {
impl<'a, 'b, 'c> Visitor<()> for MacroDefVisitor<'a, 'b, 'c> {
fn visit_item(&mut self, item: &Item, _: ()) {
match item.node {
ItemMac(..) => {
@ -1565,9 +1573,9 @@ impl<'a, 'b> Visitor<()> for MacroDefVisitor<'a, 'b> {
}
}
fn encode_macro_defs(ecx: &EncodeContext,
krate: &Crate,
ebml_w: &mut Encoder) {
fn encode_macro_defs<'a>(ecx: &'a EncodeContext,
krate: &Crate,
ebml_w: &'a mut Encoder) {
ebml_w.start_tag(tag_exported_macros);
{
let mut visitor = MacroDefVisitor {
@ -1579,12 +1587,12 @@ fn encode_macro_defs(ecx: &EncodeContext,
ebml_w.end_tag();
}
struct ImplVisitor<'a,'b> {
ecx: &'a EncodeContext<'a>,
ebml_w: &'a mut Encoder<'b>,
struct ImplVisitor<'a,'b,'c> {
ecx: &'a EncodeContext<'b>,
ebml_w: &'a mut Encoder<'c>,
}
impl<'a,'b> Visitor<()> for ImplVisitor<'a,'b> {
impl<'a,'b,'c> Visitor<()> for ImplVisitor<'a,'b,'c> {
fn visit_item(&mut self, item: &Item, _: ()) {
match item.node {
ItemImpl(_, Some(ref trait_ref), _, _) => {
@ -1617,9 +1625,9 @@ impl<'a,'b> Visitor<()> for ImplVisitor<'a,'b> {
/// * Destructors (implementations of the Drop trait).
///
/// * Implementations of traits not defined in this crate.
fn encode_impls(ecx: &EncodeContext,
krate: &Crate,
ebml_w: &mut Encoder) {
fn encode_impls<'a>(ecx: &'a EncodeContext,
krate: &Crate,
ebml_w: &'a mut Encoder) {
ebml_w.start_tag(tag_impls);
{
@ -1744,7 +1752,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
non_inlineable_statics: non_inlineable_statics,
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: encode_inlined_item,
encode_inlined_item: RefCell::new(encode_inlined_item),
type_abbrevs: RefCell::new(HashMap::new()),
};

View File

@ -92,9 +92,9 @@ impl<'a> FileSearch<'a> {
match fs::readdir(lib_search_path) {
Ok(files) => {
let mut rslt = FileDoesntMatch;
let is_rlib = |p: & &Path| {
fn is_rlib(p: & &Path) -> bool {
p.extension_str() == Some("rlib")
};
}
// Reading metadata out of rlibs is faster, and if we find both
// an rlib and a dylib we only read one of the files of
// metadata, so in the name of speed, bring all rlib files to

View File

@ -327,7 +327,7 @@ impl<'a> CheckLoanCtxt<'a> {
self.bccx.loan_path_to_str(&*old_loan.loan_path))
}
AddrOf | AutoRef | RefBinding => {
AddrOf | AutoRef | RefBinding | ClosureInvocation => {
format!("previous borrow of `{}` occurs here",
self.bccx.loan_path_to_str(&*old_loan.loan_path))
}

View File

@ -292,6 +292,26 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
visit::walk_expr(this, ex, ());
}
ast::ExprCall(f, _) => {
let expr_ty = ty::expr_ty_adjusted(tcx, f);
match ty::get(expr_ty).sty {
ty::ty_closure(~ty::ClosureTy {
store: ty::RegionTraitStore(..), ..
}) => {
let scope_r = ty::ReScope(ex.id);
let base_cmt = this.bccx.cat_expr(f);
this.guarantee_valid_kind(f.id,
f.span,
base_cmt,
ty::UniqueImmBorrow,
scope_r,
ClosureInvocation);
}
_ => {}
}
visit::walk_expr(this, ex, ());
}
_ => {
visit::walk_expr(this, ex, ());
}

View File

@ -202,6 +202,7 @@ pub enum LoanCause {
AddrOf,
AutoRef,
RefBinding,
ClosureInvocation,
}
#[deriving(Eq, TotalEq, Hash)]
@ -629,6 +630,10 @@ impl<'a> BorrowckCtxt<'a> {
AddrOf | RefBinding | AutoRef => {
format!("cannot borrow {} as mutable", descr)
}
ClosureInvocation => {
self.tcx.sess.span_bug(err.span,
"err_mutbl with a closure invocation");
}
}
}
err_out_of_root_scope(..) => {
@ -677,6 +682,10 @@ impl<'a> BorrowckCtxt<'a> {
BorrowViolation(RefBinding) => {
"cannot borrow data mutably"
}
BorrowViolation(ClosureInvocation) => {
"closure invocation"
}
};
match cause {

View File

@ -1164,7 +1164,7 @@ fn check_item_non_camel_case_types(cx: &Context, it: &ast::Item) {
fn is_camel_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
assert!(!ident.get().is_empty());
let ident = ident.get().trim_chars(&'_');
let ident = ident.get().trim_chars('_');
// start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase)

View File

@ -1104,34 +1104,34 @@ impl<'a> SanePrivacyVisitor<'a> {
/// control over anything so this forbids any mention of any visibility
fn check_all_inherited(&self, item: &ast::Item) {
let tcx = self.tcx;
let check_inherited = |sp: Span, vis: ast::Visibility| {
fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
if vis != ast::Inherited {
tcx.sess.span_err(sp, "visibility has no effect inside functions");
}
};
}
let check_struct = |def: &@ast::StructDef| {
for f in def.fields.iter() {
match f.node.kind {
ast::NamedField(_, p) => check_inherited(f.span, p),
ast::NamedField(_, p) => check_inherited(tcx, f.span, p),
ast::UnnamedField(..) => {}
}
}
};
check_inherited(item.span, item.vis);
check_inherited(tcx, item.span, item.vis);
match item.node {
ast::ItemImpl(_, _, _, ref methods) => {
for m in methods.iter() {
check_inherited(m.span, m.vis);
check_inherited(tcx, m.span, m.vis);
}
}
ast::ItemForeignMod(ref fm) => {
for i in fm.items.iter() {
check_inherited(i.span, i.vis);
check_inherited(tcx, i.span, i.vis);
}
}
ast::ItemEnum(ref def, _) => {
for v in def.variants.iter() {
check_inherited(v.span, v.node.vis);
check_inherited(tcx, v.span, v.node.vis);
match v.node.kind {
ast::StructVariantKind(ref s) => check_struct(s),
@ -1146,7 +1146,8 @@ impl<'a> SanePrivacyVisitor<'a> {
for m in methods.iter() {
match *m {
ast::Required(..) => {}
ast::Provided(ref m) => check_inherited(m.span, m.vis),
ast::Provided(ref m) => check_inherited(tcx, m.span,
m.vis),
}
}
}

View File

@ -751,7 +751,15 @@ fn constrain_callee(rcx: &mut Rcx,
ty::ty_bare_fn(..) => { }
ty::ty_closure(ref closure_ty) => {
let region = match closure_ty.store {
ty::RegionTraitStore(r, _) => r,
ty::RegionTraitStore(r, _) => {
// While we're here, link the closure's region with a unique
// immutable borrow (gathered later in borrowck)
let mc = mc::MemCategorizationContext { typer: &*rcx };
let expr_cmt = ignore_err!(mc.cat_expr(callee_expr));
link_region(mc.typer, callee_expr.span, call_region,
ty::UniqueImmBorrow, expr_cmt);
r
}
ty::UniqTraitStore => ty::ReStatic
};
rcx.fcx.mk_subr(true, infer::InvokeClosure(callee_expr.span),
@ -874,7 +882,8 @@ fn constrain_autoderefs(rcx: &mut Rcx,
{
let mc = mc::MemCategorizationContext { typer: &*rcx };
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
link_region(mc.typer, deref_expr.span, r, m, self_cmt);
link_region(mc.typer, deref_expr.span, r,
ty::BorrowKind::from_mutbl(m), self_cmt);
}
// Specialized version of constrain_call.
@ -1092,7 +1101,8 @@ fn link_pattern(mc: mc::MemCategorizationContext<&Rcx>,
match mc.cat_slice_pattern(sub_cmt, slice_pat) {
Ok((slice_cmt, slice_mutbl, slice_r)) => {
link_region(mc.typer, sub_pat.span, slice_r,
slice_mutbl, slice_cmt);
ty::BorrowKind::from_mutbl(slice_mutbl),
slice_cmt);
}
Err(()) => {}
}
@ -1118,17 +1128,20 @@ fn link_autoref(rcx: &Rcx,
match *autoref {
ty::AutoPtr(r, m) => {
link_region(mc.typer, expr.span, r, m, expr_cmt);
link_region(mc.typer, expr.span, r,
ty::BorrowKind::from_mutbl(m), expr_cmt);
}
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
link_region(mc.typer, expr.span, r, m, cmt_index);
link_region(mc.typer, expr.span, r,
ty::BorrowKind::from_mutbl(m), cmt_index);
}
ty::AutoBorrowObj(r, m) => {
let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
link_region(mc.typer, expr.span, r, m, cmt_deref);
link_region(mc.typer, expr.span, r,
ty::BorrowKind::from_mutbl(m), cmt_deref);
}
ty::AutoUnsafe(_) => {}
@ -1150,7 +1163,7 @@ fn link_by_ref(rcx: &Rcx,
let mc = mc::MemCategorizationContext { typer: rcx };
let expr_cmt = ignore_err!(mc.cat_expr(expr));
let region_min = ty::ReScope(callee_scope);
link_region(mc.typer, expr.span, region_min, ast::MutImmutable, expr_cmt);
link_region(mc.typer, expr.span, region_min, ty::ImmBorrow, expr_cmt);
}
fn link_region_from_node_type(rcx: &Rcx,
@ -1169,18 +1182,19 @@ fn link_region_from_node_type(rcx: &Rcx,
let tcx = rcx.fcx.ccx.tcx;
debug!("rptr_ty={}", ty_to_str(tcx, rptr_ty));
let r = ty::ty_region(tcx, span, rptr_ty);
link_region(rcx, span, r, mutbl, cmt_borrowed);
link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl),
cmt_borrowed);
}
}
fn link_region(rcx: &Rcx,
span: Span,
region_min: ty::Region,
mutbl: ast::Mutability,
kind: ty::BorrowKind,
cmt_borrowed: mc::cmt) {
/*!
* Informs the inference engine that a borrow of `cmt`
* must have mutability `mutbl` and lifetime `region_min`.
* must have the borrow kind `kind` and lifetime `region_min`.
* If `cmt` is a deref of a region pointer with
* lifetime `r_borrowed`, this will add the constraint that
* `region_min <= r_borrowed`.
@ -1190,9 +1204,9 @@ fn link_region(rcx: &Rcx,
// for the lifetime `region_min` for the borrow to be valid:
let mut cmt_borrowed = cmt_borrowed;
loop {
debug!("link_region(region_min={}, mutbl={}, cmt_borrowed={})",
debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
region_min.repr(rcx.tcx()),
mutbl.repr(rcx.tcx()),
kind.repr(rcx.tcx()),
cmt_borrowed.repr(rcx.tcx()));
match cmt_borrowed.cat.clone() {
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
@ -1214,7 +1228,7 @@ fn link_region(rcx: &Rcx,
adjust_upvar_borrow_kind_for_loan(
*upvar_id,
upvar_borrow,
mutbl);
kind);
infer::ReborrowUpvar(span, *upvar_id)
}
None => {
@ -1236,7 +1250,7 @@ fn link_region(rcx: &Rcx,
r_borrowed.repr(rcx.tcx()));
rcx.fcx.mk_subr(true, cause, region_min, r_borrowed);
if mutbl == ast::MutMutable {
if kind != ty::ImmBorrow {
// If this is a mutable borrow, then the thing
// being borrowed will have to be unique.
// In user code, this means it must be an `&mut`
@ -1428,12 +1442,11 @@ fn link_upvar_borrow_kind_for_nested_closures(rcx: &mut Rcx,
fn adjust_upvar_borrow_kind_for_loan(upvar_id: ty::UpvarId,
upvar_borrow: &mut ty::UpvarBorrow,
mutbl: ast::Mutability) {
kind: ty::BorrowKind) {
debug!("adjust_upvar_borrow_kind_for_loan: upvar_id={:?} kind={:?} -> {:?}",
upvar_id, upvar_borrow.kind, mutbl);
upvar_id, upvar_borrow.kind, kind);
adjust_upvar_borrow_kind(upvar_id, upvar_borrow,
ty::BorrowKind::from_mutbl(mutbl))
adjust_upvar_borrow_kind(upvar_id, upvar_borrow, kind)
}
fn adjust_upvar_borrow_kind(upvar_id: ty::UpvarId,

View File

@ -107,9 +107,9 @@ impl<'a> Parser<'a> {
}
// Return result of first successful parser
fn read_or<T>(&mut self, parsers: &[|&mut Parser| -> Option<T>])
fn read_or<T>(&mut self, parsers: &mut [|&mut Parser| -> Option<T>])
-> Option<T> {
for pf in parsers.iter() {
for pf in parsers.mut_iter() {
match self.read_atomically(|p: &mut Parser| (*pf)(p)) {
Some(r) => return Some(r),
None => {}
@ -305,7 +305,7 @@ impl<'a> Parser<'a> {
fn read_ip_addr(&mut self) -> Option<IpAddr> {
let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr();
let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr();
self.read_or([ipv4_addr, ipv6_addr])
self.read_or(&mut [ipv4_addr, ipv6_addr])
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
@ -318,7 +318,7 @@ impl<'a> Parser<'a> {
p.read_seq_3::<char, IpAddr, char>(open_br, ip_addr, clos_br)
.map(|t| match t { (_, ip, _) => ip })
};
p.read_or([ipv4_p, ipv6_p])
p.read_or(&mut [ipv4_p, ipv6_p])
};
let colon = |p: &mut Parser| p.read_given_char(':');
let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);

View File

@ -703,7 +703,7 @@ pub trait RandomAccessIterator<A>: Iterator<A> {
fn indexable(&self) -> uint;
/// Return an element at an index
fn idx(&self, index: uint) -> Option<A>;
fn idx(&mut self, index: uint) -> Option<A>;
}
/// An iterator that knows its exact length
@ -771,8 +771,9 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
#[inline]
fn indexable(&self) -> uint { self.iter.indexable() }
#[inline]
fn idx(&self, index: uint) -> Option<A> {
self.iter.idx(self.indexable() - index - 1)
fn idx(&mut self, index: uint) -> Option<A> {
let amt = self.indexable();
self.iter.idx(amt - index - 1)
}
}
@ -1071,7 +1072,7 @@ impl<A, T: Clone + RandomAccessIterator<A>> RandomAccessIterator<A> for Cycle<T>
}
#[inline]
fn idx(&self, index: uint) -> Option<A> {
fn idx(&mut self, index: uint) -> Option<A> {
let liter = self.iter.indexable();
let lorig = self.orig.indexable();
if lorig == 0 {
@ -1143,7 +1144,7 @@ for Chain<T, U> {
}
#[inline]
fn idx(&self, index: uint) -> Option<A> {
fn idx(&mut self, index: uint) -> Option<A> {
let len = self.a.indexable();
if index < len {
self.a.idx(index)
@ -1221,7 +1222,7 @@ RandomAccessIterator<(A, B)> for Zip<T, U> {
}
#[inline]
fn idx(&self, index: uint) -> Option<(A, B)> {
fn idx(&mut self, index: uint) -> Option<(A, B)> {
match self.a.idx(index) {
None => None,
Some(x) => match self.b.idx(index) {
@ -1240,7 +1241,7 @@ pub struct Map<'a, A, B, T> {
impl<'a, A, B, T> Map<'a, A, B, T> {
#[inline]
fn do_map(&self, elt: Option<A>) -> Option<B> {
fn do_map(&mut self, elt: Option<A>) -> Option<B> {
match elt {
Some(a) => Some((self.f)(a)),
_ => None
@ -1276,8 +1277,9 @@ impl<'a, A, B, T: RandomAccessIterator<A>> RandomAccessIterator<B> for Map<'a, A
}
#[inline]
fn idx(&self, index: uint) -> Option<B> {
self.do_map(self.iter.idx(index))
fn idx(&mut self, index: uint) -> Option<B> {
let elt = self.iter.idx(index);
self.do_map(elt)
}
}
@ -1415,7 +1417,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<(uint, A)> for Enumerat
}
#[inline]
fn idx(&self, index: uint) -> Option<(uint, A)> {
fn idx(&mut self, index: uint) -> Option<(uint, A)> {
match self.iter.idx(index) {
Some(a) => Some((self.count + index, a)),
_ => None,
@ -1600,7 +1602,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
}
#[inline]
fn idx(&self, index: uint) -> Option<A> {
fn idx(&mut self, index: uint) -> Option<A> {
if index >= self.indexable() {
None
} else {
@ -1649,7 +1651,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Take<T> {
}
#[inline]
fn idx(&self, index: uint) -> Option<A> {
fn idx(&mut self, index: uint) -> Option<A> {
if index >= self.n {
None
} else {
@ -1799,7 +1801,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Fuse<T> {
}
#[inline]
fn idx(&self, index: uint) -> Option<A> {
fn idx(&mut self, index: uint) -> Option<A> {
self.iter.idx(index)
}
}
@ -1822,7 +1824,7 @@ pub struct Inspect<'a, A, T> {
impl<'a, A, T> Inspect<'a, A, T> {
#[inline]
fn do_inspect(&self, elt: Option<A>) -> Option<A> {
fn do_inspect(&mut self, elt: Option<A>) -> Option<A> {
match elt {
Some(ref a) => (self.f)(a),
None => ()
@ -1862,8 +1864,9 @@ for Inspect<'a, A, T> {
}
#[inline]
fn idx(&self, index: uint) -> Option<A> {
self.do_inspect(self.iter.idx(index))
fn idx(&mut self, index: uint) -> Option<A> {
let element = self.iter.idx(index);
self.do_inspect(element)
}
}
@ -2164,7 +2167,7 @@ impl<A: Clone> RandomAccessIterator<A> for Repeat<A> {
#[inline]
fn indexable(&self) -> uint { uint::MAX }
#[inline]
fn idx(&self, _: uint) -> Option<A> { Some(self.element.clone()) }
fn idx(&mut self, _: uint) -> Option<A> { Some(self.element.clone()) }
}
/// Functions for lexicographical ordering of sequences.
@ -2907,7 +2910,7 @@ mod tests {
let xs = [1, 2, 3, 4, 5];
// test .map and .inspect that don't implement Clone
let it = xs.iter().inspect(|_| {});
let mut it = xs.iter().inspect(|_| {});
assert_eq!(xs.len(), it.indexable());
for (i, elt) in xs.iter().enumerate() {
assert_eq!(Some(elt), it.idx(i));
@ -2919,7 +2922,7 @@ mod tests {
fn test_random_access_map() {
let xs = [1, 2, 3, 4, 5];
let it = xs.iter().map(|x| *x);
let mut it = xs.iter().map(|x| *x);
assert_eq!(xs.len(), it.indexable());
for (i, elt) in xs.iter().enumerate() {
assert_eq!(Some(*elt), it.idx(i));

View File

@ -873,9 +873,9 @@ mod tests {
assert_eq!(v, None);
// test that it does not take more elements than it needs
let functions = [|| Some(()), || None, || fail!()];
let mut functions = [|| Some(()), || None, || fail!()];
let v: Option<~[()]> = collect(functions.iter().map(|f| (*f)()));
let v: Option<~[()]> = collect(functions.mut_iter().map(|f| (*f)()));
assert_eq!(v, None);
}

View File

@ -695,9 +695,9 @@ mod tests {
assert_eq!(v, Err(2));
// test that it does not take more elements than it needs
let functions = [|| Ok(()), || Err(1), || fail!()];
let mut functions = [|| Ok(()), || Err(1), || fail!()];
let v: Result<~[()], int> = collect(functions.iter().map(|f| (*f)()));
let v: Result<~[()], int> = collect(functions.mut_iter().map(|f| (*f)()));
assert_eq!(v, Err(1));
}
@ -715,9 +715,9 @@ mod tests {
Err(2));
// test that it does not take more elements than it needs
let functions = [|| Ok(()), || Err(1), || fail!()];
let mut functions = [|| Ok(()), || Err(1), || fail!()];
assert_eq!(fold_(functions.iter()
assert_eq!(fold_(functions.mut_iter()
.map(|f| (*f)())),
Err(1));
}

View File

@ -109,7 +109,7 @@ impl Task {
/// This function is *not* meant to be abused as a "try/catch" block. This
/// is meant to be used at the absolute boundaries of a task's lifetime, and
/// only for that purpose.
pub fn run(~self, f: ||) -> ~Task {
pub fn run(~self, mut f: ||) -> ~Task {
// Need to put ourselves into TLS, but also need access to the unwinder.
// Unsafely get a handle to the task so we can continue to use it after
// putting it in tls (so we can invoke the unwinder).

View File

@ -212,8 +212,7 @@ impl<'a, T> Iterator<&'a [T]> for RevSplits<'a, T> {
return Some(self.v);
}
let pred = &mut self.pred;
match self.v.iter().rposition(|x| (*pred)(x)) {
match self.v.iter().rposition(|x| (self.pred)(x)) {
None => {
self.finished = true;
Some(self.v)
@ -489,7 +488,7 @@ impl<'a, T> RandomAccessIterator<&'a [T]> for Chunks<'a, T> {
}
#[inline]
fn idx(&self, index: uint) -> Option<&'a [T]> {
fn idx(&mut self, index: uint) -> Option<&'a [T]> {
if index < self.indexable() {
let lo = index * self.size;
let mut hi = lo + self.size;
@ -2101,7 +2100,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
}
#[inline]
fn idx(&self, index: uint) -> Option<&'a T> {
fn idx(&mut self, index: uint) -> Option<&'a T> {
unsafe {
if index < self.indexable() {
transmute(self.ptr.offset(index as int))
@ -2138,7 +2137,8 @@ impl<'a, T> Iterator<&'a mut [T]> for MutSplits<'a, T> {
fn next(&mut self) -> Option<&'a mut [T]> {
if self.finished { return None; }
match self.v.iter().position(|x| (self.pred)(x)) {
let pred = &mut self.pred;
match self.v.iter().position(|x| (*pred)(x)) {
None => {
self.finished = true;
let tmp = mem::replace(&mut self.v, &mut []);
@ -2173,7 +2173,8 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T> {
fn next_back(&mut self) -> Option<&'a mut [T]> {
if self.finished { return None; }
match self.v.iter().rposition(|x| (self.pred)(x)) {
let pred = &mut self.pred;
match self.v.iter().rposition(|x| (*pred)(x)) {
None => {
self.finished = true;
let tmp = mem::replace(&mut self.v, &mut []);
@ -3346,7 +3347,7 @@ mod tests {
assert_eq!(v.chunks(6).collect::<~[&[int]]>(), ~[&[1i,2,3,4,5]]);
assert_eq!(v.chunks(2).rev().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]);
let it = v.chunks(2);
let mut it = v.chunks(2);
assert_eq!(it.indexable(), 3);
assert_eq!(it.idx(0).unwrap(), &[1,2]);
assert_eq!(it.idx(1).unwrap(), &[3,4]);

View File

@ -217,7 +217,7 @@ impl<'a, S: Str> StrVector for Vec<S> {
/// Something that can be used to compare against a character
pub trait CharEq {
/// Determine if the splitter should split at the given character
fn matches(&self, char) -> bool;
fn matches(&mut self, char) -> bool;
/// Indicate if this is only concerned about ASCII characters,
/// which can allow for a faster implementation.
fn only_ascii(&self) -> bool;
@ -225,7 +225,7 @@ pub trait CharEq {
impl CharEq for char {
#[inline]
fn matches(&self, c: char) -> bool { *self == c }
fn matches(&mut self, c: char) -> bool { *self == c }
#[inline]
fn only_ascii(&self) -> bool { (*self as uint) < 128 }
@ -233,7 +233,7 @@ impl CharEq for char {
impl<'a> CharEq for |char|: 'a -> bool {
#[inline]
fn matches(&self, c: char) -> bool { (*self)(c) }
fn matches(&mut self, c: char) -> bool { (*self)(c) }
#[inline]
fn only_ascii(&self) -> bool { false }
@ -241,16 +241,16 @@ impl<'a> CharEq for |char|: 'a -> bool {
impl CharEq for extern "Rust" fn(char) -> bool {
#[inline]
fn matches(&self, c: char) -> bool { (*self)(c) }
fn matches(&mut self, c: char) -> bool { (*self)(c) }
#[inline]
fn only_ascii(&self) -> bool { false }
}
impl<'a, C: CharEq> CharEq for &'a [C] {
impl<'a> CharEq for &'a [char] {
#[inline]
fn matches(&self, c: char) -> bool {
self.iter().any(|m| m.matches(c))
fn matches(&mut self, c: char) -> bool {
self.iter().any(|&mut m| m.matches(c))
}
#[inline]
@ -1981,11 +1981,11 @@ pub trait StrSlice<'a> {
/// # Example
///
/// ```rust
/// assert_eq!("11foo1bar11".trim_chars(&'1'), "foo1bar")
/// assert_eq!("12foo1bar12".trim_chars(& &['1', '2']), "foo1bar")
/// assert_eq!("123foo1bar123".trim_chars(&|c: char| c.is_digit()), "foo1bar")
/// assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar")
/// assert_eq!("12foo1bar12".trim_chars(&['1', '2']), "foo1bar")
/// assert_eq!("123foo1bar123".trim_chars(|c: char| c.is_digit()), "foo1bar")
/// ```
fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'a str;
fn trim_chars<C: CharEq>(&self, to_trim: C) -> &'a str;
/// Returns a string with leading `chars_to_trim` removed.
///
@ -1996,11 +1996,11 @@ pub trait StrSlice<'a> {
/// # Example
///
/// ```rust
/// assert_eq!("11foo1bar11".trim_left_chars(&'1'), "foo1bar11")
/// assert_eq!("12foo1bar12".trim_left_chars(& &['1', '2']), "foo1bar12")
/// assert_eq!("123foo1bar123".trim_left_chars(&|c: char| c.is_digit()), "foo1bar123")
/// assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11")
/// assert_eq!("12foo1bar12".trim_left_chars(&['1', '2']), "foo1bar12")
/// assert_eq!("123foo1bar123".trim_left_chars(|c: char| c.is_digit()), "foo1bar123")
/// ```
fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'a str;
fn trim_left_chars<C: CharEq>(&self, to_trim: C) -> &'a str;
/// Returns a string with trailing `chars_to_trim` removed.
///
@ -2011,11 +2011,11 @@ pub trait StrSlice<'a> {
/// # Example
///
/// ```rust
/// assert_eq!("11foo1bar11".trim_right_chars(&'1'), "11foo1bar")
/// assert_eq!("12foo1bar12".trim_right_chars(& &['1', '2']), "12foo1bar")
/// assert_eq!("123foo1bar123".trim_right_chars(&|c: char| c.is_digit()), "123foo1bar")
/// assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar")
/// assert_eq!("12foo1bar12".trim_right_chars(&['1', '2']), "12foo1bar")
/// assert_eq!("123foo1bar123".trim_right_chars(|c: char| c.is_digit()), "123foo1bar")
/// ```
fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'a str;
fn trim_right_chars<C: CharEq>(&self, to_trim: C) -> &'a str;
/// Replace all occurrences of one string with another.
///
@ -2491,21 +2491,31 @@ impl<'a> StrSlice<'a> for &'a str {
#[inline]
fn trim_left(&self) -> &'a str {
self.trim_left_chars(&char::is_whitespace)
self.trim_left_chars(char::is_whitespace)
}
#[inline]
fn trim_right(&self) -> &'a str {
self.trim_right_chars(&char::is_whitespace)
self.trim_right_chars(char::is_whitespace)
}
#[inline]
fn trim_chars<C: CharEq>(&self, to_trim: &C) -> &'a str {
self.trim_left_chars(to_trim).trim_right_chars(to_trim)
fn trim_chars<C: CharEq>(&self, mut to_trim: C) -> &'a str {
let cur = match self.find(|c: char| !to_trim.matches(c)) {
None => "",
Some(i) => unsafe { raw::slice_bytes(*self, i, self.len()) }
};
match cur.rfind(|c: char| !to_trim.matches(c)) {
None => "",
Some(i) => {
let right = cur.char_range_at(i).next;
unsafe { raw::slice_bytes(cur, 0, right) }
}
}
}
#[inline]
fn trim_left_chars<C: CharEq>(&self, to_trim: &C) -> &'a str {
fn trim_left_chars<C: CharEq>(&self, mut to_trim: C) -> &'a str {
match self.find(|c: char| !to_trim.matches(c)) {
None => "",
Some(first) => unsafe { raw::slice_bytes(*self, first, self.len()) }
@ -2513,7 +2523,7 @@ impl<'a> StrSlice<'a> for &'a str {
}
#[inline]
fn trim_right_chars<C: CharEq>(&self, to_trim: &C) -> &'a str {
fn trim_right_chars<C: CharEq>(&self, mut to_trim: C) -> &'a str {
match self.rfind(|c: char| !to_trim.matches(c)) {
None => "",
Some(last) => {
@ -2631,7 +2641,7 @@ impl<'a> StrSlice<'a> for &'a str {
unsafe { cast::transmute(*self) }
}
fn find<C: CharEq>(&self, search: C) -> Option<uint> {
fn find<C: CharEq>(&self, mut search: C) -> Option<uint> {
if search.only_ascii() {
self.bytes().position(|b| search.matches(b as char))
} else {
@ -2642,7 +2652,7 @@ impl<'a> StrSlice<'a> for &'a str {
}
}
fn rfind<C: CharEq>(&self, search: C) -> Option<uint> {
fn rfind<C: CharEq>(&self, mut search: C) -> Option<uint> {
if search.only_ascii() {
self.bytes().rposition(|b| search.matches(b as char))
} else {
@ -3160,40 +3170,40 @@ mod tests {
#[test]
fn test_trim_left_chars() {
let v: &[char] = &[];
assert_eq!(" *** foo *** ".trim_left_chars(&v), " *** foo *** ");
assert_eq!(" *** foo *** ".trim_left_chars(& &['*', ' ']), "foo *** ");
assert_eq!(" *** *** ".trim_left_chars(& &['*', ' ']), "");
assert_eq!("foo *** ".trim_left_chars(& &['*', ' ']), "foo *** ");
assert_eq!(" *** foo *** ".trim_left_chars(v), " *** foo *** ");
assert_eq!(" *** foo *** ".trim_left_chars(&['*', ' ']), "foo *** ");
assert_eq!(" *** *** ".trim_left_chars(&['*', ' ']), "");
assert_eq!("foo *** ".trim_left_chars(&['*', ' ']), "foo *** ");
assert_eq!("11foo1bar11".trim_left_chars(&'1'), "foo1bar11");
assert_eq!("12foo1bar12".trim_left_chars(& &['1', '2']), "foo1bar12");
assert_eq!("123foo1bar123".trim_left_chars(&|c: char| c.is_digit()), "foo1bar123");
assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11");
assert_eq!("12foo1bar12".trim_left_chars(&['1', '2']), "foo1bar12");
assert_eq!("123foo1bar123".trim_left_chars(|c: char| c.is_digit()), "foo1bar123");
}
#[test]
fn test_trim_right_chars() {
let v: &[char] = &[];
assert_eq!(" *** foo *** ".trim_right_chars(&v), " *** foo *** ");
assert_eq!(" *** foo *** ".trim_right_chars(& &['*', ' ']), " *** foo");
assert_eq!(" *** *** ".trim_right_chars(& &['*', ' ']), "");
assert_eq!(" *** foo".trim_right_chars(& &['*', ' ']), " *** foo");
assert_eq!(" *** foo *** ".trim_right_chars(v), " *** foo *** ");
assert_eq!(" *** foo *** ".trim_right_chars(&['*', ' ']), " *** foo");
assert_eq!(" *** *** ".trim_right_chars(&['*', ' ']), "");
assert_eq!(" *** foo".trim_right_chars(&['*', ' ']), " *** foo");
assert_eq!("11foo1bar11".trim_right_chars(&'1'), "11foo1bar");
assert_eq!("12foo1bar12".trim_right_chars(& &['1', '2']), "12foo1bar");
assert_eq!("123foo1bar123".trim_right_chars(&|c: char| c.is_digit()), "123foo1bar");
assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar");
assert_eq!("12foo1bar12".trim_right_chars(&['1', '2']), "12foo1bar");
assert_eq!("123foo1bar123".trim_right_chars(|c: char| c.is_digit()), "123foo1bar");
}
#[test]
fn test_trim_chars() {
let v: &[char] = &[];
assert_eq!(" *** foo *** ".trim_chars(&v), " *** foo *** ");
assert_eq!(" *** foo *** ".trim_chars(& &['*', ' ']), "foo");
assert_eq!(" *** *** ".trim_chars(& &['*', ' ']), "");
assert_eq!("foo".trim_chars(& &['*', ' ']), "foo");
assert_eq!(" *** foo *** ".trim_chars(v), " *** foo *** ");
assert_eq!(" *** foo *** ".trim_chars(&['*', ' ']), "foo");
assert_eq!(" *** *** ".trim_chars(&['*', ' ']), "");
assert_eq!("foo".trim_chars(&['*', ' ']), "foo");
assert_eq!("11foo1bar11".trim_chars(&'1'), "foo1bar");
assert_eq!("12foo1bar12".trim_chars(& &['1', '2']), "foo1bar");
assert_eq!("123foo1bar123".trim_chars(&|c: char| c.is_digit()), "foo1bar");
assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar");
assert_eq!("12foo1bar12".trim_chars(&['1', '2']), "foo1bar");
assert_eq!("123foo1bar123".trim_chars(|c: char| c.is_digit()), "foo1bar");
}
#[test]
@ -4123,7 +4133,7 @@ mod bench {
fn split_unicode_not_ascii(b: &mut Bencher) {
struct NotAscii(char);
impl CharEq for NotAscii {
fn matches(&self, c: char) -> bool {
fn matches(&mut self, c: char) -> bool {
let NotAscii(cc) = *self;
cc == c
}
@ -4148,7 +4158,7 @@ mod bench {
struct NotAscii(char);
impl CharEq for NotAscii {
#[inline]
fn matches(&self, c: char) -> bool {
fn matches(&mut self, c: char) -> bool {
let NotAscii(cc) = *self;
cc == c
}

View File

@ -35,19 +35,19 @@ use ops::Drop;
#[cfg(test)] use task::failing;
pub trait Finally<T> {
fn finally(&self, dtor: ||) -> T;
fn finally(&mut self, dtor: ||) -> T;
}
impl<'a,T> Finally<T> for ||: 'a -> T {
fn finally(&self, dtor: ||) -> T {
try_finally(&mut (), (),
|_, _| (*self)(),
fn finally(&mut self, dtor: ||) -> T {
try_finally(&mut (), self,
|_, f| (*f)(),
|_| dtor())
}
}
impl<T> Finally<T> for fn() -> T {
fn finally(&self, dtor: ||) -> T {
fn finally(&mut self, dtor: ||) -> T {
try_finally(&mut (), (),
|_, _| (*self)(),
|_| dtor())
@ -145,7 +145,7 @@ fn test_fail() {
#[test]
fn test_retval() {
let closure: || -> int = || 10;
let mut closure: || -> int = || 10;
let i = closure.finally(|| { });
assert_eq!(i, 10);
}
@ -154,6 +154,6 @@ fn test_retval() {
fn test_compact() {
fn do_some_fallible_work() {}
fn but_always_run_this_function() { }
do_some_fallible_work.finally(
but_always_run_this_function);
let mut f = do_some_fallible_work;
f.finally(but_always_run_this_function);
}

View File

@ -34,7 +34,9 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt,
ret_ty: Self,
inline: true,
const_nonmatching: false,
combine_substructure: |c, s, sub| cs_clone("Clone", c, s, sub)
combine_substructure: combine_substructure(|c, s, sub| {
cs_clone("Clone", c, s, sub)
}),
}
)
};

View File

@ -40,7 +40,9 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt,
ret_ty: Literal(Path::new(vec!("bool"))),
inline: true,
const_nonmatching: true,
combine_substructure: $f
combine_substructure: combine_substructure(|a, b, c| {
$f(a, b, c)
})
}
}
);

View File

@ -30,7 +30,9 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt,
ret_ty: Literal(Path::new(vec!("bool"))),
inline: true,
const_nonmatching: false,
combine_substructure: |cx, span, substr| cs_op($op, $equal, cx, span, substr)
combine_substructure: combine_substructure(|cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
})
}
}
);

View File

@ -48,7 +48,9 @@ pub fn expand_deriving_totaleq(cx: &mut ExtCtxt,
ret_ty: nil_ty(),
inline: true,
const_nonmatching: true,
combine_substructure: cs_total_eq_assert
combine_substructure: combine_substructure(|a, b, c| {
cs_total_eq_assert(a, b, c)
})
}
)
};

View File

@ -37,7 +37,9 @@ pub fn expand_deriving_totalord(cx: &mut ExtCtxt,
ret_ty: Literal(Path::new(vec!("std", "cmp", "Ordering"))),
inline: true,
const_nonmatching: false,
combine_substructure: cs_cmp
combine_substructure: combine_substructure(|a, b, c| {
cs_cmp(a, b, c)
}),
}
)
};

View File

@ -52,7 +52,9 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
vec!(~Self, ~Literal(Path::new_local("__E"))), true)),
inline: false,
const_nonmatching: true,
combine_substructure: decodable_substructure,
combine_substructure: combine_substructure(|a, b, c| {
decodable_substructure(a, b, c)
}),
})
};

View File

@ -34,7 +34,9 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
ret_ty: Self,
inline: true,
const_nonmatching: false,
combine_substructure: default_substructure
combine_substructure: combine_substructure(|a, b, c| {
default_substructure(a, b, c)
})
})
};
trait_def.expand(cx, mitem, item, push)

View File

@ -123,7 +123,9 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
true)),
inline: false,
const_nonmatching: true,
combine_substructure: encodable_substructure,
combine_substructure: combine_substructure(|a, b, c| {
encodable_substructure(a, b, c)
}),
})
};

View File

@ -177,6 +177,8 @@ StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span
*/
use std::cell::RefCell;
use ast;
use ast::{P, EnumDef, Expr, Ident, Generics, StructDef};
use ast_util;
@ -234,7 +236,7 @@ pub struct MethodDef<'a> {
/// actual enum variants, i.e. can use _ => .. match.
pub const_nonmatching: bool,
pub combine_substructure: CombineSubstructureFunc<'a>,
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
}
/// All the data about the data structure/method being derived upon.
@ -317,6 +319,11 @@ pub type EnumNonMatchFunc<'a> =
&[@Expr]|: 'a
-> @Expr;
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
-> RefCell<CombineSubstructureFunc<'a>> {
RefCell::new(f)
}
impl<'a> TraitDef<'a> {
pub fn expand(&self,
@ -509,8 +516,9 @@ impl<'a> MethodDef<'a> {
nonself_args: nonself_args,
fields: fields
};
(self.combine_substructure)(cx, trait_.span,
&substructure)
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc = &mut *f;
(*f)(cx, trait_.span, &substructure)
}
fn get_ret_ty(&self,

View File

@ -49,7 +49,9 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
ret_ty: nil_ty(),
inline: true,
const_nonmatching: false,
combine_substructure: hash_substructure
combine_substructure: combine_substructure(|a, b, c| {
hash_substructure(a, b, c)
})
}
)
};

View File

@ -41,7 +41,9 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
// liable to cause code-bloat
inline: true,
const_nonmatching: false,
combine_substructure: |c, s, sub| cs_from("i64", c, s, sub),
combine_substructure: combine_substructure(|c, s, sub| {
cs_from("i64", c, s, sub)
}),
},
MethodDef {
name: "from_u64",
@ -56,7 +58,9 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
// liable to cause code-bloat
inline: true,
const_nonmatching: false,
combine_substructure: |c, s, sub| cs_from("u64", c, s, sub),
combine_substructure: combine_substructure(|c, s, sub| {
cs_from("u64", c, s, sub)
}),
})
};

View File

@ -43,7 +43,9 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
ret_ty: Self,
inline: false,
const_nonmatching: false,
combine_substructure: rand_substructure
combine_substructure: combine_substructure(|a, b, c| {
rand_substructure(a, b, c)
})
}
)
};

View File

@ -44,7 +44,9 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt,
ret_ty: Literal(Path::new(vec!("std", "fmt", "Result"))),
inline: false,
const_nonmatching: false,
combine_substructure: show_substructure
combine_substructure: combine_substructure(|a, b, c| {
show_substructure(a, b, c)
})
}
)
};

View File

@ -34,7 +34,9 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
ret_ty: Self,
inline: true,
const_nonmatching: false,
combine_substructure: zero_substructure
combine_substructure: combine_substructure(|a, b, c| {
zero_substructure(a, b, c)
})
},
MethodDef {
name: "is_zero",
@ -44,13 +46,13 @@ pub fn expand_deriving_zero(cx: &mut ExtCtxt,
ret_ty: Literal(Path::new(vec!("bool"))),
inline: true,
const_nonmatching: false,
combine_substructure: |cx, span, substr| {
combine_substructure: combine_substructure(|cx, span, substr| {
cs_and(|cx, span, _, _| cx.span_bug(span,
"Non-matching enum \
variant in \
deriving(Zero)"),
cx, span, substr)
}
})
}
)
};

View File

@ -0,0 +1,64 @@
// 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.
// Ensure that invoking a closure counts as a unique immutable borrow
type Fn<'a> = ||:'a;
struct Test<'a> {
f: ||: 'a
}
fn call(f: |Fn|) {
f(|| {
//~^ ERROR: closure requires unique access to `f` but it is already borrowed
f(|| {})
});
}
fn test1() {
call(|a| {
a();
});
}
fn test2(f: &||) {
(*f)(); //~ ERROR: closure invocation in a `&` reference
}
fn test3(f: &mut ||) {
(*f)();
}
fn test4(f: &Test) {
(f.f)() //~ ERROR: closure invocation in a `&` reference
}
fn test5(f: &mut Test) {
(f.f)()
}
fn test6() {
let f = || {};
(|| {
f();
})();
}
fn test7() {
fn foo(_: |g: |int|, b: int|) {}
let f = |g: |int|, b: int| {};
f(|a| { //~ ERROR: cannot borrow `f` as immutable because previous closure
foo(f); //~ ERROR: cannot move out of captured outer variable
}, 3);
}
fn main() {}

View File

@ -16,7 +16,7 @@ struct R<'a> {
// This struct is needed to create the
// otherwise infinite type of a fn that
// accepts itself as argument:
c: |&R, bool|: 'a
c: |&mut R, bool|: 'a
}
fn innocent_looking_victim() {
@ -28,6 +28,7 @@ fn innocent_looking_victim() {
match x {
Some(ref msg) => {
(f.c)(f, true);
//~^ ERROR: cannot borrow `*f` as mutable because
println!("{:?}", msg);
},
None => fail!("oops"),
@ -36,9 +37,9 @@ fn innocent_looking_victim() {
})
}
fn conspirator(f: |&R, bool|) {
let r = R {c: f};
f(&r, false) //~ ERROR use of moved value
fn conspirator(f: |&mut R, bool|) {
let mut r = R {c: f};
f(&mut r, false) //~ ERROR use of moved value
}
fn main() { innocent_looking_victim() }

View File

@ -18,13 +18,13 @@
fn f() { }
static bare_fns: &'static [fn()] = &[f, f];
struct S<'a>(||:'a);
static mut closures: &'static [S<'static>] = &[S(f), S(f)];
static mut closures: &'static mut [S<'static>] = &mut [S(f), S(f)];
pub fn main() {
unsafe {
for &bare_fn in bare_fns.iter() { bare_fn() }
for closure in closures.iter() {
let S(ref closure) = *closure;
for closure in closures.mut_iter() {
let S(ref mut closure) = *closure;
(*closure)()
}
}

View File

@ -8,23 +8,23 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub trait OpInt<'a> { fn call<'a>(&'a self, int, int) -> int; }
pub trait OpInt<'a> { fn call<'a>(&'a mut self, int, int) -> int; }
impl<'a> OpInt<'a> for |int, int|: 'a -> int {
fn call(&self, a:int, b:int) -> int {
fn call(&mut self, a:int, b:int) -> int {
(*self)(a, b)
}
}
fn squarei<'a>(x: int, op: &'a OpInt) -> int { op.call(x, x) }
fn squarei<'a>(x: int, op: &'a mut OpInt) -> int { op.call(x, x) }
fn muli(x:int, y:int) -> int { x * y }
pub fn main() {
let f = |x,y| muli(x,y);
let mut f = |x,y| muli(x,y);
{
let g = &f;
let h = g as &OpInt;
let g = &mut f;
let h = g as &mut OpInt;
squarei(3, h);
}
}