librustc: Allow &mut
to be loaned; allow self
to be loaned; make &mut
loanable to &
. r=nmatsakis
This commit is contained in:
parent
bbbb80559c
commit
ad25e208ee
29 changed files with 338 additions and 166 deletions
|
@ -14,6 +14,7 @@
|
||||||
#[forbid(deprecated_pattern)];
|
#[forbid(deprecated_pattern)];
|
||||||
#[warn(non_camel_case_types)];
|
#[warn(non_camel_case_types)];
|
||||||
|
|
||||||
|
use cast::transmute;
|
||||||
use cast;
|
use cast;
|
||||||
use cmp::{Eq, Ord};
|
use cmp::{Eq, Ord};
|
||||||
use iter::BaseIter;
|
use iter::BaseIter;
|
||||||
|
@ -477,14 +478,20 @@ pub fn shift<T>(v: &mut ~[T]) -> T {
|
||||||
// Memcopy the head element (the one we want) to the location we just
|
// Memcopy the head element (the one we want) to the location we just
|
||||||
// popped. For the moment it unsafely exists at both the head and last
|
// popped. For the moment it unsafely exists at both the head and last
|
||||||
// positions
|
// positions
|
||||||
let first_slice = view(*v, 0, 1);
|
{
|
||||||
let last_slice = mut_view(*v, next_ln, ln);
|
let first_slice = view(*v, 0, 1);
|
||||||
raw::copy_memory(last_slice, first_slice, 1);
|
let last_slice = view(*v, next_ln, ln);
|
||||||
|
raw::copy_memory(::cast::transmute(last_slice), first_slice, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Memcopy everything to the left one element
|
// Memcopy everything to the left one element
|
||||||
let init_slice = mut_view(*v, 0, next_ln);
|
{
|
||||||
let tail_slice = view(*v, 1, ln);
|
let init_slice = view(*v, 0, next_ln);
|
||||||
raw::copy_memory(init_slice, tail_slice, next_ln);
|
let tail_slice = view(*v, 1, ln);
|
||||||
|
raw::copy_memory(::cast::transmute(init_slice),
|
||||||
|
tail_slice,
|
||||||
|
next_ln);
|
||||||
|
}
|
||||||
|
|
||||||
// Set the new length. Now the vector is back to normal
|
// Set the new length. Now the vector is back to normal
|
||||||
raw::set_len(&mut *v, next_ln);
|
raw::set_len(&mut *v, next_ln);
|
||||||
|
|
|
@ -22,9 +22,9 @@ use core::prelude::*;
|
||||||
use middle::borrowck::{Loan, bckerr, borrowck_ctxt, cmt, inherent_mutability};
|
use middle::borrowck::{Loan, bckerr, borrowck_ctxt, cmt, inherent_mutability};
|
||||||
use middle::borrowck::{req_maps, save_and_restore};
|
use middle::borrowck::{req_maps, save_and_restore};
|
||||||
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
|
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
|
||||||
use middle::mem_categorization::{cat_local, cat_rvalue, cat_special, gc_ptr};
|
use middle::mem_categorization::{cat_local, cat_rvalue, cat_self};
|
||||||
use middle::mem_categorization::{loan_path, lp_arg, lp_comp, lp_deref};
|
use middle::mem_categorization::{cat_special, gc_ptr, loan_path, lp_arg};
|
||||||
use middle::mem_categorization::{lp_local};
|
use middle::mem_categorization::{lp_comp, lp_deref, lp_local};
|
||||||
use middle::ty::{CopyValue, MoveValue, ReadValue};
|
use middle::ty::{CopyValue, MoveValue, ReadValue};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use util::ppaux::ty_to_str;
|
use util::ppaux::ty_to_str;
|
||||||
|
@ -444,7 +444,7 @@ impl check_loan_ctxt {
|
||||||
self.check_for_loan_conflicting_with_assignment(
|
self.check_for_loan_conflicting_with_assignment(
|
||||||
at, ex, cmt, lp_base);
|
at, ex, cmt, lp_base);
|
||||||
}
|
}
|
||||||
lp_comp(*) | lp_local(*) | lp_arg(*) | lp_deref(*) => ()
|
lp_comp(*) | lp_self | lp_local(*) | lp_arg(*) | lp_deref(*) => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,16 +481,13 @@ impl check_loan_ctxt {
|
||||||
|
|
||||||
match cmt.cat {
|
match cmt.cat {
|
||||||
// Rvalues, locals, and arguments can be moved:
|
// Rvalues, locals, and arguments can be moved:
|
||||||
cat_rvalue | cat_local(_) | cat_arg(_) => {}
|
cat_rvalue | cat_local(_) | cat_arg(_) | cat_self(_) => {}
|
||||||
|
|
||||||
// We allow moving out of static items because the old code
|
// We allow moving out of static items because the old code
|
||||||
// did. This seems consistent with permitting moves out of
|
// did. This seems consistent with permitting moves out of
|
||||||
// rvalues, I guess.
|
// rvalues, I guess.
|
||||||
cat_special(sk_static_item) => {}
|
cat_special(sk_static_item) => {}
|
||||||
|
|
||||||
// We allow moving out of explicit self only.
|
|
||||||
cat_special(sk_self) => {}
|
|
||||||
|
|
||||||
cat_deref(_, _, unsafe_ptr) => {}
|
cat_deref(_, _, unsafe_ptr) => {}
|
||||||
|
|
||||||
// Nothing else.
|
// Nothing else.
|
||||||
|
|
|
@ -480,13 +480,44 @@ impl gather_loan_ctxt {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normally we wouldn't allow `re_free` here. However, in this case
|
||||||
|
// it should be sound. Below is nmatsakis' reasoning:
|
||||||
|
//
|
||||||
|
// Perhaps [this permits] a function kind of like this one here, which
|
||||||
|
// consumes one mut pointer and returns a narrower one:
|
||||||
|
//
|
||||||
|
// struct Foo { f: int }
|
||||||
|
// fn foo(p: &v/mut Foo) -> &v/mut int { &mut p.f }
|
||||||
|
//
|
||||||
|
// I think this should work fine but there is more subtlety to it than
|
||||||
|
// I at first imagined. Unfortunately it's a very important use case,
|
||||||
|
// I think, so it really ought to work. The changes you [pcwalton]
|
||||||
|
// made to permit re_free() do permit this case, I think, but I'm not
|
||||||
|
// sure what else they permit. I have to think that over a bit.
|
||||||
|
//
|
||||||
|
// Ordinarily, a loan with scope re_free wouldn't make sense, because
|
||||||
|
// you couldn't enforce it. But in this case, your function signature
|
||||||
|
// informs the caller that you demand exclusive access to p and its
|
||||||
|
// contents for the lifetime v. Since borrowed pointers are
|
||||||
|
// non-copyable, they must have (a) made a borrow which will enforce
|
||||||
|
// those conditions and then (b) given you the resulting pointer.
|
||||||
|
// Therefore, they should be respecting the loan. So it actually seems
|
||||||
|
// that it's ok in this case to have a loan with re_free, so long as
|
||||||
|
// the scope of the loan is no greater than the region pointer on
|
||||||
|
// which it is based. Neat but not something I had previously
|
||||||
|
// considered all the way through. (Note that we already rely on
|
||||||
|
// similar reasoning to permit you to return borrowed pointers into
|
||||||
|
// immutable structures, this is just the converse I suppose)
|
||||||
|
|
||||||
let scope_id = match scope_r {
|
let scope_id = match scope_r {
|
||||||
ty::re_scope(scope_id) => scope_id,
|
ty::re_scope(scope_id) | ty::re_free(scope_id, _) => scope_id,
|
||||||
_ => {
|
_ => {
|
||||||
self.bccx.tcx.sess.span_bug(
|
self.bccx.tcx.sess.span_bug(
|
||||||
cmt.span,
|
cmt.span,
|
||||||
fmt!("loans required but scope is scope_region is %s",
|
fmt!("loans required but scope is scope_region is %s \
|
||||||
region_to_str(self.tcx(), scope_r)));
|
(%?)",
|
||||||
|
region_to_str(self.tcx(), scope_r),
|
||||||
|
scope_r));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use core::prelude::*;
|
||||||
use middle::borrowck::{Loan, bckres, borrowck_ctxt, cmt, err_mutbl};
|
use middle::borrowck::{Loan, bckres, borrowck_ctxt, cmt, err_mutbl};
|
||||||
use middle::borrowck::{err_out_of_scope};
|
use middle::borrowck::{err_out_of_scope};
|
||||||
use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp};
|
use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp};
|
||||||
use middle::mem_categorization::{cat_deref, cat_discr, cat_local};
|
use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self};
|
||||||
use middle::mem_categorization::{cat_special, cat_stack_upvar, comp_field};
|
use middle::mem_categorization::{cat_special, cat_stack_upvar, comp_field};
|
||||||
use middle::mem_categorization::{comp_index, comp_variant, gc_ptr};
|
use middle::mem_categorization::{comp_index, comp_variant, gc_ptr};
|
||||||
use middle::mem_categorization::{region_ptr};
|
use middle::mem_categorization::{region_ptr};
|
||||||
|
@ -121,7 +121,7 @@ impl LoanContext {
|
||||||
cmt.span,
|
cmt.span,
|
||||||
~"rvalue with a non-none lp");
|
~"rvalue with a non-none lp");
|
||||||
}
|
}
|
||||||
cat_local(local_id) | cat_arg(local_id) => {
|
cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => {
|
||||||
let local_scope_id = self.tcx().region_map.get(local_id);
|
let local_scope_id = self.tcx().region_map.get(local_id);
|
||||||
self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl)
|
self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl)
|
||||||
}
|
}
|
||||||
|
@ -162,9 +162,18 @@ impl LoanContext {
|
||||||
// then the memory is freed.
|
// then the memory is freed.
|
||||||
self.loan_unstable_deref(cmt, cmt_base, req_mutbl)
|
self.loan_unstable_deref(cmt, cmt_base, req_mutbl)
|
||||||
}
|
}
|
||||||
|
cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => {
|
||||||
|
// Mutable data can be loaned out as immutable or const. We must
|
||||||
|
// loan out the base as well as the main memory. For example,
|
||||||
|
// if someone borrows `*b`, we want to borrow `b` as immutable
|
||||||
|
// as well.
|
||||||
|
do self.loan(cmt_base, m_imm).chain |_| {
|
||||||
|
self.issue_loan(cmt, region, m_const)
|
||||||
|
}
|
||||||
|
}
|
||||||
cat_deref(_, _, unsafe_ptr) |
|
cat_deref(_, _, unsafe_ptr) |
|
||||||
cat_deref(_, _, gc_ptr(_)) |
|
cat_deref(_, _, gc_ptr(_)) |
|
||||||
cat_deref(_, _, region_ptr(_)) => {
|
cat_deref(_, _, region_ptr(_, _)) => {
|
||||||
// Aliased data is simply not lendable.
|
// Aliased data is simply not lendable.
|
||||||
self.bccx.tcx.sess.span_bug(
|
self.bccx.tcx.sess.span_bug(
|
||||||
cmt.span,
|
cmt.span,
|
||||||
|
|
|
@ -20,7 +20,7 @@ use middle::borrowck::{cmt, err_mut_uniq, err_mut_variant};
|
||||||
use middle::borrowck::{err_out_of_root_scope, err_out_of_scope};
|
use middle::borrowck::{err_out_of_root_scope, err_out_of_scope};
|
||||||
use middle::borrowck::{err_root_not_permitted};
|
use middle::borrowck::{err_root_not_permitted};
|
||||||
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
|
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
|
||||||
use middle::mem_categorization::{cat_discr, cat_local, cat_special};
|
use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special};
|
||||||
use middle::mem_categorization::{cat_stack_upvar, comp_field, comp_index};
|
use middle::mem_categorization::{cat_stack_upvar, comp_field, comp_index};
|
||||||
use middle::mem_categorization::{comp_variant, gc_ptr, region_ptr};
|
use middle::mem_categorization::{comp_variant, gc_ptr, region_ptr};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
@ -90,7 +90,6 @@ priv impl &preserve_ctxt {
|
||||||
let _i = indenter();
|
let _i = indenter();
|
||||||
|
|
||||||
match cmt.cat {
|
match cmt.cat {
|
||||||
cat_special(sk_self) |
|
|
||||||
cat_special(sk_implicit_self) |
|
cat_special(sk_implicit_self) |
|
||||||
cat_special(sk_heap_upvar) => {
|
cat_special(sk_heap_upvar) => {
|
||||||
self.compare_scope(cmt, ty::re_scope(self.item_ub))
|
self.compare_scope(cmt, ty::re_scope(self.item_ub))
|
||||||
|
@ -148,6 +147,10 @@ priv impl &preserve_ctxt {
|
||||||
let local_scope_id = self.tcx().region_map.get(local_id);
|
let local_scope_id = self.tcx().region_map.get(local_id);
|
||||||
self.compare_scope(cmt, ty::re_scope(local_scope_id))
|
self.compare_scope(cmt, ty::re_scope(local_scope_id))
|
||||||
}
|
}
|
||||||
|
cat_self(local_id) => {
|
||||||
|
let local_scope_id = self.tcx().region_map.get(local_id);
|
||||||
|
self.compare_scope(cmt, ty::re_scope(local_scope_id))
|
||||||
|
}
|
||||||
cat_comp(cmt_base, comp_field(*)) |
|
cat_comp(cmt_base, comp_field(*)) |
|
||||||
cat_comp(cmt_base, comp_index(*)) |
|
cat_comp(cmt_base, comp_index(*)) |
|
||||||
cat_comp(cmt_base, comp_tuple) |
|
cat_comp(cmt_base, comp_tuple) |
|
||||||
|
@ -171,7 +174,7 @@ priv impl &preserve_ctxt {
|
||||||
// freed, so require imm.
|
// freed, so require imm.
|
||||||
self.require_imm(cmt, cmt_base, err_mut_uniq)
|
self.require_imm(cmt, cmt_base, err_mut_uniq)
|
||||||
}
|
}
|
||||||
cat_deref(_, _, region_ptr(region)) => {
|
cat_deref(_, _, region_ptr(_, region)) => {
|
||||||
// References are always "stable" for lifetime `region` by
|
// References are always "stable" for lifetime `region` by
|
||||||
// induction (when the reference of type &MT was created,
|
// induction (when the reference of type &MT was created,
|
||||||
// the memory must have been stable).
|
// the memory must have been stable).
|
||||||
|
|
|
@ -73,6 +73,7 @@ enum categorization {
|
||||||
cat_deref(cmt, uint, ptr_kind), // deref of a ptr
|
cat_deref(cmt, uint, ptr_kind), // deref of a ptr
|
||||||
cat_comp(cmt, comp_kind), // adjust to locate an internal component
|
cat_comp(cmt, comp_kind), // adjust to locate an internal component
|
||||||
cat_discr(cmt, ast::node_id), // match discriminant (see preserve())
|
cat_discr(cmt, ast::node_id), // match discriminant (see preserve())
|
||||||
|
cat_self(ast::node_id), // explicit `self`
|
||||||
}
|
}
|
||||||
|
|
||||||
// different kinds of pointers:
|
// different kinds of pointers:
|
||||||
|
@ -80,7 +81,7 @@ enum categorization {
|
||||||
pub enum ptr_kind {
|
pub enum ptr_kind {
|
||||||
uniq_ptr,
|
uniq_ptr,
|
||||||
gc_ptr(ast::mutability),
|
gc_ptr(ast::mutability),
|
||||||
region_ptr(ty::Region),
|
region_ptr(ast::mutability, ty::Region),
|
||||||
unsafe_ptr
|
unsafe_ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +104,6 @@ pub enum comp_kind {
|
||||||
enum special_kind {
|
enum special_kind {
|
||||||
sk_method,
|
sk_method,
|
||||||
sk_static_item,
|
sk_static_item,
|
||||||
sk_self,
|
|
||||||
sk_implicit_self, // old by-reference `self`
|
sk_implicit_self, // old by-reference `self`
|
||||||
sk_heap_upvar
|
sk_heap_upvar
|
||||||
}
|
}
|
||||||
|
@ -135,45 +135,15 @@ impl cmt_ : cmp::Eq {
|
||||||
// a loan path is like a category, but it exists only when the data is
|
// a loan path is like a category, but it exists only when the data is
|
||||||
// interior to the stack frame. loan paths are used as the key to a
|
// interior to the stack frame. loan paths are used as the key to a
|
||||||
// map indicating what is borrowed at any point in time.
|
// map indicating what is borrowed at any point in time.
|
||||||
|
#[deriving_eq]
|
||||||
pub enum loan_path {
|
pub enum loan_path {
|
||||||
lp_local(ast::node_id),
|
lp_local(ast::node_id),
|
||||||
lp_arg(ast::node_id),
|
lp_arg(ast::node_id),
|
||||||
|
lp_self,
|
||||||
lp_deref(@loan_path, ptr_kind),
|
lp_deref(@loan_path, ptr_kind),
|
||||||
lp_comp(@loan_path, comp_kind)
|
lp_comp(@loan_path, comp_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl loan_path : cmp::Eq {
|
|
||||||
pure fn eq(&self, other: &loan_path) -> bool {
|
|
||||||
match (*self) {
|
|
||||||
lp_local(e0a) => {
|
|
||||||
match (*other) {
|
|
||||||
lp_local(e0b) => e0a == e0b,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lp_arg(e0a) => {
|
|
||||||
match (*other) {
|
|
||||||
lp_arg(e0b) => e0a == e0b,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lp_deref(e0a, e1a) => {
|
|
||||||
match (*other) {
|
|
||||||
lp_deref(e0b, e1b) => e0a == e0b && e1a == e1b,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lp_comp(e0a, e1a) => {
|
|
||||||
match (*other) {
|
|
||||||
lp_comp(e0b, e1b) => e0a == e0b && e1a == e1b,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pure fn ne(&self, other: &loan_path) -> bool { !(*self).eq(other) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// We pun on *T to mean both actual deref of a ptr as well
|
// We pun on *T to mean both actual deref of a ptr as well
|
||||||
// as accessing of components:
|
// as accessing of components:
|
||||||
enum deref_kind {deref_ptr(ptr_kind), deref_comp(comp_kind)}
|
enum deref_kind {deref_ptr(ptr_kind), deref_comp(comp_kind)}
|
||||||
|
@ -193,14 +163,17 @@ fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
|
||||||
Some(deref_ptr(uniq_ptr))
|
Some(deref_ptr(uniq_ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_rptr(r, _) |
|
ty::ty_rptr(r, mt) |
|
||||||
ty::ty_evec(_, ty::vstore_slice(r)) |
|
ty::ty_evec(mt, ty::vstore_slice(r)) => {
|
||||||
|
Some(deref_ptr(region_ptr(mt.mutbl, r)))
|
||||||
|
}
|
||||||
|
|
||||||
ty::ty_estr(ty::vstore_slice(r)) => {
|
ty::ty_estr(ty::vstore_slice(r)) => {
|
||||||
Some(deref_ptr(region_ptr(r)))
|
Some(deref_ptr(region_ptr(ast::m_imm, r)))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_fn(ref f) if (*f).meta.proto == ast::ProtoBorrowed => {
|
ty::ty_fn(ref f) if (*f).meta.proto == ast::ProtoBorrowed => {
|
||||||
Some(deref_ptr(region_ptr((*f).meta.region)))
|
Some(deref_ptr(region_ptr(ast::m_imm, (*f).meta.region)))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ty_box(mt) |
|
ty::ty_box(mt) |
|
||||||
|
@ -481,15 +454,18 @@ impl &mem_categorization_ctxt {
|
||||||
mutbl:m, ty:expr_ty}
|
mutbl:m, ty:expr_ty}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::def_self(_, is_implicit) => {
|
ast::def_self(self_id, is_implicit) => {
|
||||||
let special_kind = if is_implicit {
|
let cat, loan_path;
|
||||||
sk_implicit_self
|
if is_implicit {
|
||||||
|
cat = cat_special(sk_implicit_self);
|
||||||
|
loan_path = None;
|
||||||
} else {
|
} else {
|
||||||
sk_self
|
cat = cat_self(self_id);
|
||||||
|
loan_path = Some(@lp_self);
|
||||||
};
|
};
|
||||||
|
|
||||||
@{id:id, span:span,
|
@{id:id, span:span,
|
||||||
cat:cat_special(special_kind), lp:None,
|
cat:cat, lp:loan_path,
|
||||||
mutbl:m_imm, ty:expr_ty}
|
mutbl:m_imm, ty:expr_ty}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,13 +602,16 @@ impl &mem_categorization_ctxt {
|
||||||
deref_ptr(ptr) => {
|
deref_ptr(ptr) => {
|
||||||
let lp = do base_cmt.lp.chain_ref |l| {
|
let lp = do base_cmt.lp.chain_ref |l| {
|
||||||
// Given that the ptr itself is loanable, we can
|
// Given that the ptr itself is loanable, we can
|
||||||
// loan out deref'd uniq ptrs as the data they are
|
// loan out deref'd uniq ptrs or mut ptrs as the data
|
||||||
// the only way to reach the data they point at.
|
// they are the only way to mutably reach the data they
|
||||||
// Other ptr types admit aliases and are therefore
|
// point at. Other ptr types admit mutable aliases and
|
||||||
// not loanable.
|
// are therefore not loanable.
|
||||||
match ptr {
|
match ptr {
|
||||||
uniq_ptr => {Some(@lp_deref(*l, ptr))}
|
uniq_ptr => Some(@lp_deref(*l, ptr)),
|
||||||
gc_ptr(*) | region_ptr(_) | unsafe_ptr => {None}
|
region_ptr(ast::m_mutbl, _) => {
|
||||||
|
Some(@lp_deref(*l, ptr))
|
||||||
|
}
|
||||||
|
gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -642,7 +621,7 @@ impl &mem_categorization_ctxt {
|
||||||
uniq_ptr => {
|
uniq_ptr => {
|
||||||
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
|
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
|
||||||
}
|
}
|
||||||
gc_ptr(*) | region_ptr(_) | unsafe_ptr => {
|
gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => {
|
||||||
mt.mutbl
|
mt.mutbl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -688,7 +667,7 @@ impl &mem_categorization_ctxt {
|
||||||
uniq_ptr => {
|
uniq_ptr => {
|
||||||
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
|
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
|
||||||
}
|
}
|
||||||
gc_ptr(_) | region_ptr(_) | unsafe_ptr => {
|
gc_ptr(_) | region_ptr(_, _) | unsafe_ptr => {
|
||||||
mt.mutbl
|
mt.mutbl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -866,13 +845,13 @@ impl &mem_categorization_ctxt {
|
||||||
cat_special(sk_method) => ~"method",
|
cat_special(sk_method) => ~"method",
|
||||||
cat_special(sk_static_item) => ~"static_item",
|
cat_special(sk_static_item) => ~"static_item",
|
||||||
cat_special(sk_implicit_self) => ~"implicit-self",
|
cat_special(sk_implicit_self) => ~"implicit-self",
|
||||||
cat_special(sk_self) => ~"self",
|
|
||||||
cat_special(sk_heap_upvar) => ~"heap-upvar",
|
cat_special(sk_heap_upvar) => ~"heap-upvar",
|
||||||
cat_stack_upvar(_) => ~"stack-upvar",
|
cat_stack_upvar(_) => ~"stack-upvar",
|
||||||
cat_rvalue => ~"rvalue",
|
cat_rvalue => ~"rvalue",
|
||||||
cat_local(node_id) => fmt!("local(%d)", node_id),
|
cat_local(node_id) => fmt!("local(%d)", node_id),
|
||||||
cat_binding(node_id) => fmt!("binding(%d)", node_id),
|
cat_binding(node_id) => fmt!("binding(%d)", node_id),
|
||||||
cat_arg(node_id) => fmt!("arg(%d)", node_id),
|
cat_arg(node_id) => fmt!("arg(%d)", node_id),
|
||||||
|
cat_self(node_id) => fmt!("self(%d)", node_id),
|
||||||
cat_deref(cmt, derefs, ptr) => {
|
cat_deref(cmt, derefs, ptr) => {
|
||||||
fmt!("%s->(%s, %u)", self.cat_to_repr(cmt.cat),
|
fmt!("%s->(%s, %u)", self.cat_to_repr(cmt.cat),
|
||||||
self.ptr_sigil(ptr), derefs)
|
self.ptr_sigil(ptr), derefs)
|
||||||
|
@ -896,7 +875,7 @@ impl &mem_categorization_ctxt {
|
||||||
match ptr {
|
match ptr {
|
||||||
uniq_ptr => ~"~",
|
uniq_ptr => ~"~",
|
||||||
gc_ptr(_) => ~"@",
|
gc_ptr(_) => ~"@",
|
||||||
region_ptr(_) => ~"&",
|
region_ptr(_, _) => ~"&",
|
||||||
unsafe_ptr => ~"*"
|
unsafe_ptr => ~"*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -919,6 +898,7 @@ impl &mem_categorization_ctxt {
|
||||||
lp_arg(node_id) => {
|
lp_arg(node_id) => {
|
||||||
fmt!("arg(%d)", node_id)
|
fmt!("arg(%d)", node_id)
|
||||||
}
|
}
|
||||||
|
lp_self => ~"self",
|
||||||
lp_deref(lp, ptr) => {
|
lp_deref(lp, ptr) => {
|
||||||
fmt!("%s->(%s)", self.lp_to_str(lp),
|
fmt!("%s->(%s)", self.lp_to_str(lp),
|
||||||
self.ptr_sigil(ptr))
|
self.ptr_sigil(ptr))
|
||||||
|
@ -945,13 +925,13 @@ impl &mem_categorization_ctxt {
|
||||||
cat_special(sk_method) => ~"method",
|
cat_special(sk_method) => ~"method",
|
||||||
cat_special(sk_static_item) => ~"static item",
|
cat_special(sk_static_item) => ~"static item",
|
||||||
cat_special(sk_implicit_self) => ~"self reference",
|
cat_special(sk_implicit_self) => ~"self reference",
|
||||||
cat_special(sk_self) => ~"self value",
|
|
||||||
cat_special(sk_heap_upvar) => {
|
cat_special(sk_heap_upvar) => {
|
||||||
~"captured outer variable in a heap closure"
|
~"captured outer variable in a heap closure"
|
||||||
}
|
}
|
||||||
cat_rvalue => ~"non-lvalue",
|
cat_rvalue => ~"non-lvalue",
|
||||||
cat_local(_) => mut_str + ~" local variable",
|
cat_local(_) => mut_str + ~" local variable",
|
||||||
cat_binding(_) => ~"pattern binding",
|
cat_binding(_) => ~"pattern binding",
|
||||||
|
cat_self(_) => ~"self value",
|
||||||
cat_arg(_) => ~"argument",
|
cat_arg(_) => ~"argument",
|
||||||
cat_deref(_, _, pk) => fmt!("dereference of %s %s pointer",
|
cat_deref(_, _, pk) => fmt!("dereference of %s %s pointer",
|
||||||
mut_str, self.ptr_sigil(pk)),
|
mut_str, self.ptr_sigil(pk)),
|
||||||
|
@ -1045,7 +1025,8 @@ impl categorization {
|
||||||
cat_special(*) |
|
cat_special(*) |
|
||||||
cat_local(*) |
|
cat_local(*) |
|
||||||
cat_binding(*) |
|
cat_binding(*) |
|
||||||
cat_arg(*) => {
|
cat_arg(*) |
|
||||||
|
cat_self(*) => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -336,6 +336,14 @@ fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Record the ID of `self`.
|
||||||
|
match fk {
|
||||||
|
visit::fk_method(_, _, method) => {
|
||||||
|
cx.region_map.insert(method.self_id, body.node.id);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
debug!("visiting fn with body %d. cx.parent: %? \
|
debug!("visiting fn with body %d. cx.parent: %? \
|
||||||
fn_cx.parent: %?",
|
fn_cx.parent: %?",
|
||||||
body.node.id, cx.parent, fn_cx.parent);
|
body.node.id, cx.parent, fn_cx.parent);
|
||||||
|
|
|
@ -241,19 +241,24 @@ fn check_poison(is_mutex: bool, failed: bool) {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
struct PoisonOnFail {
|
struct PoisonOnFail {
|
||||||
failed: &mut bool,
|
failed: *mut bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PoisonOnFail : Drop {
|
impl PoisonOnFail : Drop {
|
||||||
fn finalize(&self) {
|
fn finalize(&self) {
|
||||||
/* assert !*self.failed; -- might be false in case of cond.wait() */
|
unsafe {
|
||||||
if task::failing() { *self.failed = true; }
|
/* assert !*self.failed;
|
||||||
|
-- might be false in case of cond.wait() */
|
||||||
|
if task::failing() {
|
||||||
|
*self.failed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn PoisonOnFail(failed: &r/mut bool) -> PoisonOnFail/&r {
|
fn PoisonOnFail(failed: &r/mut bool) -> PoisonOnFail {
|
||||||
PoisonOnFail {
|
PoisonOnFail {
|
||||||
failed: failed
|
failed: ptr::to_mut_unsafe_ptr(failed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,7 +420,7 @@ pub fn unwrap_rw_arc<T: Const Owned>(arc: RWARC<T>) -> T {
|
||||||
// field is never overwritten; only 'failed' and 'data'.
|
// field is never overwritten; only 'failed' and 'data'.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
fn borrow_rwlock<T: Const Owned>(state: &r/mut RWARCInner<T>) -> &r/RWlock {
|
fn borrow_rwlock<T: Const Owned>(state: &r/mut RWARCInner<T>) -> &r/RWlock {
|
||||||
unsafe { cast::transmute_immut(&mut state.lock) }
|
unsafe { cast::transmute(&mut state.lock) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME (#3154) ice with struct/&<T> prevents these from being structs.
|
// FIXME (#3154) ice with struct/&<T> prevents these from being structs.
|
||||||
|
@ -442,12 +447,14 @@ impl<T: Const Owned> &RWWriteMode<T> {
|
||||||
match *self {
|
match *self {
|
||||||
RWWriteMode((ref data, ref token, ref poison)) => {
|
RWWriteMode((ref data, ref token, ref poison)) => {
|
||||||
do token.write_cond |cond| {
|
do token.write_cond |cond| {
|
||||||
let cvar = Condvar {
|
unsafe {
|
||||||
is_mutex: false,
|
let cvar = Condvar {
|
||||||
failed: &mut *poison.failed,
|
is_mutex: false,
|
||||||
cond: cond
|
failed: &mut *poison.failed,
|
||||||
};
|
cond: cond
|
||||||
blk(&mut **data, &cvar)
|
};
|
||||||
|
blk(&mut **data, &cvar)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use core::vec;
|
||||||
#[abi = "rust-intrinsic"]
|
#[abi = "rust-intrinsic"]
|
||||||
extern "C" mod rusti {
|
extern "C" mod rusti {
|
||||||
fn move_val_init<T>(dst: &mut T, -src: T);
|
fn move_val_init<T>(dst: &mut T, -src: T);
|
||||||
|
fn init<T>() -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PriorityQueue <T: Ord>{
|
pub struct PriorityQueue <T: Ord>{
|
||||||
|
@ -136,8 +137,9 @@ impl <T: Ord> PriorityQueue<T> {
|
||||||
while pos > start {
|
while pos > start {
|
||||||
let parent = (pos - 1) >> 1;
|
let parent = (pos - 1) >> 1;
|
||||||
if new > self.data[parent] {
|
if new > self.data[parent] {
|
||||||
rusti::move_val_init(&mut self.data[pos],
|
let mut x = rusti::init();
|
||||||
move *addr_of(&self.data[parent]));
|
x <-> self.data[parent];
|
||||||
|
rusti::move_val_init(&mut self.data[pos], move x);
|
||||||
pos = parent;
|
pos = parent;
|
||||||
loop
|
loop
|
||||||
}
|
}
|
||||||
|
@ -159,8 +161,9 @@ impl <T: Ord> PriorityQueue<T> {
|
||||||
if right < end && !(self.data[child] > self.data[right]) {
|
if right < end && !(self.data[child] > self.data[right]) {
|
||||||
child = right;
|
child = right;
|
||||||
}
|
}
|
||||||
rusti::move_val_init(&mut self.data[pos],
|
let mut x = rusti::init();
|
||||||
move *addr_of(&self.data[child]));
|
x <-> self.data[child];
|
||||||
|
rusti::move_val_init(&mut self.data[pos], move x);
|
||||||
pos = child;
|
pos = child;
|
||||||
child = 2 * pos + 1;
|
child = 2 * pos + 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,10 @@ impl <K: Eq Ord, V: Eq> TreeMap<K, V>: Eq {
|
||||||
unsafe { // unsafe as a purity workaround
|
unsafe { // unsafe as a purity workaround
|
||||||
// ICE: x.next() != y.next()
|
// ICE: x.next() != y.next()
|
||||||
|
|
||||||
let (x1, x2) = x.next().unwrap();
|
x = x.next();
|
||||||
let (y1, y2) = y.next().unwrap();
|
y = y.next();
|
||||||
|
let (x1, x2) = x.get().unwrap();
|
||||||
|
let (y1, y2) = y.get().unwrap();
|
||||||
|
|
||||||
if x1 != y1 || x2 != y2 {
|
if x1 != y1 || x2 != y2 {
|
||||||
return false
|
return false
|
||||||
|
@ -160,35 +162,46 @@ impl <K: Ord, V> TreeMap<K, V> {
|
||||||
/// Get a lazy iterator over the key-value pairs in the map.
|
/// Get a lazy iterator over the key-value pairs in the map.
|
||||||
/// Requires that it be frozen (immutable).
|
/// Requires that it be frozen (immutable).
|
||||||
pure fn iter(&self) -> TreeMapIterator/&self<K, V> {
|
pure fn iter(&self) -> TreeMapIterator/&self<K, V> {
|
||||||
TreeMapIterator{stack: ~[], node: &self.root}
|
TreeMapIterator{stack: ~[], node: &self.root, current: None}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lazy forward iterator over a map
|
/// Lazy forward iterator over a map
|
||||||
pub struct TreeMapIterator<K: Ord, V> {
|
pub struct TreeMapIterator<K: Ord, V> {
|
||||||
priv stack: ~[&~TreeNode<K, V>],
|
priv stack: ~[&~TreeNode<K, V>],
|
||||||
priv node: &Option<~TreeNode<K, V>>
|
priv node: &Option<~TreeNode<K, V>>,
|
||||||
|
priv current: Option<&~TreeNode<K, V>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <K: Ord, V> TreeMapIterator<K, V> {
|
impl <K: Ord, V> TreeMapIterator<K, V> {
|
||||||
/// Advance the iterator to the next node (in order) and return a
|
// Returns the current node, or None if this iterator is at the end.
|
||||||
/// tuple with a reference to the key and value. If there are no
|
fn get(&const self) -> Option<(&self/K, &self/V)> {
|
||||||
/// more nodes, return `None`.
|
match self.current {
|
||||||
fn next(&mut self) -> Option<(&self/K, &self/V)> {
|
Some(res) => Some((&res.key, &res.value)),
|
||||||
while !self.stack.is_empty() || self.node.is_some() {
|
None => None
|
||||||
match *self.node {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advance the iterator to the next node (in order). If this iterator
|
||||||
|
/// is finished, does nothing.
|
||||||
|
fn next(self) -> TreeMapIterator/&self<K, V> {
|
||||||
|
let mut this = self;
|
||||||
|
while !this.stack.is_empty() || this.node.is_some() {
|
||||||
|
match *this.node {
|
||||||
Some(ref x) => {
|
Some(ref x) => {
|
||||||
self.stack.push(x);
|
this.stack.push(x);
|
||||||
self.node = &x.left;
|
this.node = &x.left;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let res = self.stack.pop();
|
let res = this.stack.pop();
|
||||||
self.node = &res.right;
|
this.node = &res.right;
|
||||||
return Some((&res.key, &res.value));
|
this.current = Some(res);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
this.current = None;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,15 +269,19 @@ impl <T: Ord> TreeSet<T> {
|
||||||
let mut x = self.iter();
|
let mut x = self.iter();
|
||||||
let mut y = other.iter();
|
let mut y = other.iter();
|
||||||
unsafe { // purity workaround
|
unsafe { // purity workaround
|
||||||
let mut a = x.next();
|
x = x.next();
|
||||||
let mut b = y.next();
|
y = y.next();
|
||||||
|
let mut a = x.get();
|
||||||
|
let mut b = y.get();
|
||||||
while a.is_some() && b.is_some() {
|
while a.is_some() && b.is_some() {
|
||||||
let a1 = a.unwrap();
|
let a1 = a.unwrap();
|
||||||
let b1 = b.unwrap();
|
let b1 = b.unwrap();
|
||||||
if a1 < b1 {
|
if a1 < b1 {
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
} else if b1 < a1 {
|
} else if b1 < a1 {
|
||||||
b = y.next();
|
y = y.next();
|
||||||
|
b = y.get();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -283,8 +300,10 @@ impl <T: Ord> TreeSet<T> {
|
||||||
let mut x = self.iter();
|
let mut x = self.iter();
|
||||||
let mut y = other.iter();
|
let mut y = other.iter();
|
||||||
unsafe { // purity workaround
|
unsafe { // purity workaround
|
||||||
let mut a = x.next();
|
x = x.next();
|
||||||
let mut b = y.next();
|
y = y.next();
|
||||||
|
let mut a = x.get();
|
||||||
|
let mut b = y.get();
|
||||||
while b.is_some() {
|
while b.is_some() {
|
||||||
if a.is_none() {
|
if a.is_none() {
|
||||||
return false
|
return false
|
||||||
|
@ -298,9 +317,11 @@ impl <T: Ord> TreeSet<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(a1 < b1) {
|
if !(a1 < b1) {
|
||||||
b = y.next();
|
y = y.next();
|
||||||
|
b = y.get();
|
||||||
}
|
}
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -312,13 +333,15 @@ impl <T: Ord> TreeSet<T> {
|
||||||
let mut y = other.iter();
|
let mut y = other.iter();
|
||||||
|
|
||||||
unsafe { // purity workaround
|
unsafe { // purity workaround
|
||||||
let mut a = x.next();
|
x = x.next();
|
||||||
let mut b = y.next();
|
y = y.next();
|
||||||
|
let mut a = x.get();
|
||||||
|
let mut b = y.get();
|
||||||
|
|
||||||
while a.is_some() {
|
while a.is_some() {
|
||||||
if b.is_none() {
|
if b.is_none() {
|
||||||
return do a.while_some() |a1| {
|
return do a.while_some() |a1| {
|
||||||
if f(a1) { x.next() } else { None }
|
if f(a1) { x = x.next(); x.get() } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,10 +350,12 @@ impl <T: Ord> TreeSet<T> {
|
||||||
|
|
||||||
if a1 < b1 {
|
if a1 < b1 {
|
||||||
if !f(a1) { return }
|
if !f(a1) { return }
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
} else {
|
} else {
|
||||||
if !(b1 < a1) { a = x.next() }
|
if !(b1 < a1) { x = x.next(); a = x.get() }
|
||||||
b = y.next();
|
y = y.next();
|
||||||
|
b = y.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,13 +368,15 @@ impl <T: Ord> TreeSet<T> {
|
||||||
let mut y = other.iter();
|
let mut y = other.iter();
|
||||||
|
|
||||||
unsafe { // purity workaround
|
unsafe { // purity workaround
|
||||||
let mut a = x.next();
|
x = x.next();
|
||||||
let mut b = y.next();
|
y = y.next();
|
||||||
|
let mut a = x.get();
|
||||||
|
let mut b = y.get();
|
||||||
|
|
||||||
while a.is_some() {
|
while a.is_some() {
|
||||||
if b.is_none() {
|
if b.is_none() {
|
||||||
return do a.while_some() |a1| {
|
return do a.while_some() |a1| {
|
||||||
if f(a1) { x.next() } else { None }
|
if f(a1) { x.next(); x.get() } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,18 +385,21 @@ impl <T: Ord> TreeSet<T> {
|
||||||
|
|
||||||
if a1 < b1 {
|
if a1 < b1 {
|
||||||
if !f(a1) { return }
|
if !f(a1) { return }
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
} else {
|
} else {
|
||||||
if b1 < a1 {
|
if b1 < a1 {
|
||||||
if !f(b1) { return }
|
if !f(b1) { return }
|
||||||
} else {
|
} else {
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
}
|
}
|
||||||
b = y.next();
|
y = y.next();
|
||||||
|
b = y.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
do b.while_some |b1| {
|
do b.while_some |b1| {
|
||||||
if f(b1) { y.next() } else { None }
|
if f(b1) { y = y.next(); y.get() } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,19 +410,23 @@ impl <T: Ord> TreeSet<T> {
|
||||||
let mut y = other.iter();
|
let mut y = other.iter();
|
||||||
|
|
||||||
unsafe { // purity workaround
|
unsafe { // purity workaround
|
||||||
let mut a = x.next();
|
x = x.next();
|
||||||
let mut b = y.next();
|
y = y.next();
|
||||||
|
let mut a = x.get();
|
||||||
|
let mut b = y.get();
|
||||||
|
|
||||||
while a.is_some() && b.is_some() {
|
while a.is_some() && b.is_some() {
|
||||||
let a1 = a.unwrap();
|
let a1 = a.unwrap();
|
||||||
let b1 = b.unwrap();
|
let b1 = b.unwrap();
|
||||||
if a1 < b1 {
|
if a1 < b1 {
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
} else {
|
} else {
|
||||||
if !(b1 < a1) {
|
if !(b1 < a1) {
|
||||||
if !f(a1) { return }
|
if !f(a1) { return }
|
||||||
}
|
}
|
||||||
b = y.next();
|
y = y.next();
|
||||||
|
b = y.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,13 +438,15 @@ impl <T: Ord> TreeSet<T> {
|
||||||
let mut y = other.iter();
|
let mut y = other.iter();
|
||||||
|
|
||||||
unsafe { // purity workaround
|
unsafe { // purity workaround
|
||||||
let mut a = x.next();
|
x = x.next();
|
||||||
let mut b = y.next();
|
y = y.next();
|
||||||
|
let mut a = x.get();
|
||||||
|
let mut b = y.get();
|
||||||
|
|
||||||
while a.is_some() {
|
while a.is_some() {
|
||||||
if b.is_none() {
|
if b.is_none() {
|
||||||
return do a.while_some() |a1| {
|
return do a.while_some() |a1| {
|
||||||
if f(a1) { x.next() } else { None }
|
if f(a1) { x = x.next(); x.get() } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,13 +455,16 @@ impl <T: Ord> TreeSet<T> {
|
||||||
|
|
||||||
if b1 < a1 {
|
if b1 < a1 {
|
||||||
if !f(b1) { return }
|
if !f(b1) { return }
|
||||||
b = y.next();
|
y = y.next();
|
||||||
|
b = y.get();
|
||||||
} else {
|
} else {
|
||||||
if !f(a1) { return }
|
if !f(a1) { return }
|
||||||
if !(a1 < b1) {
|
if !(a1 < b1) {
|
||||||
b = y.next()
|
y = y.next();
|
||||||
|
b = y.get()
|
||||||
}
|
}
|
||||||
a = x.next();
|
x = x.next();
|
||||||
|
a = x.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,11 +477,18 @@ pub struct TreeSetIterator<T: Ord> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: Ord> TreeSetIterator<T> {
|
impl <T: Ord> TreeSetIterator<T> {
|
||||||
/// Advance the iterator to the next node (in order) and return a
|
/// Returns the current node, or None if this iterator is at the end.
|
||||||
/// tuple with a reference to the value. If there are no more nodes,
|
fn get(&const self) -> Option<&self/T> {
|
||||||
/// return `None`.
|
match self.iter.get() {
|
||||||
fn next(&mut self) -> Option<&self/T> {
|
None => None,
|
||||||
self.iter.next().map_consume(|(x, _)| x)
|
Some((k, _)) => Some(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advance the iterator to the next node (in order). If this iterator is
|
||||||
|
/// finished, does nothing.
|
||||||
|
fn next(self) -> TreeSetIterator/&self<T> {
|
||||||
|
TreeSetIterator { iter: self.iter.next() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,17 +900,23 @@ mod test_treemap {
|
||||||
//assert iter.next() == Some((&x1, &y1));
|
//assert iter.next() == Some((&x1, &y1));
|
||||||
//assert iter.next().eq(&Some((&x1, &y1)));
|
//assert iter.next().eq(&Some((&x1, &y1)));
|
||||||
|
|
||||||
assert iter.next().unwrap() == (&x1, &y1);
|
iter = iter.next();
|
||||||
assert iter.next().unwrap() == (&x2, &y2);
|
assert iter.get().unwrap() == (&x1, &y1);
|
||||||
assert iter.next().unwrap() == (&x3, &y3);
|
iter = iter.next();
|
||||||
assert iter.next().unwrap() == (&x4, &y4);
|
assert iter.get().unwrap() == (&x2, &y2);
|
||||||
assert iter.next().unwrap() == (&x5, &y5);
|
iter = iter.next();
|
||||||
|
assert iter.get().unwrap() == (&x3, &y3);
|
||||||
|
iter = iter.next();
|
||||||
|
assert iter.get().unwrap() == (&x4, &y4);
|
||||||
|
iter = iter.next();
|
||||||
|
assert iter.get().unwrap() == (&x5, &y5);
|
||||||
|
|
||||||
// ICE:
|
// ICE:
|
||||||
//assert iter.next() == None;
|
//assert iter.next() == None;
|
||||||
//assert iter.next().eq(&None);
|
//assert iter.next().eq(&None);
|
||||||
|
|
||||||
assert iter.next().is_none();
|
iter = iter.next();
|
||||||
|
assert iter.get().is_none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ fn main() {
|
||||||
do (&mut x).with |opt| { //~ ERROR illegal borrow
|
do (&mut x).with |opt| { //~ ERROR illegal borrow
|
||||||
match opt {
|
match opt {
|
||||||
&Right(ref f) => {
|
&Right(ref f) => {
|
||||||
x = X(Left((0,0)));
|
x = X(Left((0,0))); //~ ERROR assigning to captured outer mutable variable
|
||||||
(*f)()
|
(*f)()
|
||||||
},
|
},
|
||||||
_ => fail
|
_ => fail
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn a(x: &mut Foo) {
|
fn a(x: &mut Foo) {
|
||||||
x.f(); //~ ERROR illegal borrow unless pure
|
x.f();
|
||||||
x.g();
|
x.g();
|
||||||
x.h();
|
x.h();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,9 @@ fn main() {
|
||||||
let q = &mut b.foo; //~ ERROR loan of mutable field as mutable conflicts with prior loan
|
let q = &mut b.foo; //~ ERROR loan of mutable field as mutable conflicts with prior loan
|
||||||
//~^ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
//~^ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
||||||
let r = &mut b; //~ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
let r = &mut b; //~ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
||||||
|
//~^ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
||||||
io::println(fmt!("*p = %u", *p));
|
io::println(fmt!("*p = %u", *p));
|
||||||
q.x += 1;
|
q.x += 1;
|
||||||
r.foo.x += 1;
|
r.foo.x += 1;
|
||||||
io::println(fmt!("*p = %u", *p));
|
io::println(fmt!("*p = %u", *p));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut _a = 3;
|
let mut _a = 3;
|
||||||
let _b = &mut _a;
|
let _b = &mut _a; //~ NOTE loan of mutable local variable granted here
|
||||||
{
|
{
|
||||||
let _c = &*_b; //~ ERROR illegal borrow unless pure
|
let _c = &*_b;
|
||||||
_a = 4; //~ NOTE impure due to assigning to mutable local variable
|
_a = 4; //~ ERROR assigning to mutable local variable prohibited
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
fn borrow(_v: &int) {}
|
fn borrow(_v: &int) {}
|
||||||
|
|
||||||
fn box_mut(v: &mut ~int) {
|
fn box_mut(v: &mut ~int) {
|
||||||
borrow(*v); //~ ERROR illegal borrow unless pure
|
borrow(*v); // OK: &mut -> &imm
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_rec_mut(v: &{mut f: ~int}) {
|
fn box_rec_mut(v: &{mut f: ~int}) {
|
||||||
|
@ -19,11 +19,11 @@ fn box_rec_mut(v: &{mut f: ~int}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_mut_rec(v: &mut {f: ~int}) {
|
fn box_mut_rec(v: &mut {f: ~int}) {
|
||||||
borrow(v.f); //~ ERROR illegal borrow unless pure
|
borrow(v.f); // OK: &mut -> &imm
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_mut_recs(v: &mut {f: {g: {h: ~int}}}) {
|
fn box_mut_recs(v: &mut {f: {g: {h: ~int}}}) {
|
||||||
borrow(v.f.g.h); //~ ERROR illegal borrow unless pure
|
borrow(v.f.g.h); // OK: &mut -> &imm
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_imm(v: &~int) {
|
fn box_imm(v: &~int) {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
fn main() {
|
||||||
|
let mut b = ~3;
|
||||||
|
let _x = &mut *b; //~ NOTE prior loan as mutable granted here
|
||||||
|
let _y = &mut *b; //~ ERROR loan of dereference of mutable ~ pointer as mutable conflicts with prior loan
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
fn main() {
|
||||||
|
let mut a = ~3;
|
||||||
|
let mut b = &mut a; //~ NOTE loan of mutable local variable granted here
|
||||||
|
let _c = &mut *b;
|
||||||
|
let mut d = /*move*/ a; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan
|
||||||
|
*d += 1;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
let mut b = ~3;
|
||||||
|
let _x = &mut *b; //~ NOTE loan of mutable local variable granted here
|
||||||
|
let mut y = /*move*/ b; //~ ERROR moving out of mutable local variable prohibited
|
||||||
|
*y += 1;
|
||||||
|
}
|
||||||
|
|
11
src/test/compile-fail/borrowck-wg-move-base-2.rs
Normal file
11
src/test/compile-fail/borrowck-wg-move-base-2.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fn foo(x: &mut int) {
|
||||||
|
let mut a = 3;
|
||||||
|
let mut _y = &mut *x;
|
||||||
|
let _z = &mut *_y;
|
||||||
|
_y = &mut a; //~ ERROR assigning to mutable local variable prohibited
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn broken() {
|
||||||
while x < 10 {
|
while x < 10 {
|
||||||
let mut z = x;
|
let mut z = x;
|
||||||
_y.push(&mut z); //~ ERROR illegal borrow
|
_y.push(&mut z); //~ ERROR illegal borrow
|
||||||
x += 1;
|
x += 1; //~ ERROR assigning to mutable local variable prohibited due to outstanding loan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,7 @@ fn main() {
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
{f: ref mut v} => {
|
{f: ref mut v} => {
|
||||||
impure(*v); //~ ERROR illegal borrow unless pure
|
impure(*v);
|
||||||
//~^ NOTE impure due to access to impure function
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,8 +15,7 @@ fn borrow_from_arg_imm_ref(&&v: ~int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrow_from_arg_mut_ref(v: &mut ~int) {
|
fn borrow_from_arg_mut_ref(v: &mut ~int) {
|
||||||
borrow(*v); //~ ERROR illegal borrow unless pure
|
borrow(*v);
|
||||||
//~^ NOTE impure due to access to impure function
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrow_from_arg_move(-v: ~int) {
|
fn borrow_from_arg_move(-v: ~int) {
|
13
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs
Normal file
13
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
struct Cat;
|
||||||
|
|
||||||
|
fn bar(_: &Cat) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(cat: &mut Cat) {
|
||||||
|
bar(&*cat);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut mimi = ~Cat;
|
||||||
|
foo(mimi);
|
||||||
|
}
|
18
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs
Normal file
18
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
struct Wizard {
|
||||||
|
spells: ~[&static/str]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Wizard {
|
||||||
|
fn cast(&mut self) {
|
||||||
|
for self.spells.each |&spell| {
|
||||||
|
io::println(spell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut harry = Wizard {
|
||||||
|
spells: ~[ "expelliarmus", "expecto patronum", "incendio" ]
|
||||||
|
};
|
||||||
|
harry.cast();
|
||||||
|
}
|
12
src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs
Normal file
12
src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
fn g(x: &Option<int>) {
|
||||||
|
io::println(x.get().to_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f(x: &mut Option<int>) {
|
||||||
|
g(&*x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = ~Some(3);
|
||||||
|
f(x);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue