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:
commit
6beb376b5c
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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()),
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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, ());
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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).
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
}),
|
||||
}
|
||||
)
|
||||
};
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
)
|
||||
};
|
||||
|
@ -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)
|
||||
}),
|
||||
}
|
||||
)
|
||||
};
|
||||
|
@ -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)
|
||||
}),
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}),
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
)
|
||||
};
|
||||
|
@ -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)
|
||||
}),
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
)
|
||||
};
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
)
|
||||
};
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
};
|
||||
|
64
src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
Normal file
64
src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
Normal 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() {}
|
@ -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() }
|
||||
|
@ -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)()
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user