auto merge of #4914 : nikomatsakis/rust/issue-4856, r=nikomatsakis

and then adjust code to match. rs=unsound (will review post-landing)

rs=unsound
This commit is contained in:
bors 2013-02-12 20:40:19 -08:00
commit 27b3e01377
25 changed files with 1046 additions and 575 deletions

View file

@ -383,7 +383,9 @@ pub mod linear {
},
};
self.value_for_bucket(idx)
unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker
::cast::transmute_region(self.value_for_bucket(idx))
}
}
/// Return the value corresponding to the key in the map, or create,
@ -412,7 +414,9 @@ pub mod linear {
},
};
self.value_for_bucket(idx)
unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker
::cast::transmute_region(self.value_for_bucket(idx))
}
}
fn consume(&mut self, f: fn(K, V)) {

View file

@ -256,15 +256,15 @@ pub unsafe fn shared_mutable_state<T: Owned>(data: T) ->
}
#[inline(always)]
pub unsafe fn get_shared_mutable_state<T: Owned>(rc: &a/SharedMutableState<T>)
-> &a/mut T {
pub unsafe fn get_shared_mutable_state<T: Owned>(
rc: *SharedMutableState<T>) -> *mut T
{
unsafe {
let ptr: ~ArcData<T> = cast::reinterpret_cast(&(*rc).data);
assert ptr.count > 0;
// Cast us back into the correct region
let r = cast::transmute_region(option::get_ref(&ptr.data));
let r = cast::transmute(option::get_ref(&ptr.data));
cast::forget(move ptr);
return cast::transmute_mut(r);
return r;
}
}
#[inline(always)]
@ -376,15 +376,17 @@ impl<T: Owned> Exclusive<T> {
// the exclusive. Supporting that is a work in progress.
#[inline(always)]
unsafe fn with<U>(f: fn(x: &mut T) -> U) -> U {
let rec = unsafe { get_shared_mutable_state(&self.x) };
do rec.lock.lock {
if rec.failed {
die!(~"Poisoned exclusive - another task failed inside!");
unsafe {
let rec = get_shared_mutable_state(&self.x);
do (*rec).lock.lock {
if (*rec).failed {
die!(~"Poisoned exclusive - another task failed inside!");
}
(*rec).failed = true;
let result = f(&mut (*rec).data);
(*rec).failed = false;
move result
}
rec.failed = true;
let result = f(&mut rec.data);
rec.failed = false;
move result
}
}

View file

@ -2071,17 +2071,19 @@ pub mod raw {
/// Appends a byte to a string. (Not UTF-8 safe).
pub unsafe fn push_byte(s: &mut ~str, b: u8) {
reserve_at_least(&mut *s, s.len() + 1);
let new_len = s.len() + 1;
reserve_at_least(&mut *s, new_len);
do as_buf(*s) |buf, len| {
let buf: *mut u8 = ::cast::reinterpret_cast(&buf);
*ptr::mut_offset(buf, len) = b;
}
set_len(&mut *s, s.len() + 1);
set_len(&mut *s, new_len);
}
/// Appends a vector of bytes to a string. (Not UTF-8 safe).
unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
reserve_at_least(&mut *s, s.len() + bytes.len());
let new_len = s.len() + bytes.len();
reserve_at_least(&mut *s, new_len);
for vec::each(bytes) |byte| { push_byte(&mut *s, *byte); }
}

View file

@ -623,13 +623,15 @@ unsafe fn push_fast<T>(v: &mut ~[T], initval: T) {
#[inline(never)]
fn push_slow<T>(v: &mut ~[T], initval: T) {
reserve_at_least(&mut *v, v.len() + 1u);
let new_len = v.len() + 1;
reserve_at_least(&mut *v, new_len);
unsafe { push_fast(v, initval) }
}
#[inline(always)]
pub fn push_all<T: Copy>(v: &mut ~[T], rhs: &[const T]) {
reserve(&mut *v, v.len() + rhs.len());
let new_len = v.len() + rhs.len();
reserve(&mut *v, new_len);
for uint::range(0u, rhs.len()) |i| {
push(&mut *v, unsafe { raw::get(rhs, i) })
@ -638,7 +640,8 @@ pub fn push_all<T: Copy>(v: &mut ~[T], rhs: &[const T]) {
#[inline(always)]
pub fn push_all_move<T>(v: &mut ~[T], mut rhs: ~[T]) {
reserve(&mut *v, v.len() + rhs.len());
let new_len = v.len() + rhs.len();
reserve(&mut *v, new_len);
unsafe {
do as_mut_buf(rhs) |p, len| {
for uint::range(0, len) |i| {
@ -663,9 +666,9 @@ pub fn truncate<T>(v: &mut ~[T], newlen: uint) {
let mut dropped = rusti::init();
dropped <-> *ptr::mut_offset(p, i);
}
raw::set_len(&mut *v, newlen);
}
}
unsafe { raw::set_len(&mut *v, newlen); }
}
/**
@ -740,7 +743,8 @@ pub pure fn append_mut<T: Copy>(lhs: ~[mut T], rhs: &[const T]) -> ~[mut T] {
* * initval - The value for the new elements
*/
pub fn grow<T: Copy>(v: &mut ~[T], n: uint, initval: &T) {
reserve_at_least(&mut *v, v.len() + n);
let new_len = v.len() + n;
reserve_at_least(&mut *v, new_len);
let mut i: uint = 0u;
while i < n {
@ -763,7 +767,8 @@ pub fn grow<T: Copy>(v: &mut ~[T], n: uint, initval: &T) {
* value
*/
pub fn grow_fn<T>(v: &mut ~[T], n: uint, op: iter::InitOp<T>) {
reserve_at_least(&mut *v, v.len() + n);
let new_len = v.len() + n;
reserve_at_least(&mut *v, new_len);
let mut i: uint = 0u;
while i < n {
v.push(op(i));

View file

@ -305,22 +305,31 @@ impl CheckLoanCtxt {
return;
}
match (old_loan.mutbl, new_loan.mutbl) {
(m_const, _) | (_, m_const) | (m_imm, m_imm) => {
/*ok*/
match (old_loan.kind, new_loan.kind) {
(PartialFreeze, PartialTake) | (PartialTake, PartialFreeze) |
(TotalFreeze, PartialFreeze) | (PartialFreeze, TotalFreeze) |
(Immobile, _) | (_, Immobile) |
(PartialFreeze, PartialFreeze) |
(PartialTake, PartialTake) |
(TotalFreeze, TotalFreeze) => {
/* ok */
}
(m_mutbl, m_mutbl) | (m_mutbl, m_imm) | (m_imm, m_mutbl) => {
(PartialTake, TotalFreeze) | (TotalFreeze, PartialTake) |
(TotalTake, TotalFreeze) | (TotalFreeze, TotalTake) |
(TotalTake, PartialFreeze) | (PartialFreeze, TotalTake) |
(TotalTake, PartialTake) | (PartialTake, TotalTake) |
(TotalTake, TotalTake) => {
self.bccx.span_err(
new_loan.cmt.span,
fmt!("loan of %s as %s \
conflicts with prior loan",
self.bccx.cmt_to_str(new_loan.cmt),
self.bccx.mut_to_str(new_loan.mutbl)));
self.bccx.loan_kind_to_str(new_loan.kind)));
self.bccx.span_note(
old_loan.cmt.span,
fmt!("prior loan as %s granted here",
self.bccx.mut_to_str(old_loan.mutbl)));
self.bccx.loan_kind_to_str(old_loan.kind)));
}
}
}
@ -348,13 +357,13 @@ impl CheckLoanCtxt {
// are only assigned once
} else {
match cmt.mutbl {
m_mutbl => { /*ok*/ }
m_const | m_imm => {
self.bccx.span_err(
ex.span,
at.ing_form(self.bccx.cmt_to_str(cmt)));
return;
}
McDeclared | McInherited => { /*ok*/ }
McReadOnly | McImmutable => {
self.bccx.span_err(
ex.span,
at.ing_form(self.bccx.cmt_to_str(cmt)));
return;
}
}
}
@ -428,19 +437,20 @@ impl CheckLoanCtxt {
cmt: cmt,
lp: @loan_path) {
for self.walk_loans_of(ex.id, lp) |loan| {
match loan.mutbl {
m_const => { /*ok*/ }
m_mutbl | m_imm => {
self.bccx.span_err(
ex.span,
fmt!("%s prohibited due to outstanding loan",
at.ing_form(self.bccx.cmt_to_str(cmt))));
self.bccx.span_note(
loan.cmt.span,
fmt!("loan of %s granted here",
self.bccx.cmt_to_str(loan.cmt)));
return;
}
match loan.kind {
Immobile => { /* ok */ }
TotalFreeze | PartialFreeze |
TotalTake | PartialTake => {
self.bccx.span_err(
ex.span,
fmt!("%s prohibited due to outstanding loan",
at.ing_form(self.bccx.cmt_to_str(cmt))));
self.bccx.span_note(
loan.cmt.span,
fmt!("loan of %s granted here",
self.bccx.cmt_to_str(loan.cmt)));
return;
}
}
}

View file

@ -20,7 +20,10 @@ use core::prelude::*;
use middle::borrowck::preserve::{PreserveCondition, PcOk, PcIfPure};
use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl};
use middle::borrowck::{LoanKind, TotalFreeze, PartialFreeze,
TotalTake, PartialTake, Immobile};
use middle::borrowck::{req_maps};
use middle::borrowck::loan;
use middle::mem_categorization::{cat_binding, cat_discr, cmt, comp_variant};
use middle::mem_categorization::{mem_categorization_ctxt};
use middle::mem_categorization::{opt_deref_kind};
@ -340,13 +343,22 @@ impl GatherLoanCtxt {
fn guarantee_valid(@mut self,
cmt: cmt,
req_mutbl: ast::mutability,
scope_r: ty::Region) {
scope_r: ty::Region)
{
let loan_kind = match req_mutbl {
m_mutbl => TotalTake,
m_imm => TotalFreeze,
m_const => Immobile
};
self.bccx.stats.guaranteed_paths += 1;
debug!("guarantee_valid(cmt=%s, req_mutbl=%s, scope_r=%s)",
debug!("guarantee_valid(cmt=%s, req_mutbl=%?, \
loan_kind=%?, scope_r=%s)",
self.bccx.cmt_to_repr(cmt),
self.bccx.mut_to_str(req_mutbl),
req_mutbl,
loan_kind,
region_to_str(self.tcx(), scope_r));
let _i = indenter();
@ -362,10 +374,10 @@ impl GatherLoanCtxt {
// it within that scope, the loan will be detected and an
// error will be reported.
Some(_) => {
match self.bccx.loan(cmt, scope_r, req_mutbl) {
match loan::loan(self.bccx, cmt, scope_r, loan_kind) {
Err(ref e) => { self.bccx.report((*e)); }
Ok(move loans) => {
self.add_loans(cmt, req_mutbl, scope_r, move loans);
self.add_loans(cmt, loan_kind, scope_r, move loans);
}
}
}
@ -378,7 +390,7 @@ impl GatherLoanCtxt {
// pointer is desired, that is ok as long as we are pure)
None => {
let result: bckres<PreserveCondition> = {
do self.check_mutbl(req_mutbl, cmt).chain |pc1| {
do self.check_mutbl(loan_kind, cmt).chain |pc1| {
do self.bccx.preserve(cmt, scope_r,
self.item_ub,
self.root_ub).chain |pc2| {
@ -446,37 +458,41 @@ impl GatherLoanCtxt {
// reqires an immutable pointer, but `f` lives in (aliased)
// mutable memory.
fn check_mutbl(@mut self,
req_mutbl: ast::mutability,
loan_kind: LoanKind,
cmt: cmt)
-> bckres<PreserveCondition> {
debug!("check_mutbl(req_mutbl=%?, cmt.mutbl=%?)",
req_mutbl, cmt.mutbl);
debug!("check_mutbl(loan_kind=%?, cmt.mutbl=%?)",
loan_kind, cmt.mutbl);
if req_mutbl == m_const || req_mutbl == cmt.mutbl {
debug!("required is const or they are the same");
Ok(PcOk)
} else {
let e = bckerr { cmt: cmt, code: err_mutbl(req_mutbl) };
if req_mutbl == m_imm {
// if this is an @mut box, then it's generally OK to borrow as
// &imm; this will result in a write guard
if cmt.cat.is_mutable_box() {
match loan_kind {
Immobile => Ok(PcOk),
TotalTake | PartialTake => {
if cmt.mutbl.is_mutable() {
Ok(PcOk)
} else {
// you can treat mutable things as imm if you are pure
debug!("imm required, must be pure");
Err(bckerr { cmt: cmt, code: err_mutbl(loan_kind) })
}
}
TotalFreeze | PartialFreeze => {
if cmt.mutbl.is_immutable() {
Ok(PcOk)
} else if cmt.cat.is_mutable_box() {
Ok(PcOk)
} else {
// Eventually:
let e = bckerr {cmt: cmt,
code: err_mutbl(loan_kind)};
Ok(PcIfPure(e))
}
} else {
Err(e)
}
}
}
fn add_loans(@mut self,
cmt: cmt,
req_mutbl: ast::mutability,
loan_kind: LoanKind,
scope_r: ty::Region,
+loans: ~[Loan]) {
if loans.len() == 0 {
@ -526,7 +542,7 @@ impl GatherLoanCtxt {
self.add_loans_to_scope_id(scope_id, move loans);
if req_mutbl == m_imm && cmt.mutbl != m_imm {
if loan_kind.is_freeze() && !cmt.mutbl.is_immutable() {
self.bccx.stats.loaned_paths_imm += 1;
if self.tcx().sess.borrowck_note_loan() {
@ -542,7 +558,9 @@ impl GatherLoanCtxt {
fn add_loans_to_scope_id(@mut self,
scope_id: ast::node_id,
+loans: ~[Loan]) {
debug!("adding %u loans to scope_id %?", loans.len(), scope_id);
debug!("adding %u loans to scope_id %?: %s",
loans.len(), scope_id,
str::connect(loans.map(|l| self.bccx.loan_to_repr(l)), ", "));
match self.req_maps.req_loan_map.find(&scope_id) {
Some(req_loans) => {
req_loans.push_all(loans);

View file

@ -44,6 +44,8 @@ FIXME #4730 --- much more needed, don't have time to write this all up now
use core::prelude::*;
use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl};
use middle::borrowck::{LoanKind, TotalFreeze, PartialFreeze,
TotalTake, PartialTake, Immobile};
use middle::borrowck::{err_out_of_scope};
use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp};
use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self};
@ -57,27 +59,26 @@ use core::result::{Err, Ok, Result};
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
impl BorrowckCtxt {
fn loan(&self,
pub fn loan(bccx: @BorrowckCtxt,
cmt: cmt,
scope_region: ty::Region,
mutbl: ast::mutability) -> bckres<~[Loan]> {
let mut lc = LoanContext {
bccx: self,
scope_region: scope_region,
loans: ~[]
};
match lc.loan(cmt, mutbl, true) {
Err(ref e) => return Err((*e)),
Ok(()) => {}
}
// XXX: Workaround for borrow check bug.
Ok(copy lc.loans)
loan_kind: LoanKind) -> bckres<~[Loan]>
{
let mut lc = LoanContext {
bccx: bccx,
scope_region: scope_region,
loans: ~[]
};
match lc.loan(cmt, loan_kind, true) {
Err(ref e) => return Err((*e)),
Ok(()) => {}
}
// XXX: Workaround for borrow check bug.
Ok(copy lc.loans)
}
struct LoanContext {
bccx: &BorrowckCtxt,
bccx: @BorrowckCtxt,
// the region scope for which we must preserve the memory
scope_region: ty::Region,
@ -87,12 +88,13 @@ struct LoanContext {
}
impl LoanContext {
fn tcx(&mut self) -> ty::ctxt { self.bccx.tcx }
fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
fn loan(&mut self,
cmt: cmt,
req_mutbl: ast::mutability,
owns_lent_data: bool) -> bckres<()> {
loan_kind: LoanKind,
owns_lent_data: bool) -> bckres<()>
{
/*!
*
* The main routine.
@ -107,9 +109,9 @@ impl LoanContext {
* discussion in `issue_loan()`.
*/
debug!("loan(%s, %s)",
debug!("loan(%s, %?)",
self.bccx.cmt_to_repr(cmt),
self.bccx.mut_to_str(req_mutbl));
loan_kind);
let _i = indenter();
// see stable() above; should only be called when `cmt` is lendable
@ -127,15 +129,16 @@ impl LoanContext {
~"rvalue with a non-none lp");
}
cat_local(local_id) | cat_arg(local_id) | cat_self(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,
// FIXME(#4903)
let local_scope_id = self.bccx.tcx.region_map.get(&local_id);
self.issue_loan(cmt, ty::re_scope(local_scope_id), loan_kind,
owns_lent_data)
}
cat_stack_upvar(cmt) => {
self.loan(cmt, req_mutbl, owns_lent_data)
self.loan(cmt, loan_kind, owns_lent_data)
}
cat_discr(base, _) => {
self.loan(base, req_mutbl, owns_lent_data)
self.loan(base, loan_kind, owns_lent_data)
}
cat_comp(cmt_base, comp_field(_, m)) |
cat_comp(cmt_base, comp_index(_, m)) => {
@ -145,13 +148,13 @@ impl LoanContext {
// that case, it must also be embedded in an immutable
// location, or else the whole structure could be
// overwritten and the component along with it.
self.loan_stable_comp(cmt, cmt_base, req_mutbl, m,
self.loan_stable_comp(cmt, cmt_base, loan_kind, m,
owns_lent_data)
}
cat_comp(cmt_base, comp_tuple) |
cat_comp(cmt_base, comp_anon_field) => {
// As above.
self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm,
self.loan_stable_comp(cmt, cmt_base, loan_kind, m_imm,
owns_lent_data)
}
cat_comp(cmt_base, comp_variant(enum_did)) => {
@ -159,10 +162,10 @@ impl LoanContext {
// variants, because if the enum value is overwritten then
// the memory changes type.
if ty::enum_is_univariant(self.bccx.tcx, enum_did) {
self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm,
self.loan_stable_comp(cmt, cmt_base, loan_kind, m_imm,
owns_lent_data)
} else {
self.loan_unstable_deref(cmt, cmt_base, req_mutbl,
self.loan_unstable_deref(cmt, cmt_base, loan_kind,
owns_lent_data)
}
}
@ -170,7 +173,7 @@ impl LoanContext {
// For unique pointers, the memory being pointed out is
// unstable because if the unique pointer is overwritten
// then the memory is freed.
self.loan_unstable_deref(cmt, cmt_base, req_mutbl,
self.loan_unstable_deref(cmt, cmt_base, loan_kind,
owns_lent_data)
}
cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => {
@ -178,8 +181,8 @@ impl LoanContext {
// 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, false).chain |_| {
self.issue_loan(cmt, region, m_const, owns_lent_data)
do self.loan(cmt_base, TotalFreeze, false).chain |_| {
self.issue_loan(cmt, region, loan_kind, owns_lent_data)
}
}
cat_deref(_, _, unsafe_ptr) |
@ -199,66 +202,38 @@ impl LoanContext {
fn loan_stable_comp(&mut self,
cmt: cmt,
cmt_base: cmt,
req_mutbl: ast::mutability,
loan_kind: LoanKind,
comp_mutbl: ast::mutability,
owns_lent_data: bool) -> bckres<()> {
// Determine the mutability that the base component must have,
// given the required mutability of the pointer (`req_mutbl`)
// and the declared mutability of the component (`comp_mutbl`).
// This is surprisingly subtle.
//
// Note that the *declared* mutability of the component is not
// necessarily the same as cmt.mutbl, since a component
// declared as immutable but embedded in a mutable context
// becomes mutable. It's best to think of comp_mutbl as being
// either MUTABLE or DEFAULT, not MUTABLE or IMMUTABLE. We
// should really patch up the AST to reflect this distinction.
//
// Let's consider the cases below:
//
// 1. mut required, mut declared: In this case, the base
// component must merely be const. The reason is that it
// does not matter if the base component is borrowed as
// mutable or immutable, as the mutability of the base
// component is overridden in the field declaration itself
// (see `compile-fail/borrowck-mut-field-imm-base.rs`)
//
// 2. mut required, imm declared: This would only be legal if
// the component is embeded in a mutable context. However,
// we detect mismatches between the mutability of the value
// as a whole and the required mutability in `issue_loan()`
// above. In any case, presuming that the component IS
// embedded in a mutable context, both the component and
// the base must be loaned as MUTABLE. This is to ensure
// that there is no loan of the base as IMMUTABLE, which
// would imply that the component must be IMMUTABLE too
// (see `compile-fail/borrowck-imm-field-imm-base.rs`).
//
// 3. mut required, const declared: this shouldn't really be
// possible, since I don't think you can declare a const
// field, but I guess if we DID permit such a declaration
// it would be equivalent to the case above?
//
// 4. imm required, * declared: In this case, the base must be
// immutable. This is true regardless of what was declared
// for this subcomponent, this if the base is mutable, the
// subcomponent must be mutable.
// (see `compile-fail/borrowck-imm-field-mut-base.rs`).
//
// 5. const required, * declared: In this case, the base need
// only be const, since we don't ultimately care whether
// the subcomponent is mutable or not.
let base_mutbl = match (req_mutbl, comp_mutbl) {
(m_mutbl, m_mutbl) => m_const, // (1)
(m_mutbl, _) => m_mutbl, // (2, 3)
(m_imm, _) => m_imm, // (4)
(m_const, _) => m_const // (5)
owns_lent_data: bool) -> bckres<()>
{
let base_kind = match (comp_mutbl, loan_kind) {
// Declared as "immutable" means: inherited mutability and
// hence mutable iff parent is mutable. So propagate
// mutability on up.
(m_imm, TotalFreeze) | (m_imm, PartialFreeze) => PartialFreeze,
(m_imm, TotalTake) | (m_imm, PartialTake) => PartialTake,
// Declared as "mutable" means: always mutable no matter
// what the mutability of the base is. So that means we
// can weaken the condition on the base to PartialFreeze.
// This implies that the user could freeze the base, but
// that is ok since the even with an &T base, the mut
// field will still be considered mutable.
(_, TotalTake) | (_, PartialTake) |
(_, TotalFreeze) | (_, PartialFreeze) => {
PartialFreeze
}
// If we just need to guarantee the value won't be moved,
// it doesn't matter what mutability the component was
// declared with.
(_, Immobile) => Immobile,
};
do self.loan(cmt_base, base_mutbl, owns_lent_data).chain |_ok| {
do self.loan(cmt_base, base_kind, owns_lent_data).chain |_ok| {
// can use static for the scope because the base
// determines the lifetime, ultimately
self.issue_loan(cmt, ty::re_static, req_mutbl,
self.issue_loan(cmt, ty::re_static, loan_kind,
owns_lent_data)
}
}
@ -269,23 +244,23 @@ impl LoanContext {
fn loan_unstable_deref(&mut self,
cmt: cmt,
cmt_base: cmt,
req_mutbl: ast::mutability,
loan_kind: LoanKind,
owns_lent_data: bool) -> bckres<()> {
// Variant components: the base must be immutable, because
// if it is overwritten, the types of the embedded data
// could change.
do self.loan(cmt_base, m_imm, owns_lent_data).chain |_| {
do self.loan(cmt_base, PartialFreeze, owns_lent_data).chain |_| {
// can use static, as in loan_stable_comp()
self.issue_loan(cmt, ty::re_static, req_mutbl,
self.issue_loan(cmt, ty::re_static, loan_kind,
owns_lent_data)
}
}
fn issue_loan(&mut self,
cmt: cmt,
scope_ub: ty::Region,
req_mutbl: ast::mutability,
owns_lent_data: bool) -> bckres<()> {
+cmt: cmt,
+scope_ub: ty::Region,
+loan_kind: LoanKind,
+owns_lent_data: bool) -> bckres<()> {
// Subtle: the `scope_ub` is the maximal lifetime of `cmt`.
// Therefore, if `cmt` owns the data being lent, then the
// scope of the loan must be less than `scope_ub`, or else the
@ -297,25 +272,15 @@ impl LoanContext {
// reborrowed.
if !owns_lent_data ||
self.bccx.is_subregion_of(/*bad*/copy self.scope_region,
scope_ub) {
match req_mutbl {
m_mutbl => {
// We do not allow non-mutable data to be loaned
// out as mutable under any circumstances.
if cmt.mutbl != m_mutbl {
return Err(bckerr {
cmt:cmt,
code:err_mutbl(req_mutbl)
});
}
}
m_const | m_imm => {
// However, mutable data can be loaned out as
// immutable (and any data as const). The
// `check_loans` pass will then guarantee that no
// writes occur for the duration of the loan.
}
self.bccx.is_subregion_of(self.scope_region, scope_ub)
{
if loan_kind.is_take() && !cmt.mutbl.is_mutable() {
// We do not allow non-mutable data to be "taken"
// under any circumstances.
return Err(bckerr {
cmt:cmt,
code:err_mutbl(loan_kind)
});
}
self.loans.push(Loan {
@ -323,8 +288,9 @@ impl LoanContext {
// loan process does not apply at all.
lp: cmt.lp.get(),
cmt: cmt,
mutbl: req_mutbl
kind: loan_kind
});
return Ok(());
} else {
// The loan being requested lives longer than the data

View file

@ -368,7 +368,7 @@ pub enum bckerr_code {
err_mut_uniq,
err_mut_variant,
err_root_not_permitted,
err_mutbl(ast::mutability),
err_mutbl(LoanKind),
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
err_out_of_scope(ty::Region, ty::Region) // superscope, subscope
}
@ -390,8 +390,19 @@ pub enum MoveError {
// shorthand for something that fails with `bckerr` or succeeds with `T`
pub type bckres<T> = Result<T, bckerr>;
#[deriving_eq]
pub enum LoanKind {
TotalFreeze, // Entire path is frozen (borrowed as &T)
PartialFreeze, // Some subpath is frozen (borrowed as &T)
TotalTake, // Entire path is "taken" (borrowed as &mut T)
PartialTake, // Some subpath is "taken" (borrowed as &mut T)
Immobile // Path cannot be moved (borrowed as &const T)
}
/// a complete record of a loan that was granted
pub struct Loan {lp: @loan_path, cmt: cmt, mutbl: ast::mutability}
pub struct Loan {lp: @loan_path,
cmt: cmt,
kind: LoanKind}
/// maps computed by `gather_loans` that are then used by `check_loans`
///
@ -420,6 +431,22 @@ pub fn save_and_restore_managed<T:Copy,U>(save_and_restore_t: @mut T,
move u
}
impl LoanKind {
fn is_freeze(&self) -> bool {
match *self {
TotalFreeze | PartialFreeze => true,
_ => false
}
}
fn is_take(&self) -> bool {
match *self {
TotalTake | PartialTake => true,
_ => false
}
}
}
/// Creates and returns a new root_map
pub impl root_map_key : to_bytes::IterBytes {
@ -520,9 +547,9 @@ pub impl BorrowckCtxt {
fn bckerr_to_str(&self, err: bckerr) -> ~str {
match err.code {
err_mutbl(req) => {
err_mutbl(lk) => {
fmt!("creating %s alias to %s",
self.mut_to_str(req),
self.loan_kind_to_str(lk),
self.cmt_to_str(err.cmt))
}
err_mut_uniq => {
@ -599,9 +626,17 @@ pub impl BorrowckCtxt {
mc.mut_to_str(mutbl)
}
fn loan_kind_to_str(&self, lk: LoanKind) -> ~str {
match lk {
TotalFreeze | PartialFreeze => ~"immutable",
TotalTake | PartialTake => ~"mutable",
Immobile => ~"read-only"
}
}
fn loan_to_repr(&self, loan: &Loan) -> ~str {
fmt!("Loan(lp=%?, cmt=%s, mutbl=%?)",
loan.lp, self.cmt_to_repr(loan.cmt), loan.mutbl)
fmt!("Loan(lp=%?, cmt=%s, kind=%?)",
loan.lp, self.cmt_to_repr(loan.cmt), loan.kind)
}
}

View file

@ -190,10 +190,10 @@ impl PreserveCtxt {
// otherwise we have no guarantee the pointer will stay
// live, so we must root the pointer (i.e., inc the ref
// count) for the duration of the loan.
debug!("base.mutbl = %?", self.bccx.mut_to_str(base.mutbl));
debug!("base.mutbl = %?", base.mutbl);
if cmt.cat.derefs_through_mutable_box() {
self.attempt_root(cmt, base, derefs)
} else if base.mutbl == m_imm {
} else if base.mutbl.is_immutable() {
let non_rooting_ctxt = PreserveCtxt {
root_managed_data: false,
..*self
@ -293,14 +293,11 @@ impl PreserveCtxt {
// the base is preserved, but if we are not mutable then
// purity is required
Ok(PcOk) => {
match cmt_base.mutbl {
m_mutbl | m_const => {
Ok(PcIfPure(bckerr {cmt:cmt, code:code}))
if !cmt_base.mutbl.is_immutable() {
Ok(PcIfPure(bckerr {cmt:cmt, code:code}))
} else {
Ok(PcOk)
}
m_imm => {
Ok(PcOk)
}
}
}
// the base requires purity too, that's fine

View file

@ -108,6 +108,14 @@ pub enum special_kind {
sk_heap_upvar
}
#[deriving_eq]
pub enum MutabilityCategory {
McImmutable, // Immutable.
McReadOnly, // Read-only (`const`)
McDeclared, // Directly declared as mutable.
McInherited // Inherited from the fact that owner is mutable.
}
// a complete categorization of a value indicating where it originated
// and how it is located, as well as the mutability of the memory in
// which the value is stored.
@ -115,12 +123,12 @@ pub enum special_kind {
// note: cmt stands for "categorized mutable type".
#[deriving_eq]
pub struct cmt_ {
id: ast::node_id, // id of expr/pat producing this value
span: span, // span of same expr/pat
cat: categorization, // categorization of expr
lp: Option<@loan_path>, // loan path for expr, if any
mutbl: ast::mutability, // mutability of expr as lvalue
ty: ty::t // type of the expr
id: ast::node_id, // id of expr/pat producing this value
span: span, // span of same expr/pat
cat: categorization, // categorization of expr
lp: Option<@loan_path>, // loan path for expr, if any
mutbl: MutabilityCategory, // mutability of expr as lvalue
ty: ty::t // type of the expr
}
pub type cmt = @cmt_;
@ -298,8 +306,55 @@ pub struct mem_categorization_ctxt {
method_map: typeck::method_map,
}
pub impl &mem_categorization_ctxt {
fn cat_expr(expr: @ast::expr) -> cmt {
impl ToStr for MutabilityCategory {
pure fn to_str(&self) -> ~str {
fmt!("%?", *self)
}
}
impl MutabilityCategory {
static fn from_mutbl(m: ast::mutability) -> MutabilityCategory {
match m {
m_imm => McImmutable,
m_const => McReadOnly,
m_mutbl => McDeclared
}
}
fn inherit(&self) -> MutabilityCategory {
match *self {
McImmutable => McImmutable,
McReadOnly => McReadOnly,
McDeclared => McInherited,
McInherited => McInherited
}
}
fn is_mutable(&self) -> bool {
match *self {
McImmutable | McReadOnly => false,
McDeclared | McInherited => true
}
}
fn is_immutable(&self) -> bool {
match *self {
McImmutable => true,
McReadOnly | McDeclared | McInherited => false
}
}
fn to_user_str(&self) -> ~str {
match *self {
McDeclared | McInherited => ~"mutable",
McImmutable => ~"immutable",
McReadOnly => ~"const"
}
}
}
pub impl mem_categorization_ctxt {
fn cat_expr(&self, expr: @ast::expr) -> cmt {
match self.tcx.adjustments.find(&expr.id) {
None => {
// No adjustments.
@ -323,7 +378,8 @@ pub impl &mem_categorization_ctxt {
}
}
fn cat_expr_autoderefd(expr: @ast::expr,
fn cat_expr_autoderefd(&self,
expr: @ast::expr,
adjustment: &ty::AutoAdjustment) -> cmt {
let mut cmt = self.cat_expr_unadjusted(expr);
for uint::range(1, adjustment.autoderefs+1) |deref| {
@ -332,7 +388,7 @@ pub impl &mem_categorization_ctxt {
return cmt;
}
fn cat_expr_unadjusted(expr: @ast::expr) -> cmt {
fn cat_expr_unadjusted(&self, expr: @ast::expr) -> cmt {
debug!("cat_expr: id=%d expr=%s",
expr.id, pprust::expr_to_str(expr, self.tcx.sess.intr()));
@ -392,7 +448,8 @@ pub impl &mem_categorization_ctxt {
}
}
fn cat_def(id: ast::node_id,
fn cat_def(&self,
id: ast::node_id,
span: span,
expr_ty: ty::t,
def: ast::def) -> cmt {
@ -409,7 +466,7 @@ pub impl &mem_categorization_ctxt {
span:span,
cat:cat_special(sk_static_item),
lp:None,
mutbl:m_imm,
mutbl: McImmutable,
ty:expr_ty
}
}
@ -420,7 +477,7 @@ pub impl &mem_categorization_ctxt {
// m: mutability of the argument
// lp: loan path, must be none for aliasable things
let m = if mutbl {m_mutbl} else {m_imm};
let m = if mutbl {McDeclared} else {McImmutable};
let lp = match ty::resolved_mode(self.tcx, mode) {
ast::by_copy => Some(@lp_arg(vid)),
ast::by_ref => None,
@ -438,7 +495,7 @@ pub impl &mem_categorization_ctxt {
span:span,
cat:cat_arg(vid),
lp:lp,
mutbl:m,
mutbl: m,
ty:expr_ty
}
}
@ -458,7 +515,7 @@ pub impl &mem_categorization_ctxt {
span:span,
cat:cat,
lp:loan_path,
mutbl:m_imm,
mutbl: McImmutable,
ty:expr_ty
}
}
@ -485,7 +542,7 @@ pub impl &mem_categorization_ctxt {
span:span,
cat:cat_special(sk_heap_upvar),
lp:None,
mutbl:m_imm,
mutbl:McImmutable,
ty:expr_ty
}
}
@ -493,7 +550,7 @@ pub impl &mem_categorization_ctxt {
}
ast::def_local(vid, mutbl) => {
let m = if mutbl {m_mutbl} else {m_imm};
let m = if mutbl {McDeclared} else {McImmutable};
@cmt_ {
id:id,
span:span,
@ -511,14 +568,15 @@ pub impl &mem_categorization_ctxt {
span:span,
cat:cat_local(vid),
lp:Some(@lp_local(vid)),
mutbl:m_imm,
mutbl:McImmutable,
ty:expr_ty
}
}
}
}
fn cat_variant<N: ast_node>(arg: N,
fn cat_variant<N: ast_node>(&self,
arg: N,
enum_did: ast::def_id,
cmt: cmt) -> cmt {
@cmt_ {
@ -526,18 +584,18 @@ pub impl &mem_categorization_ctxt {
span: arg.span(),
cat: cat_comp(cmt, comp_variant(enum_did)),
lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ),
mutbl: cmt.mutbl, // imm iff in an immutable context
mutbl: cmt.mutbl.inherit(),
ty: self.tcx.ty(arg)
}
}
fn cat_rvalue<N: ast_node>(elt: N, expr_ty: ty::t) -> cmt {
fn cat_rvalue<N: ast_node>(&self, elt: N, expr_ty: ty::t) -> cmt {
@cmt_ {
id:elt.id(),
span:elt.span(),
cat:cat_rvalue,
lp:None,
mutbl:m_imm,
mutbl:McImmutable,
ty:expr_ty
}
}
@ -546,17 +604,21 @@ pub impl &mem_categorization_ctxt {
/// component is inherited from the base it is a part of. For
/// example, a record field is mutable if it is declared mutable
/// or if the container is mutable.
fn inherited_mutability(base_m: ast::mutability,
comp_m: ast::mutability) -> ast::mutability {
fn inherited_mutability(&self,
base_m: MutabilityCategory,
comp_m: ast::mutability) -> MutabilityCategory
{
match comp_m {
m_imm => {base_m} // imm: as mutable as the container
m_mutbl | m_const => {comp_m}
m_imm => base_m.inherit(),
m_const => McReadOnly,
m_mutbl => McDeclared
}
}
/// The `field_id` parameter is the ID of the enclosing expression or
/// pattern. It is used to determine which variant of an enum is in use.
fn cat_field<N:ast_node>(node: N,
fn cat_field<N:ast_node>(&self,
node: N,
base_cmt: cmt,
f_name: ast::ident,
field_id: ast::node_id) -> cmt {
@ -584,7 +646,8 @@ pub impl &mem_categorization_ctxt {
}
}
fn cat_deref_fn<N:ast_node>(node: N,
fn cat_deref_fn<N:ast_node>(&self,
node: N,
base_cmt: cmt,
deref_cnt: uint) -> cmt
{
@ -594,11 +657,13 @@ pub impl &mem_categorization_ctxt {
// know what type lies at the other end, so we just call it
// `()` (the empty tuple).
let mt = ty::mt {ty: ty::mk_tup(self.tcx, ~[]), mutbl: m_imm};
let mt = ty::mt {ty: ty::mk_tup(self.tcx, ~[]),
mutbl: m_imm};
return self.cat_deref_common(node, base_cmt, deref_cnt, mt);
}
fn cat_deref<N:ast_node>(node: N,
fn cat_deref<N:ast_node>(&self,
node: N,
base_cmt: cmt,
deref_cnt: uint) -> cmt
{
@ -615,7 +680,8 @@ pub impl &mem_categorization_ctxt {
return self.cat_deref_common(node, base_cmt, deref_cnt, mt);
}
fn cat_deref_common<N:ast_node>(node: N,
fn cat_deref_common<N:ast_node>(&self,
node: N,
base_cmt: cmt,
deref_cnt: uint,
mt: ty::mt) -> cmt
@ -644,7 +710,7 @@ pub impl &mem_categorization_ctxt {
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
}
gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => {
mt.mutbl
MutabilityCategory::from_mutbl(mt.mutbl)
}
};
@ -673,7 +739,9 @@ pub impl &mem_categorization_ctxt {
}
}
fn cat_index<N: ast_node>(elt: N, base_cmt: cmt) -> cmt {
fn cat_index<N: ast_node>(&self,
elt: N,
base_cmt: cmt) -> cmt {
let mt = match ty::index(self.tcx, base_cmt.ty) {
Some(mt) => mt,
None => {
@ -700,7 +768,7 @@ pub impl &mem_categorization_ctxt {
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
}
gc_ptr(_) | region_ptr(_, _) | unsafe_ptr => {
mt.mutbl
MutabilityCategory::from_mutbl(mt.mutbl)
}
};
@ -714,21 +782,21 @@ pub impl &mem_categorization_ctxt {
ty:mt.ty
};
comp(elt, deref_cmt, base_cmt.ty, m, mt.ty)
comp(elt, deref_cmt, base_cmt.ty, m, mt)
}
deref_comp(_) => {
// fixed-length vectors have no deref
let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl);
comp(elt, base_cmt, base_cmt.ty, m, mt.ty)
comp(elt, base_cmt, base_cmt.ty, m, mt)
}
};
fn comp<N: ast_node>(elt: N, of_cmt: cmt,
vect: ty::t, mutbl: ast::mutability,
ty: ty::t) -> cmt
vect: ty::t, mutbl: MutabilityCategory,
mt: ty::mt) -> cmt
{
let comp = comp_index(vect, mutbl);
let comp = comp_index(vect, mt.mutbl);
let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) );
@cmt_ {
id:elt.id(),
@ -736,46 +804,55 @@ pub impl &mem_categorization_ctxt {
cat:cat_comp(of_cmt, comp),
lp:index_lp,
mutbl:mutbl,
ty:ty
ty:mt.ty
}
}
}
fn cat_tuple_elt<N: ast_node>(elt: N, cmt: cmt) -> cmt {
fn cat_tuple_elt<N: ast_node>(&self,
elt: N,
cmt: cmt) -> cmt {
@cmt_ {
id: elt.id(),
span: elt.span(),
cat: cat_comp(cmt, comp_tuple),
lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ),
mutbl: cmt.mutbl, // imm iff in an immutable context
mutbl: cmt.mutbl.inherit(),
ty: self.tcx.ty(elt)
}
}
fn cat_anon_struct_field<N: ast_node>(elt: N, cmt: cmt) -> cmt {
fn cat_anon_struct_field<N: ast_node>(&self,
elt: N,
cmt: cmt) -> cmt {
@cmt_ {
id: elt.id(),
span: elt.span(),
cat: cat_comp(cmt, comp_anon_field),
lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)),
mutbl: cmt.mutbl, // imm iff in an immutable context
mutbl: cmt.mutbl.inherit(),
ty: self.tcx.ty(elt)
}
}
fn cat_method_ref(expr: @ast::expr, expr_ty: ty::t) -> cmt {
fn cat_method_ref(&self,
expr: @ast::expr,
expr_ty: ty::t) -> cmt {
@cmt_ {
id:expr.id,
span:expr.span,
cat:cat_special(sk_method),
lp:None,
mutbl:m_imm,
mutbl:McImmutable,
ty:expr_ty
}
}
fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
fn cat_pattern(&self,
cmt: cmt,
pat: @ast::pat,
op: fn(cmt, @ast::pat))
{
// Here, `cmt` is the categorization for the value being
// matched and pat is the pattern it is being matched against.
//
@ -901,7 +978,7 @@ pub impl &mem_categorization_ctxt {
}
}
fn cat_to_repr(cat: categorization) -> ~str {
fn cat_to_repr(&self, cat: categorization) -> ~str {
match cat {
cat_special(sk_method) => ~"method",
cat_special(sk_static_item) => ~"static_item",
@ -924,7 +1001,7 @@ pub impl &mem_categorization_ctxt {
}
}
fn mut_to_str(mutbl: ast::mutability) -> ~str {
fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
match mutbl {
m_mutbl => ~"mutable",
m_const => ~"const",
@ -932,7 +1009,7 @@ pub impl &mem_categorization_ctxt {
}
}
fn ptr_sigil(ptr: ptr_kind) -> ~str {
fn ptr_sigil(&self, ptr: ptr_kind) -> ~str {
match ptr {
uniq_ptr => ~"~",
gc_ptr(_) => ~"@",
@ -941,7 +1018,7 @@ pub impl &mem_categorization_ctxt {
}
}
fn comp_to_repr(comp: comp_kind) -> ~str {
fn comp_to_repr(&self, comp: comp_kind) -> ~str {
match comp {
comp_field(fld, _) => self.tcx.sess.str_of(fld),
comp_index(*) => ~"[]",
@ -951,7 +1028,7 @@ pub impl &mem_categorization_ctxt {
}
}
fn lp_to_str(lp: @loan_path) -> ~str {
fn lp_to_str(&self, lp: @loan_path) -> ~str {
match *lp {
lp_local(node_id) => {
fmt!("local(%d)", node_id)
@ -971,17 +1048,17 @@ pub impl &mem_categorization_ctxt {
}
}
fn cmt_to_repr(cmt: cmt) -> ~str {
fmt!("{%s id:%d m:%s lp:%s ty:%s}",
fn cmt_to_repr(&self, cmt: cmt) -> ~str {
fmt!("{%s id:%d m:%? lp:%s ty:%s}",
self.cat_to_repr(cmt.cat),
cmt.id,
self.mut_to_str(cmt.mutbl),
cmt.mutbl,
cmt.lp.map_default(~"none", |p| self.lp_to_str(*p) ),
ty_to_str(self.tcx, cmt.ty))
}
fn cmt_to_str(cmt: cmt) -> ~str {
let mut_str = self.mut_to_str(cmt.mutbl);
fn cmt_to_str(&self, cmt: cmt) -> ~str {
let mut_str = cmt.mutbl.to_user_str();
match cmt.cat {
cat_special(sk_method) => ~"method",
cat_special(sk_static_item) => ~"static item",
@ -1016,7 +1093,7 @@ pub impl &mem_categorization_ctxt {
}
}
fn region_to_str(r: ty::Region) -> ~str {
fn region_to_str(&self, r: ty::Region) -> ~str {
region_to_str(self.tcx, r)
}
}

View file

@ -116,26 +116,26 @@ pub impl Reflector {
fn bracketed(&mut self,
bracket_name: ~str,
+extra: ~[ValueRef],
inner: &fn()) {
inner: &fn(&mut Reflector)) {
// XXX: Bad copy.
self.visit(~"enter_" + bracket_name, copy extra);
inner();
inner(self);
self.visit(~"leave_" + bracket_name, extra);
}
fn vstore_name_and_extra(&mut self,
t: ty::t,
vstore: ty::vstore,
f: fn(+s: ~str,+v: ~[ValueRef])) {
vstore: ty::vstore) -> (~str, ~[ValueRef])
{
match vstore {
ty::vstore_fixed(n) => {
let extra = vec::append(~[self.c_uint(n)],
self.c_size_and_align(t));
f(~"fixed", extra)
}
ty::vstore_slice(_) => f(~"slice", ~[]),
ty::vstore_uniq => f(~"uniq", ~[]),
ty::vstore_box => f(~"box", ~[])
ty::vstore_fixed(n) => {
let extra = vec::append(~[self.c_uint(n)],
self.c_size_and_align(t));
(~"fixed", extra)
}
ty::vstore_slice(_) => (~"slice", ~[]),
ty::vstore_uniq => (~"uniq", ~[]),
ty::vstore_box => (~"box", ~[])
}
}
@ -168,47 +168,60 @@ pub impl Reflector {
ty::ty_float(ast::ty_f32) => self.leaf(~"f32"),
ty::ty_float(ast::ty_f64) => self.leaf(~"f64"),
ty::ty_unboxed_vec(mt) => self.visit(~"vec", self.c_mt(mt)),
ty::ty_unboxed_vec(mt) => {
let values = self.c_mt(mt);
self.visit(~"vec", values)
}
ty::ty_estr(vst) => {
do self.vstore_name_and_extra(t, vst) |name, extra| {
self.visit(~"estr_" + name, extra)
}
let (name, extra) = self.vstore_name_and_extra(t, vst);
self.visit(~"estr_" + name, extra)
}
ty::ty_evec(mt, vst) => {
do self.vstore_name_and_extra(t, vst) |name, extra| {
self.visit(~"evec_" + name, extra +
self.c_mt(mt))
}
let (name, extra) = self.vstore_name_and_extra(t, vst);
let extra = extra + self.c_mt(mt);
self.visit(~"evec_" + name, extra)
}
ty::ty_box(mt) => {
let extra = self.c_mt(mt);
self.visit(~"box", extra)
}
ty::ty_uniq(mt) => {
let extra = self.c_mt(mt);
self.visit(~"uniq", extra)
}
ty::ty_ptr(mt) => {
let extra = self.c_mt(mt);
self.visit(~"ptr", extra)
}
ty::ty_rptr(_, mt) => {
let extra = self.c_mt(mt);
self.visit(~"rptr", extra)
}
ty::ty_box(mt) => self.visit(~"box", self.c_mt(mt)),
ty::ty_uniq(mt) => self.visit(~"uniq", self.c_mt(mt)),
ty::ty_ptr(mt) => self.visit(~"ptr", self.c_mt(mt)),
ty::ty_rptr(_, mt) => self.visit(~"rptr", self.c_mt(mt)),
ty::ty_rec(fields) => {
do self.bracketed(~"rec",
~[self.c_uint(vec::len(fields))]
+ self.c_size_and_align(t)) {
let extra = ~[self.c_uint(vec::len(fields))]
+ self.c_size_and_align(t);
do self.bracketed(~"rec", extra) |this| {
for fields.eachi |i, field| {
self.visit(~"rec_field",
~[self.c_uint(i),
self.c_slice(
bcx.ccx().sess.str_of(field.ident))]
+ self.c_mt(field.mt));
let extra = ~[this.c_uint(i),
this.c_slice(
bcx.ccx().sess.str_of(field.ident))]
+ this.c_mt(field.mt);
this.visit(~"rec_field", extra);
}
}
}
ty::ty_tup(tys) => {
do self.bracketed(~"tup",
~[self.c_uint(vec::len(tys))]
+ self.c_size_and_align(t)) {
for tys.eachi |i, t| {
self.visit(~"tup_field",
~[self.c_uint(i),
self.c_tydesc(*t)]);
}
}
let extra = ~[self.c_uint(vec::len(tys))]
+ self.c_size_and_align(t);
do self.bracketed(~"tup", extra) |this| {
for tys.eachi |i, t| {
let extra = ~[this.c_uint(i), this.c_tydesc(*t)];
this.visit(~"tup_field", extra);
}
}
}
// FIXME (#2594): fetch constants out of intrinsic
@ -242,20 +255,21 @@ pub impl Reflector {
}
ty::ty_struct(did, ref substs) => {
let bcx = self.bcx;
let tcx = bcx.ccx().tcx;
let fields = ty::struct_fields(tcx, did, substs);
let bcx = self.bcx;
let tcx = bcx.ccx().tcx;
let fields = ty::struct_fields(tcx, did, substs);
do self.bracketed(~"class", ~[self.c_uint(fields.len())]
+ self.c_size_and_align(t)) {
for fields.eachi |i, field| {
self.visit(~"class_field",
~[self.c_uint(i),
self.c_slice(
bcx.ccx().sess.str_of(field.ident))]
+ self.c_mt(field.mt));
}
}
let extra = ~[self.c_uint(fields.len())]
+ self.c_size_and_align(t);
do self.bracketed(~"class", extra) |this| {
for fields.eachi |i, field| {
let extra = ~[this.c_uint(i),
this.c_slice(
bcx.ccx().sess.str_of(field.ident))]
+ this.c_mt(field.mt);
this.visit(~"class_field", extra);
}
}
}
// FIXME (#2595): visiting all the variants in turn is probably
@ -267,20 +281,20 @@ pub impl Reflector {
let tcx = bcx.ccx().tcx;
let variants = ty::substd_enum_variants(tcx, did, substs);
do self.bracketed(~"enum",
~[self.c_uint(vec::len(variants))]
+ self.c_size_and_align(t)) {
let extra = ~[self.c_uint(vec::len(variants))]
+ self.c_size_and_align(t);
do self.bracketed(~"enum", extra) |this| {
for variants.eachi |i, v| {
do self.bracketed(~"enum_variant",
~[self.c_uint(i),
self.c_int(v.disr_val),
self.c_uint(vec::len(v.args)),
self.c_slice(
bcx.ccx().sess.str_of(v.name))]) {
let extra1 = ~[this.c_uint(i),
this.c_int(v.disr_val),
this.c_uint(vec::len(v.args)),
this.c_slice(
bcx.ccx().sess.str_of(v.name))];
do this.bracketed(~"enum_variant", extra1) |this| {
for v.args.eachi |j, a| {
self.visit(~"enum_variant_field",
~[self.c_uint(j),
self.c_tydesc(*a)]);
let extra = ~[this.c_uint(j),
this.c_tydesc(*a)];
this.visit(~"enum_variant_field", extra);
}
}
}
@ -291,13 +305,17 @@ pub impl Reflector {
ty::ty_trait(_, _, _) => self.leaf(~"trait"),
ty::ty_infer(_) => self.leaf(~"infer"),
ty::ty_err => self.leaf(~"err"),
ty::ty_param(p) => self.visit(~"param", ~[self.c_uint(p.idx)]),
ty::ty_param(p) => {
let extra = ~[self.c_uint(p.idx)];
self.visit(~"param", extra)
}
ty::ty_self => self.leaf(~"self"),
ty::ty_type => self.leaf(~"type"),
ty::ty_opaque_box => self.leaf(~"opaque_box"),
ty::ty_opaque_closure_ptr(ck) => {
let ckval = ast_sigil_constant(ck);
self.visit(~"closure_ptr", ~[self.c_uint(ckval)])
let ckval = ast_sigil_constant(ck);
let extra = ~[self.c_uint(ckval)];
self.visit(~"closure_ptr", extra)
}
}
}
@ -312,14 +330,14 @@ pub impl Reflector {
ast::by_copy => 5u
}
};
self.visit(~"fn_input",
~[self.c_uint(i),
let extra = ~[self.c_uint(i),
self.c_uint(modeval),
self.c_tydesc(arg.ty)]);
self.c_tydesc(arg.ty)];
self.visit(~"fn_input", extra);
}
self.visit(~"fn_output",
~[self.c_uint(retval),
self.c_tydesc(sig.output)]);
let extra = ~[self.c_uint(retval),
self.c_tydesc(sig.output)];
self.visit(~"fn_output", extra);
}
}

View file

@ -1938,7 +1938,6 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
}
cache.insert(ty_id, TC_NONE);
debug!("computing contents of %s", ty_to_str(cx, ty));
let _i = indenter();
let mut result = match get(ty).sty {
@ -2089,8 +2088,6 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents {
result = result + TC_BIG;
}
debug!("result = %s", result.to_str());
cache.insert(ty_id, result);
return result;
}

View file

@ -118,11 +118,10 @@ pub impl CombineFields {
// A remains a subtype of B. Actually, there are other options,
// but that's the route we choose to take.
self.infcx.unify(&node_a, &node_b, |new_root, new_rank| {
self.set_var_to_merged_bounds(new_root,
&a_bounds, &b_bounds,
new_rank)
})
let (new_root, new_rank) = self.infcx.unify(&node_a, &node_b);
self.set_var_to_merged_bounds(new_root,
&a_bounds, &b_bounds,
new_rank)
}
/// make variable a subtype of T

View file

@ -832,7 +832,7 @@ pub impl RegionVarBindings {
(re_infer(ReVar(*)), _) | (_, re_infer(ReVar(*))) => {
self.combine_vars(
self.lubs, a, b, span,
|old_r, new_r| self.make_subregion(span, old_r, new_r))
|this, old_r, new_r| this.make_subregion(span, old_r, new_r))
}
_ => {
@ -859,7 +859,7 @@ pub impl RegionVarBindings {
(re_infer(ReVar(*)), _) | (_, re_infer(ReVar(*))) => {
self.combine_vars(
self.glbs, a, b, span,
|old_r, new_r| self.make_subregion(span, new_r, old_r))
|this, old_r, new_r| this.make_subregion(span, new_r, old_r))
}
_ => {
@ -915,7 +915,9 @@ pub impl RegionVarBindings {
a: Region,
b: Region,
span: span,
relate: &fn(old_r: Region, new_r: Region) -> cres<()>)
relate: &fn(self: &mut RegionVarBindings,
old_r: Region,
new_r: Region) -> cres<()>)
-> cres<Region> {
let vars = TwoRegions { a: a, b: b };
match combines.find(&vars) {
@ -926,8 +928,8 @@ pub impl RegionVarBindings {
if self.in_snapshot() {
self.undo_log.push(AddCombination(combines, vars));
}
do relate(a, re_infer(ReVar(c))).then {
do relate(b, re_infer(ReVar(c))).then {
do relate(self, a, re_infer(ReVar(c))).then {
do relate(self, b, re_infer(ReVar(c))).then {
debug!("combine_vars() c=%?", c);
Ok(re_infer(ReVar(c)))
}
@ -1035,7 +1037,8 @@ pub impl RegionVarBindings {
*/
fn resolve_regions(&mut self) {
debug!("RegionVarBindings: resolve_regions()");
self.values.put_back(self.infer_variable_values());
let v = self.infer_variable_values();
self.values.put_back(v);
}
}
@ -1220,7 +1223,7 @@ impl RegionVarBindings {
let mut graph = self.construct_graph();
self.expansion(&mut graph);
self.contraction(&mut graph);
self.extract_values_and_report_conflicts(&mut graph)
self.extract_values_and_report_conflicts(&graph)
}
fn construct_graph(&mut self) -> Graph {
@ -1257,14 +1260,14 @@ impl RegionVarBindings {
for uint::range(0, num_edges) |edge_idx| {
match graph.edges[edge_idx].constraint {
ConstrainVarSubVar(copy a_id, copy b_id) => {
ConstrainVarSubVar(a_id, b_id) => {
insert_edge(&mut graph, a_id, Outgoing, edge_idx);
insert_edge(&mut graph, b_id, Incoming, edge_idx);
}
ConstrainRegSubVar(_, copy b_id) => {
ConstrainRegSubVar(_, b_id) => {
insert_edge(&mut graph, b_id, Incoming, edge_idx);
}
ConstrainVarSubReg(copy a_id, _) => {
ConstrainVarSubReg(a_id, _) => {
insert_edge(&mut graph, a_id, Outgoing, edge_idx);
}
}
@ -1285,17 +1288,17 @@ impl RegionVarBindings {
}
fn expansion(&mut self, graph: &mut Graph) {
do self.iterate_until_fixed_point(~"Expansion", graph) |edge| {
do iterate_until_fixed_point(~"Expansion", graph) |nodes, edge| {
match edge.constraint {
ConstrainRegSubVar(copy a_region, copy b_vid) => {
let b_node = &mut graph.nodes[*b_vid];
ConstrainRegSubVar(a_region, b_vid) => {
let b_node = &mut nodes[*b_vid];
self.expand_node(a_region, b_vid, b_node)
}
ConstrainVarSubVar(copy a_vid, copy b_vid) => {
match graph.nodes[*a_vid].value {
ConstrainVarSubVar(a_vid, b_vid) => {
match nodes[*a_vid].value {
NoValue | ErrorValue => false,
Value(copy a_region) => {
let b_node = &mut graph.nodes[*b_vid];
Value(a_region) => {
let b_node = &mut nodes[*b_vid];
self.expand_node(a_region, b_vid, b_node)
}
}
@ -1325,7 +1328,7 @@ impl RegionVarBindings {
return true;
}
Value(copy cur_region) => {
Value(cur_region) => {
let lub = self.lub_concrete_regions(a_region, cur_region);
if lub == cur_region {
return false;
@ -1345,23 +1348,23 @@ impl RegionVarBindings {
}
fn contraction(&mut self, graph: &mut Graph) {
do self.iterate_until_fixed_point(~"Contraction", graph) |edge| {
do iterate_until_fixed_point(~"Contraction", graph) |nodes, edge| {
match edge.constraint {
ConstrainRegSubVar(*) => {
// This is an expansion constraint. Ignore.
false
}
ConstrainVarSubVar(copy a_vid, copy b_vid) => {
match graph.nodes[*b_vid].value {
ConstrainVarSubVar(a_vid, b_vid) => {
match nodes[*b_vid].value {
NoValue | ErrorValue => false,
Value(copy b_region) => {
let a_node = &mut graph.nodes[*a_vid];
Value(b_region) => {
let a_node = &mut nodes[*a_vid];
self.contract_node(a_vid, a_node, b_region)
}
}
}
ConstrainVarSubReg(copy a_vid, copy b_region) => {
let a_node = &mut graph.nodes[*a_vid];
ConstrainVarSubReg(a_vid, b_region) => {
let a_node = &mut nodes[*a_vid];
self.contract_node(a_vid, a_node, b_region)
}
}
@ -1387,7 +1390,7 @@ impl RegionVarBindings {
false // no change
}
Value(copy a_region) => {
Value(a_region) => {
match a_node.classification {
Expanding => {
check_node(self, a_vid, a_node, a_region, b_region)
@ -1438,29 +1441,10 @@ impl RegionVarBindings {
}
}
fn iterate_until_fixed_point(&mut self,
tag: ~str,
graph: &mut Graph,
body: &fn(edge: &GraphEdge) -> bool) {
let mut iteration = 0;
let mut changed = true;
let num_edges = graph.edges.len();
while changed {
changed = false;
iteration += 1;
debug!("---- %s Iteration #%u", tag, iteration);
for uint::range(0, num_edges) |edge_idx| {
changed |= body(&graph.edges[edge_idx]);
debug!(" >> Change after edge #%?: %?",
edge_idx, graph.edges[edge_idx]);
}
}
debug!("---- %s Complete after %u iteration(s)", tag, iteration);
}
fn extract_values_and_report_conflicts(&mut self,
graph: &mut Graph)
-> ~[GraphNodeValue] {
fn extract_values_and_report_conflicts(
&mut self,
graph: &Graph) -> ~[GraphNodeValue]
{
let dup_map = TwoRegionsMap();
graph.nodes.mapi(|idx, node| {
match node.value {
@ -1525,7 +1509,7 @@ impl RegionVarBindings {
}
fn report_error_for_expanding_node(&mut self,
graph: &mut Graph,
graph: &Graph,
dup_map: TwoRegionsMap,
node_idx: RegionVid) {
// Errors in expanding nodes result from a lower-bound that is
@ -1578,7 +1562,7 @@ impl RegionVarBindings {
}
fn report_error_for_contracting_node(&mut self,
graph: &mut Graph,
graph: &Graph,
dup_map: TwoRegionsMap,
node_idx: RegionVid) {
// Errors in contracting nodes result from two upper-bounds
@ -1632,7 +1616,7 @@ impl RegionVarBindings {
}
fn collect_concrete_regions(&mut self,
graph: &mut Graph,
graph: &Graph,
orig_node_idx: RegionVid,
dir: Direction)
-> ~[SpannedRegion] {
@ -1676,7 +1660,7 @@ impl RegionVarBindings {
}
fn each_edge(&mut self,
graph: &mut Graph,
graph: &Graph,
node_idx: RegionVid,
dir: Direction,
op: fn(edge: &GraphEdge) -> bool) {
@ -1690,3 +1674,25 @@ impl RegionVarBindings {
}
}
}
fn iterate_until_fixed_point(
tag: ~str,
graph: &mut Graph,
body: &fn(nodes: &mut [GraphNode], edge: &GraphEdge) -> bool)
{
let mut iteration = 0;
let mut changed = true;
let num_edges = graph.edges.len();
while changed {
changed = false;
iteration += 1;
debug!("---- %s Iteration #%u", tag, iteration);
for uint::range(0, num_edges) |edge_idx| {
changed |= body(graph.nodes, &graph.edges[edge_idx]);
debug!(" >> Change after edge #%?: %?",
edge_idx, graph.edges[edge_idx]);
}
}
debug!("---- %s Complete after %u iteration(s)", tag, iteration);
}

View file

@ -43,9 +43,10 @@ pub trait UnifyVid<T> {
}
pub impl InferCtxt {
fn get<T:Copy, V:Copy Eq Vid UnifyVid<T>>(&mut self,
+vid: V)
-> Node<V, T> {
fn get<T:Copy, V:Copy+Eq+Vid+UnifyVid<T>>(
&mut self,
+vid: V) -> Node<V, T>
{
/*!
*
* Find the root node for `vid`. This uses the standard
@ -53,27 +54,38 @@ pub impl InferCtxt {
* http://en.wikipedia.org/wiki/Disjoint-set_data_structure
*/
let tcx = self.tcx;
let vb = UnifyVid::appropriate_vals_and_bindings(self);
let vid_u = vid.to_uint();
match vb.vals.find(vid_u) {
None => {
self.tcx.sess.bug(fmt!("failed lookup of vid `%u`", vid_u));
}
Some(ref var_val) => {
match (*var_val) {
Redirect(vid) => {
let node: Node<V,T> = self.get(vid);
if node.root != vid {
// Path compression
vb.vals.insert(vid.to_uint(), Redirect(node.root));
return helper(tcx, vb, vid);
fn helper<T:Copy, V:Copy+Eq+Vid>(
tcx: ty::ctxt,
vb: &mut ValsAndBindings<V,T>,
vid: V) -> Node<V, T>
{
let vid_u = vid.to_uint();
match vb.vals.find(vid_u) {
None => {
tcx.sess.bug(fmt!(
"failed lookup of vid `%u`", vid_u));
}
Some(ref var_val) => {
match *var_val {
Redirect(vid) => {
let node: Node<V,T> = helper(tcx, vb, vid);
if node.root != vid {
// Path compression
vb.vals.insert(vid.to_uint(),
Redirect(node.root));
}
node
}
Root(ref pt, rk) => {
Node {root: vid, possible_types: *pt, rank: rk}
}
}
}
node
}
Root(ref pt, rk) => {
Node {root: vid, possible_types: *pt, rank: rk}
}
}
}
}
}
@ -86,21 +98,22 @@ pub impl InferCtxt {
* Sets the value for `vid` to `new_v`. `vid` MUST be a root node!
*/
let vb = UnifyVid::appropriate_vals_and_bindings(self);
let old_v = vb.vals.get(vid.to_uint());
vb.bindings.push((vid, old_v));
vb.vals.insert(vid.to_uint(), new_v);
debug!("Updating variable %s to %s",
vid.to_str(), new_v.inf_str(self));
debug!("Updating variable %s from %s to %s",
vid.to_str(), old_v.inf_str(self), new_v.inf_str(self));
{ // FIXME(#4903)---borrow checker is not flow sensitive
let vb = UnifyVid::appropriate_vals_and_bindings(self);
let old_v = vb.vals.get(vid.to_uint());
vb.bindings.push((vid, old_v));
vb.vals.insert(vid.to_uint(), new_v);
}
}
fn unify<T:Copy InferStr, V:Copy Vid ToStr UnifyVid<T>, R>(
&mut self,
node_a: &Node<V, T>,
node_b: &Node<V, T>,
op: &fn(new_root: V, new_rank: uint) -> R
) -> R {
fn unify<T:Copy InferStr, V:Copy Vid ToStr UnifyVid<T>>(
&mut self,
node_a: &Node<V, T>,
node_b: &Node<V, T>) -> (V, uint)
{
// Rank optimization: if you don't know what it is, check
// out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
@ -113,17 +126,17 @@ pub impl InferCtxt {
// a has greater rank, so a should become b's parent,
// i.e., b should redirect to a.
self.set(node_b.root, Redirect(node_a.root));
op(node_a.root, node_a.rank)
(node_a.root, node_a.rank)
} else if node_a.rank < node_b.rank {
// b has greater rank, so a should redirect to b.
self.set(node_a.root, Redirect(node_b.root));
op(node_b.root, node_b.rank)
(node_b.root, node_b.rank)
} else {
// If equal, redirect one to the other and increment the
// other's rank.
assert node_a.rank == node_b.rank;
self.set(node_b.root, Redirect(node_a.root));
op(node_a.root, node_a.rank + 1)
(node_a.root, node_a.rank + 1)
}
}
@ -183,9 +196,8 @@ pub impl InferCtxt {
}
};
self.unify(&node_a, &node_b, |new_root, new_rank| {
self.set(new_root, Root(combined, new_rank));
});
let (new_root, new_rank) = self.unify(&node_a, &node_b);
self.set(new_root, Root(combined, new_rank));
return uok();
}

View file

@ -184,25 +184,30 @@ impl<T: Owned> &MutexARC<T> {
*/
#[inline(always)]
unsafe fn access<U>(blk: fn(x: &mut T) -> U) -> U {
let state = unsafe { get_shared_mutable_state(&self.x) };
// Borrowck would complain about this if the function were not already
// unsafe. See borrow_rwlock, far below.
do (&state.lock).lock {
check_poison(true, state.failed);
let _z = PoisonOnFail(&mut state.failed);
blk(&mut state.data)
unsafe {
let state = get_shared_mutable_state(&self.x);
// Borrowck would complain about this if the function were
// not already unsafe. See borrow_rwlock, far below.
do (&(*state).lock).lock {
check_poison(true, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed);
blk(&mut (*state).data)
}
}
}
/// As access(), but with a condvar, as sync::mutex.lock_cond().
#[inline(always)]
unsafe fn access_cond<U>(blk: fn(x: &x/mut T, c: &c/Condvar) -> U) -> U {
let state = unsafe { get_shared_mutable_state(&self.x) };
do (&state.lock).lock_cond |cond| {
check_poison(true, state.failed);
let _z = PoisonOnFail(&mut state.failed);
blk(&mut state.data,
&Condvar { is_mutex: true, failed: &mut state.failed,
cond: cond })
unsafe {
let state = get_shared_mutable_state(&self.x);
do (&(*state).lock).lock_cond |cond| {
check_poison(true, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed);
blk(&mut (*state).data,
&Condvar {is_mutex: true,
failed: &mut (*state).failed,
cond: cond })
}
}
}
}
@ -285,8 +290,10 @@ pub fn RWARC<T: Const Owned>(user_data: T) -> RWARC<T> {
* Create a reader/writer ARC with the supplied data and a specified number
* of condvars (as sync::rwlock_with_condvars).
*/
pub fn rw_arc_with_condvars<T: Const Owned>(user_data: T,
num_condvars: uint) -> RWARC<T> {
pub fn rw_arc_with_condvars<T: Const Owned>(
user_data: T,
num_condvars: uint) -> RWARC<T>
{
let data =
RWARCInner { lock: rwlock_with_condvars(num_condvars),
failed: false, data: move user_data };
@ -315,23 +322,28 @@ impl<T: Const Owned> &RWARC<T> {
*/
#[inline(always)]
fn write<U>(blk: fn(x: &mut T) -> U) -> U {
let state = unsafe { get_shared_mutable_state(&self.x) };
do borrow_rwlock(state).write {
check_poison(false, state.failed);
let _z = PoisonOnFail(&mut state.failed);
blk(&mut state.data)
unsafe {
let state = get_shared_mutable_state(&self.x);
do (*borrow_rwlock(state)).write {
check_poison(false, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed);
blk(&mut (*state).data)
}
}
}
/// As write(), but with a condvar, as sync::rwlock.write_cond().
#[inline(always)]
fn write_cond<U>(blk: fn(x: &x/mut T, c: &c/Condvar) -> U) -> U {
let state = unsafe { get_shared_mutable_state(&self.x) };
do borrow_rwlock(state).write_cond |cond| {
check_poison(false, state.failed);
let _z = PoisonOnFail(&mut state.failed);
blk(&mut state.data,
&Condvar { is_mutex: false, failed: &mut state.failed,
cond: cond })
unsafe {
let state = get_shared_mutable_state(&self.x);
do (*borrow_rwlock(state)).write_cond |cond| {
check_poison(false, (*state).failed);
let _z = PoisonOnFail(&mut (*state).failed);
blk(&mut (*state).data,
&Condvar {is_mutex: false,
failed: &mut (*state).failed,
cond: cond})
}
}
}
/**
@ -369,11 +381,14 @@ impl<T: Const Owned> &RWARC<T> {
* ~~~
*/
fn write_downgrade<U>(blk: fn(v: RWWriteMode<T>) -> U) -> U {
let state = unsafe { get_shared_mutable_state(&self.x) };
do borrow_rwlock(state).write_downgrade |write_mode| {
check_poison(false, state.failed);
blk(RWWriteMode((&mut state.data, move write_mode,
PoisonOnFail(&mut state.failed))))
unsafe {
let state = get_shared_mutable_state(&self.x);
do (*borrow_rwlock(state)).write_downgrade |write_mode| {
check_poison(false, (*state).failed);
blk(RWWriteMode((&mut (*state).data,
move write_mode,
PoisonOnFail(&mut (*state).failed))))
}
}
}
@ -417,8 +432,8 @@ pub fn unwrap_rw_arc<T: Const Owned>(arc: RWARC<T>) -> T {
// lock it. This wraps the unsafety, with the justification that the 'lock'
// field is never overwritten; only 'failed' and 'data'.
#[doc(hidden)]
fn borrow_rwlock<T: Const Owned>(state: &r/mut RWARCInner<T>) -> &r/RWlock {
unsafe { cast::transmute(&mut state.lock) }
fn borrow_rwlock<T: Const Owned>(state: *const RWARCInner<T>) -> *RWlock {
unsafe { cast::transmute(&const (*state).lock) }
}
// FIXME (#3154) ice with struct/&<T> prevents these from being structs.

View file

@ -81,7 +81,8 @@ impl <T: Ord> PriorityQueue<T> {
/// Push an item onto the queue
fn push(&mut self, item: T) {
self.data.push(item);
self.siftup(0, self.len() - 1);
let new_len = self.len() - 1;
self.siftup(0, new_len);
}
/// Optimized version of a push followed by a pop
@ -179,7 +180,8 @@ impl <T: Ord> PriorityQueue<T> {
}
priv fn siftdown(&mut self, pos: uint) {
self.siftdown_range(pos, self.len());
let len = self.len();
self.siftdown_range(pos, len);
}
}

View file

@ -134,10 +134,11 @@ pub impl<V> SmallIntMap<V> {
pub impl<V: Copy> SmallIntMap<V> {
fn update_with_key(&mut self, key: uint, val: V,
ff: fn(uint, V, V) -> V) -> bool {
match self.find(&key) {
None => self.insert(key, val),
Some(orig) => self.insert(key, ff(key, copy *orig, val)),
}
let new_val = match self.find(&key) {
None => val,
Some(orig) => ff(key, *orig, val)
};
self.insert(key, new_val)
}
fn update(&mut self, key: uint, newval: V, ff: fn(V, V) -> V) -> bool {

View file

@ -673,45 +673,45 @@ fn remove<K: Ord, V>(node: &mut Option<~TreeNode<K, V>>, key: &K) -> bool {
}
};
if this {
*node = None;
return true;
}
if !this {
let left_level = save.left.map_default(0, |x| x.level);
let right_level = save.right.map_default(0, |x| x.level);
let left_level = save.left.map_default(0, |x| x.level);
let right_level = save.right.map_default(0, |x| x.level);
// re-balance, if necessary
if left_level < save.level - 1 || right_level < save.level - 1 {
save.level -= 1;
// re-balance, if necessary
if left_level < save.level - 1 || right_level < save.level - 1 {
save.level -= 1;
if right_level > save.level {
do save.right.mutate |mut x| { x.level = save.level; x }
}
skew(save);
match save.right {
Some(ref mut right) => {
skew(right);
match right.right {
Some(ref mut x) => { skew(x) },
None => ()
if right_level > save.level {
do save.right.mutate |mut x| { x.level = save.level; x }
}
skew(save);
match save.right {
Some(ref mut right) => {
skew(right);
match right.right {
Some(ref mut x) => { skew(x) },
None => ()
}
}
None => ()
}
split(save);
match save.right {
Some(ref mut x) => { split(x) },
None => ()
}
}
None => ()
}
split(save);
match save.right {
Some(ref mut x) => { split(x) },
None => ()
}
return removed;
}
removed
}
}
*node = None;
return true;
}
#[cfg(test)]

View file

@ -0,0 +1,124 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
struct Foo {
bar1: Bar,
bar2: Bar
}
struct Bar {
int1: int,
int2: int,
}
fn make_foo() -> ~Foo { die!() }
fn borrow_same_field_twice_mut_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_mut_imm() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_imm_mut() {
let mut foo = make_foo();
let _bar1 = &foo.bar1;
let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_imm_imm() {
let mut foo = make_foo();
let _bar1 = &foo.bar1;
let _bar2 = &foo.bar1;
}
fn borrow_both_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar2;
}
fn borrow_both_mut_pattern() {
let mut foo = make_foo();
match *foo {
Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {}
}
}
fn borrow_var_and_pattern() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
match *foo {
Foo { bar1: ref mut _bar1, bar2: _ } => {}
//~^ ERROR conflicts with prior loan
}
}
fn borrow_mut_and_base_imm() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan
let _foo2 = &*foo; //~ ERROR conflicts with prior loan
}
fn borrow_mut_and_base_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_mut_and_base_mut2() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_mut() {
let mut foo = make_foo();
let _bar1 = &foo.bar1.int1;
let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_mut2() {
let mut foo = make_foo();
let _bar1 = &foo.bar1.int1;
let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_imm() {
let mut foo = make_foo();
let _bar1 = &foo.bar1.int1;
let _foo1 = &foo.bar1;
let _foo2 = &*foo;
}
fn borrow_mut_and_imm() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _foo1 = &foo.bar2;
}
fn borrow_mut_from_imm() {
let foo = make_foo();
let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow
}
fn borrow_long_path_both_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &mut foo.bar2.int2;
}
fn main() {}

View file

@ -0,0 +1,124 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
struct Foo {
bar1: Bar,
bar2: Bar
}
struct Bar {
int1: int,
int2: int,
}
fn make_foo() -> Foo { die!() }
fn borrow_same_field_twice_mut_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_mut_imm() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_imm_mut() {
let mut foo = make_foo();
let _bar1 = &foo.bar1;
let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_imm_imm() {
let mut foo = make_foo();
let _bar1 = &foo.bar1;
let _bar2 = &foo.bar1;
}
fn borrow_both_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar2;
}
fn borrow_both_mut_pattern() {
let mut foo = make_foo();
match foo {
Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {}
}
}
fn borrow_var_and_pattern() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
match foo {
Foo { bar1: ref mut _bar1, bar2: _ } => {}
//~^ ERROR conflicts with prior loan
}
}
fn borrow_mut_and_base_imm() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan
let _foo2 = &foo; //~ ERROR conflicts with prior loan
}
fn borrow_mut_and_base_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_mut_and_base_mut2() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo2 = &mut foo; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_mut() {
let mut foo = make_foo();
let _bar1 = &foo.bar1.int1;
let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_mut2() {
let mut foo = make_foo();
let _bar1 = &foo.bar1.int1;
let _foo2 = &mut foo; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_imm() {
let mut foo = make_foo();
let _bar1 = &foo.bar1.int1;
let _foo1 = &foo.bar1;
let _foo2 = &foo;
}
fn borrow_mut_and_imm() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1;
let _foo1 = &foo.bar2;
}
fn borrow_mut_from_imm() {
let foo = make_foo();
let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow
}
fn borrow_long_path_both_mut() {
let mut foo = make_foo();
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &mut foo.bar2.int2;
}
fn main() {}

View file

@ -1,26 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
// Here we are checking that a reasonable error msg is provided.
//
// The current message is not ideal, but we used to say "borrowed
// pointer has lifetime &, but the borrowed value only has lifetime &"
// which is definitely no good.
fn get() -> &int {
//~^ NOTE borrowed pointer must be valid for the anonymous lifetime #1 defined on
//~^^ NOTE ...but borrowed value is only valid for the block at
let x = 3;
return &x;
//~^ ERROR illegal borrow
}
fn main() {}

View file

@ -1,30 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
struct Foo {
mut x: uint
}
struct Bar {
foo: Foo
}
fn main() {
let mut b = Bar { foo: Foo { x: 3 } };
let p = &b.foo.x;
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
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));
q.x += 1;
r.foo.x += 1;
io::println(fmt!("*p = %u", *p));
}

View file

@ -8,20 +8,27 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::hashmap::linear::LinearSet;
struct Foo {
x: uint
n: LinearSet<int>,
}
struct Bar {
foo: Foo
impl Foo {
fn foo(&mut self, fun: fn(&int)) {
for self.n.each |f| {
fun(f);
}
}
}
fn bar(f: &mut Foo) {
do f.foo |a| { //~ NOTE prior loan as mutable granted here
f.n.insert(*a); //~ ERROR conflicts with prior loan
}
}
fn main() {
let mut b = Bar { foo: Foo { x: 3 } };
let p = &b; //~ NOTE prior loan as immutable granted here
let q = &mut b.foo.x; //~ ERROR loan of mutable local variable as mutable conflicts with prior loan
let r = &p.foo.x;
io::println(fmt!("*r = %u", *r));
*q += 1;
io::println(fmt!("*r = %u", *r));
let mut f = Foo { n: LinearSet::new() };
bar(&mut f);
}

View file

@ -0,0 +1,106 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.
struct Foo {
bar1: Bar,
bar2: Bar
}
struct Bar {
int1: int,
int2: int,
}
fn borrow_same_field_twice_mut_mut(foo: &mut Foo) {
let _bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_mut_imm(foo: &mut Foo) {
let _bar1 = &mut foo.bar1;
let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_imm_mut(foo: &mut Foo) {
let _bar1 = &foo.bar1;
let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_same_field_twice_imm_imm(foo: &mut Foo) {
let _bar1 = &foo.bar1;
let _bar2 = &foo.bar1;
}
fn borrow_both_mut(foo: &mut Foo) {
let _bar1 = &mut foo.bar1;
let _bar2 = &mut foo.bar2;
}
fn borrow_both_mut_pattern(foo: &mut Foo) {
match *foo {
Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {}
}
}
fn borrow_var_and_pattern(foo: &mut Foo) {
let _bar1 = &mut foo.bar1;
match *foo {
Foo { bar1: ref mut _bar1, bar2: _ } => {}
//~^ ERROR conflicts with prior loan
}
}
fn borrow_mut_and_base_imm(foo: &mut Foo) {
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan
let _foo2 = &*foo; //~ ERROR conflicts with prior loan
}
fn borrow_mut_and_base_mut(foo: &mut Foo) {
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_mut_and_base_mut2(foo: &mut Foo) {
let _bar1 = &mut foo.bar1.int1;
let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_mut(foo: &mut Foo) {
let _bar1 = &foo.bar1.int1;
let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_mut2(foo: &mut Foo) {
let _bar1 = &foo.bar1.int1;
let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan
}
fn borrow_imm_and_base_imm(foo: &mut Foo) {
let _bar1 = &foo.bar1.int1;
let _foo1 = &foo.bar1;
let _foo2 = &*foo;
}
fn borrow_mut_and_imm(foo: &mut Foo) {
let _bar1 = &mut foo.bar1;
let _foo1 = &foo.bar2;
}
fn borrow_mut_from_imm(foo: &Foo) {
let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow
}
fn borrow_long_path_both_mut(foo: &mut Foo) {
let _bar1 = &mut foo.bar1.int1;
let _foo1 = &mut foo.bar2.int2;
}
fn main() {}