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:
commit
27b3e01377
@ -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)) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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); }
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)]
|
||||
|
124
src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs
Normal file
124
src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs
Normal 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() {}
|
124
src/test/compile-fail/borrowck-borrow-from-stack-variable.rs
Normal file
124
src/test/compile-fail/borrowck-borrow-from-stack-variable.rs
Normal 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() {}
|
@ -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() {}
|
@ -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));
|
||||
}
|
@ -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);
|
||||
}
|
106
src/test/compile-fail/borrowck-reborrow-from-mut.rs
Normal file
106
src/test/compile-fail/borrowck-reborrow-from-mut.rs
Normal 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() {}
|
Loading…
x
Reference in New Issue
Block a user