mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-12 20:16:49 +00:00
auto merge of #12158 : nikomatsakis/rust/issue-6801-borrowck-closures, r=pcwalton
I factored the commits by affected files, for the most part. The last 7 or 8 contain the meat of the PR. The rest are small changes to closures found in the codebase. Maybe interesting to read to see some of the impact of the rules. r? @pcwalton Fixes #6801
This commit is contained in:
commit
0ac6e5afda
@ -181,19 +181,25 @@ never call its underlying iterator again once `None` has been returned:
|
||||
~~~
|
||||
let xs = [1,2,3,4,5];
|
||||
let mut calls = 0;
|
||||
let it = xs.iter().scan((), |_, x| {
|
||||
calls += 1;
|
||||
if *x < 3 { Some(x) } else { None }});
|
||||
// the iterator will only yield 1 and 2 before returning None
|
||||
// If we were to call it 5 times, calls would end up as 5, despite only 2 values
|
||||
// being yielded (and therefore 3 unique calls being made). The fuse() adaptor
|
||||
// can fix this.
|
||||
let mut it = it.fuse();
|
||||
it.next();
|
||||
it.next();
|
||||
it.next();
|
||||
it.next();
|
||||
it.next();
|
||||
|
||||
{
|
||||
let it = xs.iter().scan((), |_, x| {
|
||||
calls += 1;
|
||||
if *x < 3 { Some(x) } else { None }});
|
||||
|
||||
// the iterator will only yield 1 and 2 before returning None
|
||||
// If we were to call it 5 times, calls would end up as 5, despite
|
||||
// only 2 values being yielded (and therefore 3 unique calls being
|
||||
// made). The fuse() adaptor can fix this.
|
||||
|
||||
let mut it = it.fuse();
|
||||
it.next();
|
||||
it.next();
|
||||
it.next();
|
||||
it.next();
|
||||
it.next();
|
||||
}
|
||||
|
||||
assert_eq!(calls, 3);
|
||||
~~~
|
||||
|
||||
|
@ -775,14 +775,13 @@ fn each_split_within<'a>(ss: &'a str, lim: uint, it: |&'a str| -> bool)
|
||||
let mut lim = lim;
|
||||
|
||||
let mut cont = true;
|
||||
let slice: || = || { cont = it(ss.slice(slice_start, last_end)) };
|
||||
|
||||
// if the limit is larger than the string, lower it to save cycles
|
||||
if lim >= fake_i {
|
||||
lim = fake_i;
|
||||
}
|
||||
|
||||
let machine: |(uint, char)| -> bool = |(i, c)| {
|
||||
let machine: |&mut bool, (uint, char)| -> bool = |cont, (i, c)| {
|
||||
let whitespace = if ::std::char::is_whitespace(c) { Ws } else { Cr };
|
||||
let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim };
|
||||
|
||||
@ -794,24 +793,49 @@ fn each_split_within<'a>(ss: &'a str, lim: uint, it: |&'a str| -> bool)
|
||||
(B, Cr, OverLim) if (i - last_start + 1) > lim
|
||||
=> fail!("word starting with {} longer than limit!",
|
||||
ss.slice(last_start, i + 1)),
|
||||
(B, Cr, OverLim) => { slice(); slice_start = last_start; B }
|
||||
(B, Ws, UnderLim) => { last_end = i; C }
|
||||
(B, Ws, OverLim) => { last_end = i; slice(); A }
|
||||
(B, Cr, OverLim) => {
|
||||
*cont = it(ss.slice(slice_start, last_end));
|
||||
slice_start = last_start;
|
||||
B
|
||||
}
|
||||
(B, Ws, UnderLim) => {
|
||||
last_end = i;
|
||||
C
|
||||
}
|
||||
(B, Ws, OverLim) => {
|
||||
last_end = i;
|
||||
*cont = it(ss.slice(slice_start, last_end));
|
||||
A
|
||||
}
|
||||
|
||||
(C, Cr, UnderLim) => { last_start = i; B }
|
||||
(C, Cr, OverLim) => { slice(); slice_start = i; last_start = i; last_end = i; B }
|
||||
(C, Ws, OverLim) => { slice(); A }
|
||||
(C, Ws, UnderLim) => { C }
|
||||
(C, Cr, UnderLim) => {
|
||||
last_start = i;
|
||||
B
|
||||
}
|
||||
(C, Cr, OverLim) => {
|
||||
*cont = it(ss.slice(slice_start, last_end));
|
||||
slice_start = i;
|
||||
last_start = i;
|
||||
last_end = i;
|
||||
B
|
||||
}
|
||||
(C, Ws, OverLim) => {
|
||||
*cont = it(ss.slice(slice_start, last_end));
|
||||
A
|
||||
}
|
||||
(C, Ws, UnderLim) => {
|
||||
C
|
||||
}
|
||||
};
|
||||
|
||||
cont
|
||||
*cont
|
||||
};
|
||||
|
||||
ss.char_indices().advance(|x| machine(x));
|
||||
ss.char_indices().advance(|x| machine(&mut cont, x));
|
||||
|
||||
// Let the automaton 'run out' by supplying trailing whitespace
|
||||
while cont && match state { B | C => true, A => false } {
|
||||
machine((fake_i, ' '));
|
||||
machine(&mut cont, (fake_i, ' '));
|
||||
fake_i += 1;
|
||||
}
|
||||
return cont;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#[crate_type = "dylib"];
|
||||
#[license = "MIT/ASL2"];
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::{os, path};
|
||||
use std::io::fs;
|
||||
use std::path::is_sep;
|
||||
@ -342,22 +343,24 @@ impl Pattern {
|
||||
}
|
||||
|
||||
fn matches_from(&self,
|
||||
mut prev_char: Option<char>,
|
||||
prev_char: Option<char>,
|
||||
mut file: &str,
|
||||
i: uint,
|
||||
options: MatchOptions) -> MatchResult {
|
||||
|
||||
let prev_char = Cell::new(prev_char);
|
||||
|
||||
let require_literal = |c| {
|
||||
(options.require_literal_separator && is_sep(c)) ||
|
||||
(options.require_literal_leading_dot && c == '.'
|
||||
&& is_sep(prev_char.unwrap_or('/')))
|
||||
&& is_sep(prev_char.get().unwrap_or('/')))
|
||||
};
|
||||
|
||||
for (ti, token) in self.tokens.slice_from(i).iter().enumerate() {
|
||||
match *token {
|
||||
AnySequence => {
|
||||
loop {
|
||||
match self.matches_from(prev_char, file, i + ti + 1, options) {
|
||||
match self.matches_from(prev_char.get(), file, i + ti + 1, options) {
|
||||
SubPatternDoesntMatch => (), // keep trying
|
||||
m => return m,
|
||||
}
|
||||
@ -370,7 +373,7 @@ impl Pattern {
|
||||
if require_literal(c) {
|
||||
return SubPatternDoesntMatch;
|
||||
}
|
||||
prev_char = Some(c);
|
||||
prev_char.set(Some(c));
|
||||
file = next;
|
||||
}
|
||||
}
|
||||
@ -400,7 +403,7 @@ impl Pattern {
|
||||
if !matches {
|
||||
return SubPatternDoesntMatch;
|
||||
}
|
||||
prev_char = Some(c);
|
||||
prev_char.set(Some(c));
|
||||
file = next;
|
||||
}
|
||||
}
|
||||
|
@ -361,21 +361,23 @@ pub mod write {
|
||||
|
||||
let mut llvm_c_strs = ~[];
|
||||
let mut llvm_args = ~[];
|
||||
let add = |arg: &str| {
|
||||
let s = arg.to_c_str();
|
||||
llvm_args.push(s.with_ref(|p| p));
|
||||
llvm_c_strs.push(s);
|
||||
};
|
||||
add("rustc"); // fake program name
|
||||
add("-arm-enable-ehabi");
|
||||
add("-arm-enable-ehabi-descriptors");
|
||||
if vectorize_loop { add("-vectorize-loops"); }
|
||||
if vectorize_slp { add("-vectorize-slp"); }
|
||||
if sess.time_llvm_passes() { add("-time-passes"); }
|
||||
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
|
||||
{
|
||||
let add = |arg: &str| {
|
||||
let s = arg.to_c_str();
|
||||
llvm_args.push(s.with_ref(|p| p));
|
||||
llvm_c_strs.push(s);
|
||||
};
|
||||
add("rustc"); // fake program name
|
||||
add("-arm-enable-ehabi");
|
||||
add("-arm-enable-ehabi-descriptors");
|
||||
if vectorize_loop { add("-vectorize-loops"); }
|
||||
if vectorize_slp { add("-vectorize-slp"); }
|
||||
if sess.time_llvm_passes() { add("-time-passes"); }
|
||||
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
|
||||
|
||||
for arg in sess.opts.cg.llvm_args.iter() {
|
||||
add(*arg);
|
||||
for arg in sess.opts.cg.llvm_args.iter() {
|
||||
add(*arg);
|
||||
}
|
||||
}
|
||||
|
||||
INIT.doit(|| {
|
||||
@ -631,7 +633,7 @@ pub fn mangle(sess: Session, ss: ast_map::Path,
|
||||
|
||||
let mut n = ~"_ZN"; // _Z == Begin name-sequence, N == nested
|
||||
|
||||
let push = |s: &str| {
|
||||
let push = |n: &mut ~str, s: &str| {
|
||||
let sani = sanitize(s);
|
||||
n.push_str(format!("{}{}", sani.len(), sani));
|
||||
};
|
||||
@ -640,7 +642,7 @@ pub fn mangle(sess: Session, ss: ast_map::Path,
|
||||
for s in ss.iter() {
|
||||
match *s {
|
||||
PathName(s) | PathMod(s) | PathPrettyName(s, _) => {
|
||||
push(sess.str_of(s))
|
||||
push(&mut n, sess.str_of(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -665,10 +667,10 @@ pub fn mangle(sess: Session, ss: ast_map::Path,
|
||||
}
|
||||
}
|
||||
if hash.len() > 0 {
|
||||
push(hash);
|
||||
push(&mut n, hash);
|
||||
}
|
||||
match vers {
|
||||
Some(s) => push(s),
|
||||
Some(s) => push(&mut n, s),
|
||||
None => {}
|
||||
}
|
||||
|
||||
|
@ -58,8 +58,10 @@ fn filter_view_item<'r>(cx: &Context, view_item: &'r ast::ViewItem)
|
||||
}
|
||||
|
||||
fn fold_mod(cx: &mut Context, m: &ast::Mod) -> ast::Mod {
|
||||
let filtered_items = m.items.iter()
|
||||
let filtered_items: ~[&@ast::Item] = m.items.iter()
|
||||
.filter(|&a| item_in_cfg(cx, *a))
|
||||
.collect();
|
||||
let flattened_items = filtered_items.move_iter()
|
||||
.flat_map(|&x| cx.fold_item(x).move_iter())
|
||||
.collect();
|
||||
let filtered_view_items = m.view_items.iter().filter_map(|a| {
|
||||
@ -67,7 +69,7 @@ fn fold_mod(cx: &mut Context, m: &ast::Mod) -> ast::Mod {
|
||||
}).collect();
|
||||
ast::Mod {
|
||||
view_items: filtered_view_items,
|
||||
items: filtered_items
|
||||
items: flattened_items
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,23 +115,26 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
|
||||
ast::ItemStruct(fold_struct(cx, def), generics.clone())
|
||||
}
|
||||
ast::ItemEnum(ref def, ref generics) => {
|
||||
let mut variants = def.variants.iter().map(|c| c.clone()).filter(|m| {
|
||||
(cx.in_cfg)(m.node.attrs)
|
||||
}).map(|v| {
|
||||
match v.node.kind {
|
||||
ast::TupleVariantKind(..) => v,
|
||||
ast::StructVariantKind(def) => {
|
||||
let def = fold_struct(cx, def);
|
||||
@codemap::Spanned {
|
||||
node: ast::Variant_ {
|
||||
kind: ast::StructVariantKind(def),
|
||||
..v.node.clone()
|
||||
},
|
||||
..*v
|
||||
}
|
||||
let mut variants = def.variants.iter().map(|c| c.clone()).
|
||||
filter_map(|v| {
|
||||
if !(cx.in_cfg)(v.node.attrs) {
|
||||
None
|
||||
} else {
|
||||
Some(match v.node.kind {
|
||||
ast::TupleVariantKind(..) => v,
|
||||
ast::StructVariantKind(def) => {
|
||||
let def = fold_struct(cx, def);
|
||||
@codemap::Spanned {
|
||||
node: ast::Variant_ {
|
||||
kind: ast::StructVariantKind(def),
|
||||
..v.node.clone()
|
||||
},
|
||||
..*v
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
ast::ItemEnum(ast::EnumDef {
|
||||
variants: variants.collect(),
|
||||
}, generics.clone())
|
||||
@ -165,10 +170,11 @@ fn retain_stmt(cx: &Context, stmt: @ast::Stmt) -> bool {
|
||||
}
|
||||
|
||||
fn fold_block(cx: &mut Context, b: ast::P<ast::Block>) -> ast::P<ast::Block> {
|
||||
let resulting_stmts = b.stmts.iter()
|
||||
.filter(|&a| retain_stmt(cx, *a))
|
||||
.flat_map(|&stmt| cx.fold_stmt(stmt).move_iter())
|
||||
.collect();
|
||||
let resulting_stmts: ~[&@ast::Stmt] =
|
||||
b.stmts.iter().filter(|&a| retain_stmt(cx, *a)).collect();
|
||||
let resulting_stmts = resulting_stmts.move_iter()
|
||||
.flat_map(|&stmt| cx.fold_stmt(stmt).move_iter())
|
||||
.collect();
|
||||
let filtered_view_items = b.view_items.iter().filter_map(|a| {
|
||||
filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
|
||||
}).collect();
|
||||
|
@ -924,7 +924,6 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
pos: ebml_w.writer.tell().unwrap(),
|
||||
});
|
||||
}
|
||||
let add_to_index: || = || add_to_index(item, ebml_w, index);
|
||||
|
||||
debug!("encoding info for item at {}",
|
||||
ecx.tcx.sess.codemap.span_to_str(item.span));
|
||||
@ -932,7 +931,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
let def_id = local_def(item.id);
|
||||
match item.node {
|
||||
ItemStatic(_, m, _) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
if m == ast::MutMutable {
|
||||
@ -959,7 +958,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemFn(_, purity, _, ref generics, _) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
encode_family(ebml_w, purity_fn_family(purity));
|
||||
@ -977,7 +976,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemMod(ref m) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
encode_info_for_mod(ecx,
|
||||
ebml_w,
|
||||
m,
|
||||
@ -987,7 +986,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
item.vis);
|
||||
}
|
||||
ItemForeignMod(ref fm) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
encode_family(ebml_w, 'n');
|
||||
@ -1004,7 +1003,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemTy(..) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
encode_family(ebml_w, 'y');
|
||||
@ -1015,7 +1014,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
ebml_w.end_tag();
|
||||
}
|
||||
ItemEnum(ref enum_definition, ref generics) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
@ -1053,7 +1052,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
struct_def.fields, index);
|
||||
|
||||
/* Index the class*/
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
|
||||
/* Now, make an item for the class itself */
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
@ -1106,7 +1105,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
let impls = tcx.impls.borrow();
|
||||
let imp = impls.get().get(&def_id);
|
||||
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
encode_family(ebml_w, 'i');
|
||||
@ -1170,7 +1169,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
||||
}
|
||||
}
|
||||
ItemTrait(_, ref super_traits, ref ms) => {
|
||||
add_to_index();
|
||||
add_to_index(item, ebml_w, index);
|
||||
ebml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(ebml_w, def_id);
|
||||
encode_family(ebml_w, 'I');
|
||||
|
@ -96,8 +96,9 @@ pub fn parse_ident(st: &mut PState, last: char) -> ast::Ident {
|
||||
}
|
||||
|
||||
fn parse_ident_(st: &mut PState, is_last: |char| -> bool) -> ast::Ident {
|
||||
let tcx = st.tcx;
|
||||
scan(st, is_last, |bytes| {
|
||||
st.tcx.sess.ident_of(str::from_utf8(bytes).unwrap())
|
||||
tcx.sess.ident_of(str::from_utf8(bytes).unwrap())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,11 @@ impl<'a> Visitor<()> for CheckLoanCtxt<'a> {
|
||||
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
|
||||
check_loans_in_pat(self, p);
|
||||
}
|
||||
fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
|
||||
b: &ast::Block, s: Span, n: ast::NodeId, _: ()) {
|
||||
check_loans_in_fn(self, fk, fd, b, s, n);
|
||||
fn visit_fn(&mut self, _fk: &visit::FnKind, _fd: &ast::FnDecl,
|
||||
_b: &ast::Block, _s: Span, _n: ast::NodeId, _: ()) {
|
||||
// Don't process nested items or closures here,
|
||||
// the outer loop will take care of it.
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME(#10894) should continue recursing
|
||||
@ -218,9 +220,19 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
loan2.repr(self.tcx()));
|
||||
|
||||
// Restrictions that would cause the new loan to be illegal:
|
||||
let illegal_if = match loan2.mutbl {
|
||||
MutableMutability => RESTR_FREEZE | RESTR_CLAIM,
|
||||
ImmutableMutability => RESTR_FREEZE,
|
||||
let illegal_if = match loan2.kind {
|
||||
// Look for restrictions against mutation. These are
|
||||
// generated by all other borrows.
|
||||
ty::MutBorrow => RESTR_MUTATE,
|
||||
|
||||
// Look for restrictions against freezing (immutable borrows).
|
||||
// These are generated by `&mut` borrows.
|
||||
ty::ImmBorrow => RESTR_FREEZE,
|
||||
|
||||
// No matter how the data is borrowed (as `&`, as `&mut`,
|
||||
// or as `&unique imm`) it will always generate a
|
||||
// restriction against mutating the data. So look for those.
|
||||
ty::UniqueImmBorrow => RESTR_MUTATE,
|
||||
};
|
||||
debug!("illegal_if={:?}", illegal_if);
|
||||
|
||||
@ -228,47 +240,107 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
if !restr.set.intersects(illegal_if) { continue; }
|
||||
if restr.loan_path != loan2.loan_path { continue; }
|
||||
|
||||
match (new_loan.mutbl, old_loan.mutbl) {
|
||||
(_, MutableMutability) => {
|
||||
let var = self.bccx.loan_path_to_str(new_loan.loan_path);
|
||||
let old_pronoun = if new_loan.loan_path == old_loan.loan_path {
|
||||
~"it"
|
||||
} else {
|
||||
format!("`{}`",
|
||||
self.bccx.loan_path_to_str(old_loan.loan_path))
|
||||
};
|
||||
|
||||
match (new_loan.kind, old_loan.kind) {
|
||||
(ty::MutBorrow, ty::MutBorrow) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("cannot borrow `{}` because it is already \
|
||||
borrowed as mutable", var));
|
||||
self.bccx.span_note(
|
||||
old_loan.span,
|
||||
format!("previous borrow of `{0}` as mutable occurs \
|
||||
here; the mutable borrow prevents subsequent \
|
||||
moves, borrows, or modification of `{0}` \
|
||||
until the borrow ends", var));
|
||||
format!("cannot borrow `{}` as mutable \
|
||||
more than once at a time",
|
||||
self.bccx.loan_path_to_str(new_loan.loan_path)));
|
||||
}
|
||||
|
||||
(_, mutability) => {
|
||||
(ty::UniqueImmBorrow, _) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("closure requires unique access to `{}` \
|
||||
but {} is already borrowed",
|
||||
self.bccx.loan_path_to_str(new_loan.loan_path),
|
||||
old_pronoun));
|
||||
}
|
||||
|
||||
(_, ty::UniqueImmBorrow) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("cannot borrow `{}` as {} because \
|
||||
it is already borrowed as {}",
|
||||
self.bccx.loan_path_to_str(new_loan.loan_path),
|
||||
self.bccx.mut_to_str(new_loan.mutbl),
|
||||
self.bccx.mut_to_str(old_loan.mutbl)));
|
||||
previous closure requires unique access",
|
||||
self.bccx.loan_path_to_str(new_loan.loan_path),
|
||||
new_loan.kind.to_user_str()));
|
||||
}
|
||||
|
||||
let var = self.bccx.loan_path_to_str(new_loan.loan_path);
|
||||
let mut note = format!("previous borrow of `{}` occurs \
|
||||
here", var);
|
||||
if mutability == ImmutableMutability {
|
||||
note.push_str(format!("; the immutable borrow prevents \
|
||||
subsequent moves or mutable
|
||||
borrows of `{}` until the
|
||||
borrow ends", var));
|
||||
}
|
||||
self.bccx.span_note(old_loan.span, note);
|
||||
(_, _) => {
|
||||
self.bccx.span_err(
|
||||
new_loan.span,
|
||||
format!("cannot borrow `{}` as {} because \
|
||||
{} is also borrowed as {}",
|
||||
self.bccx.loan_path_to_str(new_loan.loan_path),
|
||||
new_loan.kind.to_user_str(),
|
||||
old_pronoun,
|
||||
old_loan.kind.to_user_str()));
|
||||
}
|
||||
}
|
||||
|
||||
match new_loan.cause {
|
||||
ClosureCapture(span) => {
|
||||
self.bccx.span_note(
|
||||
span,
|
||||
format!("borrow occurs due to use of `{}` in closure",
|
||||
self.bccx.loan_path_to_str(new_loan.loan_path)));
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let rule_summary = match old_loan.kind {
|
||||
ty::MutBorrow => {
|
||||
format!("the mutable borrow prevents subsequent \
|
||||
moves, borrows, or modification of `{0}` \
|
||||
until the borrow ends",
|
||||
self.bccx.loan_path_to_str(old_loan.loan_path))
|
||||
}
|
||||
|
||||
ty::ImmBorrow => {
|
||||
format!("the immutable borrow prevents subsequent \
|
||||
moves or mutable borrows of `{0}` \
|
||||
until the borrow ends",
|
||||
self.bccx.loan_path_to_str(old_loan.loan_path))
|
||||
}
|
||||
|
||||
ty::UniqueImmBorrow => {
|
||||
format!("the unique capture prevents subsequent \
|
||||
moves or borrows of `{0}` \
|
||||
until the borrow ends",
|
||||
self.bccx.loan_path_to_str(old_loan.loan_path))
|
||||
}
|
||||
};
|
||||
|
||||
let borrow_summary = match old_loan.cause {
|
||||
ClosureCapture(_) => {
|
||||
format!("previous borrow of `{}` occurs here due to \
|
||||
use in closure",
|
||||
self.bccx.loan_path_to_str(old_loan.loan_path))
|
||||
}
|
||||
|
||||
AddrOf | AutoRef | RefBinding => {
|
||||
format!("previous borrow of `{}` occurs here",
|
||||
self.bccx.loan_path_to_str(old_loan.loan_path))
|
||||
}
|
||||
};
|
||||
|
||||
self.bccx.span_note(
|
||||
old_loan.span,
|
||||
format!("{}; {}", borrow_summary, rule_summary));
|
||||
|
||||
let old_loan_span = ast_map::node_span(self.tcx().items,
|
||||
old_loan.kill_scope);
|
||||
self.bccx.span_end_note(old_loan_span,
|
||||
"previous borrow ends here");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -349,11 +421,23 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
}
|
||||
|
||||
// Otherwise, just a plain error.
|
||||
self.bccx.span_err(
|
||||
expr.span,
|
||||
format!("cannot assign to {} {}",
|
||||
cmt.mutbl.to_user_str(),
|
||||
self.bccx.cmt_to_str(cmt)));
|
||||
match opt_loan_path(cmt) {
|
||||
Some(lp) => {
|
||||
self.bccx.span_err(
|
||||
expr.span,
|
||||
format!("cannot assign to {} {} `{}`",
|
||||
cmt.mutbl.to_user_str(),
|
||||
self.bccx.cmt_to_str(cmt),
|
||||
self.bccx.loan_path_to_str(lp)));
|
||||
}
|
||||
None => {
|
||||
self.bccx.span_err(
|
||||
expr.span,
|
||||
format!("cannot assign to {} {}",
|
||||
cmt.mutbl.to_user_str(),
|
||||
self.bccx.cmt_to_str(cmt)));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
fn mark_variable_as_used_mut(this: &CheckLoanCtxt,
|
||||
@ -377,11 +461,11 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
return;
|
||||
}
|
||||
|
||||
mc::cat_stack_upvar(b) => {
|
||||
cmt = b;
|
||||
mc::cat_upvar(..) => {
|
||||
return;
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::gc_ptr) => {
|
||||
mc::cat_deref(_, _, mc::GcPtr) => {
|
||||
assert_eq!(cmt.mutbl, mc::McImmutable);
|
||||
return;
|
||||
}
|
||||
@ -389,25 +473,22 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
mc::cat_rvalue(..) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_copied_upvar(..) |
|
||||
mc::cat_deref(_, _, mc::unsafe_ptr(..)) |
|
||||
mc::cat_deref(_, _, mc::region_ptr(..)) => {
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_deref(_, _, mc::BorrowedPtr(..)) => {
|
||||
assert_eq!(cmt.mutbl, mc::McDeclared);
|
||||
return;
|
||||
}
|
||||
|
||||
mc::cat_discr(b, _) |
|
||||
mc::cat_deref(b, _, mc::uniq_ptr) => {
|
||||
mc::cat_deref(b, _, mc::OwnedPtr) => {
|
||||
assert_eq!(cmt.mutbl, mc::McInherited);
|
||||
cmt = b;
|
||||
}
|
||||
|
||||
mc::cat_downcast(b) |
|
||||
mc::cat_interior(b, _) => {
|
||||
if cmt.mutbl == mc::McInherited {
|
||||
cmt = b;
|
||||
} else {
|
||||
return; // field declared as mutable or some such
|
||||
}
|
||||
assert_eq!(cmt.mutbl, mc::McInherited);
|
||||
cmt = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -422,7 +503,7 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
debug!("check_for_aliasable_mutable_writes(cmt={}, guarantor={})",
|
||||
cmt.repr(this.tcx()), guarantor.repr(this.tcx()));
|
||||
match guarantor.cat {
|
||||
mc::cat_deref(b, _, mc::region_ptr(ast::MutMutable, _)) => {
|
||||
mc::cat_deref(b, _, mc::BorrowedPtr(ty::MutBorrow, _)) => {
|
||||
// Statically prohibit writes to `&mut` when aliasable
|
||||
|
||||
check_for_aliasability_violation(this, expr, b);
|
||||
@ -557,7 +638,7 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
// with inherited mutability and with `&mut`
|
||||
// pointers.
|
||||
LpExtend(lp_base, mc::McInherited, _) |
|
||||
LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::MutMutable, _))) => {
|
||||
LpExtend(lp_base, _, LpDeref(mc::BorrowedPtr(ty::MutBorrow, _))) => {
|
||||
loan_path = lp_base;
|
||||
}
|
||||
|
||||
@ -572,9 +653,7 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
// Check for a non-const loan of `loan_path`
|
||||
let cont = this.each_in_scope_loan(expr.id, |loan| {
|
||||
if loan.loan_path == loan_path {
|
||||
this.report_illegal_mutation(expr,
|
||||
full_loan_path,
|
||||
loan);
|
||||
this.report_illegal_mutation(expr, full_loan_path, loan);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
@ -603,9 +682,10 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
fn check_move_out_from_expr(&self, expr: &ast::Expr) {
|
||||
match expr.node {
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
||||
// moves due to capture clauses are checked
|
||||
// in `check_loans_in_fn`, so that we can
|
||||
// give a better error message
|
||||
// Moves due to captures are checked in
|
||||
// check_captured_variables() because it allows
|
||||
// us to give a more precise error message with
|
||||
// a more precise span.
|
||||
}
|
||||
_ => {
|
||||
self.check_move_out_from_id(expr.id, expr.span)
|
||||
@ -621,18 +701,59 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
self.bccx.span_err(
|
||||
span,
|
||||
format!("cannot move out of `{}` \
|
||||
because it is borrowed",
|
||||
because it is borrowed",
|
||||
self.bccx.loan_path_to_str(move_path)));
|
||||
self.bccx.span_note(
|
||||
loan_span,
|
||||
format!("borrow of `{}` occurs here",
|
||||
self.bccx.loan_path_to_str(loan_path)));
|
||||
self.bccx.loan_path_to_str(loan_path)));
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
fn check_captured_variables(&self,
|
||||
closure_id: ast::NodeId,
|
||||
span: Span) {
|
||||
let capture_map = self.bccx.capture_map.borrow();
|
||||
let cap_vars = capture_map.get().get(&closure_id);
|
||||
for cap_var in cap_vars.borrow().iter() {
|
||||
let var_id = ast_util::def_id_of_def(cap_var.def).node;
|
||||
let var_path = @LpVar(var_id);
|
||||
self.check_if_path_is_moved(closure_id, span,
|
||||
MovedInCapture, var_path);
|
||||
match cap_var.mode {
|
||||
moves::CapRef | moves::CapCopy => {}
|
||||
moves::CapMove => {
|
||||
check_by_move_capture(self, closure_id, cap_var, var_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
fn check_by_move_capture(this: &CheckLoanCtxt,
|
||||
closure_id: ast::NodeId,
|
||||
cap_var: &moves::CaptureVar,
|
||||
move_path: @LoanPath) {
|
||||
let move_err = this.analyze_move_out_from(closure_id, move_path);
|
||||
match move_err {
|
||||
MoveOk => {}
|
||||
MoveWhileBorrowed(loan_path, loan_span) => {
|
||||
this.bccx.span_err(
|
||||
cap_var.span,
|
||||
format!("cannot move `{}` into closure \
|
||||
because it is borrowed",
|
||||
this.bccx.loan_path_to_str(move_path)));
|
||||
this.bccx.span_note(
|
||||
loan_span,
|
||||
format!("borrow of `{}` occurs here",
|
||||
this.bccx.loan_path_to_str(loan_path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn analyze_move_out_from(&self,
|
||||
expr_id: ast::NodeId,
|
||||
mut move_path: @LoanPath)
|
||||
@ -681,67 +802,6 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_loans_in_fn<'a>(this: &mut CheckLoanCtxt<'a>,
|
||||
fk: &visit::FnKind,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
sp: Span,
|
||||
id: ast::NodeId) {
|
||||
match *fk {
|
||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
||||
// Don't process nested items.
|
||||
return;
|
||||
}
|
||||
|
||||
visit::FkFnBlock(..) => {
|
||||
check_captured_variables(this, id, sp);
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_fn(this, fk, decl, body, sp, id, ());
|
||||
|
||||
fn check_captured_variables(this: &CheckLoanCtxt,
|
||||
closure_id: ast::NodeId,
|
||||
span: Span) {
|
||||
let capture_map = this.bccx.capture_map.borrow();
|
||||
let cap_vars = capture_map.get().get(&closure_id);
|
||||
for cap_var in cap_vars.borrow().iter() {
|
||||
let var_id = ast_util::def_id_of_def(cap_var.def).node;
|
||||
let var_path = @LpVar(var_id);
|
||||
this.check_if_path_is_moved(closure_id, span,
|
||||
MovedInCapture, var_path);
|
||||
match cap_var.mode {
|
||||
moves::CapRef | moves::CapCopy => {}
|
||||
moves::CapMove => {
|
||||
check_by_move_capture(this, closure_id, cap_var, var_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
fn check_by_move_capture(this: &CheckLoanCtxt,
|
||||
closure_id: ast::NodeId,
|
||||
cap_var: &moves::CaptureVar,
|
||||
move_path: @LoanPath) {
|
||||
let move_err = this.analyze_move_out_from(closure_id, move_path);
|
||||
match move_err {
|
||||
MoveOk => {}
|
||||
MoveWhileBorrowed(loan_path, loan_span) => {
|
||||
this.bccx.span_err(
|
||||
cap_var.span,
|
||||
format!("cannot move `{}` into closure \
|
||||
because it is borrowed",
|
||||
this.bccx.loan_path_to_str(move_path)));
|
||||
this.bccx.span_note(
|
||||
loan_span,
|
||||
format!("borrow of `{}` occurs here",
|
||||
this.bccx.loan_path_to_str(loan_path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_loans_in_local<'a>(this: &mut CheckLoanCtxt<'a>,
|
||||
local: &ast::Local) {
|
||||
visit::walk_local(this, local, ());
|
||||
@ -769,6 +829,9 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>,
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
||||
this.check_captured_variables(expr.id, expr.span)
|
||||
}
|
||||
ast::ExprAssign(dest, _) |
|
||||
ast::ExprAssignOp(_, _, dest, _) => {
|
||||
this.check_assignment(dest);
|
||||
|
@ -18,9 +18,8 @@ use middle::borrowck::move_data::*;
|
||||
use middle::moves;
|
||||
use middle::ty;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::{UserString};
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
pub fn gather_decl(bccx: &BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
@ -35,33 +34,14 @@ pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
move_expr: &ast::Expr,
|
||||
cmt: mc::cmt) {
|
||||
gather_move_from_expr_or_pat(bccx, move_data, move_expr.id, MoveExpr, cmt);
|
||||
gather_move(bccx, move_data, move_expr.id, MoveExpr, cmt);
|
||||
}
|
||||
|
||||
pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
move_pat: &ast::Pat,
|
||||
cmt: mc::cmt) {
|
||||
gather_move_from_expr_or_pat(bccx, move_data, move_pat.id, MovePat, cmt);
|
||||
}
|
||||
|
||||
fn gather_move_from_expr_or_pat(bccx: &BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
move_id: ast::NodeId,
|
||||
move_kind: MoveKind,
|
||||
cmt: mc::cmt) {
|
||||
if !check_is_legal_to_move_from(bccx, cmt, cmt) {
|
||||
return;
|
||||
}
|
||||
|
||||
match opt_loan_path(cmt) {
|
||||
Some(loan_path) => {
|
||||
move_data.add_move(bccx.tcx, loan_path, move_id, move_kind);
|
||||
}
|
||||
None => {
|
||||
// move from rvalue or unsafe pointer, hence ok
|
||||
}
|
||||
}
|
||||
gather_move(bccx, move_data, move_pat.id, MovePat, cmt);
|
||||
}
|
||||
|
||||
pub fn gather_captures(bccx: &BorrowckCtxt,
|
||||
@ -72,16 +52,38 @@ pub fn gather_captures(bccx: &BorrowckCtxt,
|
||||
for captured_var in captured_vars.borrow().iter() {
|
||||
match captured_var.mode {
|
||||
moves::CapMove => {
|
||||
let fvar_id = ast_util::def_id_of_def(captured_var.def).node;
|
||||
let loan_path = @LpVar(fvar_id);
|
||||
move_data.add_move(bccx.tcx, loan_path, closure_expr.id,
|
||||
Captured);
|
||||
let cmt = bccx.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
captured_var);
|
||||
gather_move(bccx, move_data, closure_expr.id, Captured, cmt);
|
||||
}
|
||||
moves::CapCopy | moves::CapRef => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_move(bccx: &BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
move_id: ast::NodeId,
|
||||
move_kind: MoveKind,
|
||||
cmt: mc::cmt) {
|
||||
debug!("gather_move(move_id={}, cmt={})",
|
||||
move_id, cmt.repr(bccx.tcx));
|
||||
|
||||
if !check_is_legal_to_move_from(bccx, cmt, cmt) {
|
||||
return;
|
||||
}
|
||||
|
||||
match opt_loan_path(cmt) {
|
||||
Some(loan_path) => {
|
||||
move_data.add_move(bccx.tcx, loan_path, move_id, move_kind);
|
||||
}
|
||||
None => {
|
||||
// move from rvalue or unsafe pointer, hence ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gather_assignment(bccx: &BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
assignment_id: ast::NodeId,
|
||||
@ -99,15 +101,15 @@ fn check_is_legal_to_move_from(bccx: &BorrowckCtxt,
|
||||
cmt0: mc::cmt,
|
||||
cmt: mc::cmt) -> bool {
|
||||
match cmt.cat {
|
||||
mc::cat_deref(_, _, mc::region_ptr(..)) |
|
||||
mc::cat_deref(_, _, mc::gc_ptr) |
|
||||
mc::cat_deref(_, _, mc::unsafe_ptr(..)) |
|
||||
mc::cat_stack_upvar(..) |
|
||||
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(_, _, mc::GcPtr) |
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_upvar(..) |
|
||||
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
|
||||
bccx.span_err(
|
||||
cmt0.span,
|
||||
format!("cannot move out of {}",
|
||||
bccx.cmt_to_str(cmt)));
|
||||
bccx.cmt_to_str(cmt)));
|
||||
false
|
||||
}
|
||||
|
||||
@ -158,7 +160,7 @@ fn check_is_legal_to_move_from(bccx: &BorrowckCtxt,
|
||||
}
|
||||
}
|
||||
|
||||
mc::cat_deref(b, _, mc::uniq_ptr) |
|
||||
mc::cat_deref(b, _, mc::OwnedPtr) |
|
||||
mc::cat_discr(b, _) => {
|
||||
check_is_legal_to_move_from(bccx, cmt0, b)
|
||||
}
|
||||
|
@ -26,16 +26,19 @@ pub fn guarantee_lifetime(bccx: &BorrowckCtxt,
|
||||
item_scope_id: ast::NodeId,
|
||||
root_scope_id: ast::NodeId,
|
||||
span: Span,
|
||||
cause: LoanCause,
|
||||
cmt: mc::cmt,
|
||||
loan_region: ty::Region,
|
||||
loan_mutbl: LoanMutability) -> R {
|
||||
loan_kind: ty::BorrowKind)
|
||||
-> Result<(),()> {
|
||||
debug!("guarantee_lifetime(cmt={}, loan_region={})",
|
||||
cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
|
||||
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
|
||||
item_scope_id: item_scope_id,
|
||||
span: span,
|
||||
cause: cause,
|
||||
loan_region: loan_region,
|
||||
loan_mutbl: loan_mutbl,
|
||||
loan_kind: loan_kind,
|
||||
cmt_original: cmt,
|
||||
root_scope_id: root_scope_id};
|
||||
ctxt.check(cmt, None)
|
||||
@ -55,8 +58,9 @@ struct GuaranteeLifetimeContext<'a> {
|
||||
root_scope_id: ast::NodeId,
|
||||
|
||||
span: Span,
|
||||
cause: LoanCause,
|
||||
loan_region: ty::Region,
|
||||
loan_mutbl: LoanMutability,
|
||||
loan_kind: ty::BorrowKind,
|
||||
cmt_original: mc::cmt
|
||||
}
|
||||
|
||||
@ -76,21 +80,18 @@ impl<'a> GuaranteeLifetimeContext<'a> {
|
||||
mc::cat_copied_upvar(..) | // L-Local
|
||||
mc::cat_local(..) | // L-Local
|
||||
mc::cat_arg(..) | // L-Local
|
||||
mc::cat_deref(_, _, mc::region_ptr(..)) | // L-Deref-Borrowed
|
||||
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
|
||||
mc::cat_upvar(..) |
|
||||
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
|
||||
let scope = self.scope(cmt);
|
||||
self.check_scope(scope)
|
||||
}
|
||||
|
||||
mc::cat_stack_upvar(cmt) => {
|
||||
self.check(cmt, discr_scope)
|
||||
}
|
||||
|
||||
mc::cat_static_item => {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mc::cat_deref(base, derefs, mc::gc_ptr) => {
|
||||
mc::cat_deref(base, derefs, mc::GcPtr) => {
|
||||
let base_scope = self.scope(base);
|
||||
|
||||
// L-Deref-Managed-Imm-User-Root
|
||||
@ -112,7 +113,7 @@ impl<'a> GuaranteeLifetimeContext<'a> {
|
||||
}
|
||||
|
||||
mc::cat_downcast(base) |
|
||||
mc::cat_deref(base, _, mc::uniq_ptr) | // L-Deref-Send
|
||||
mc::cat_deref(base, _, mc::OwnedPtr) | // L-Deref-Send
|
||||
mc::cat_interior(base, _) => { // L-Field
|
||||
self.check(base, discr_scope)
|
||||
}
|
||||
@ -269,12 +270,12 @@ impl<'a> GuaranteeLifetimeContext<'a> {
|
||||
mc::cat_rvalue(..) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_copied_upvar(..) |
|
||||
mc::cat_deref(..) => {
|
||||
mc::cat_deref(..) |
|
||||
mc::cat_upvar(..) => {
|
||||
false
|
||||
}
|
||||
r @ mc::cat_downcast(..) |
|
||||
r @ mc::cat_interior(..) |
|
||||
r @ mc::cat_stack_upvar(..) |
|
||||
r @ mc::cat_discr(..) => {
|
||||
self.tcx().sess.span_bug(
|
||||
cmt.span,
|
||||
@ -294,6 +295,7 @@ impl<'a> GuaranteeLifetimeContext<'a> {
|
||||
mc::cat_rvalue(temp_scope) => {
|
||||
temp_scope
|
||||
}
|
||||
mc::cat_upvar(..) |
|
||||
mc::cat_copied_upvar(_) => {
|
||||
ty::ReScope(self.item_scope_id)
|
||||
}
|
||||
@ -304,17 +306,16 @@ impl<'a> GuaranteeLifetimeContext<'a> {
|
||||
mc::cat_arg(local_id) => {
|
||||
ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
|
||||
}
|
||||
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
|
||||
ty::ReStatic
|
||||
}
|
||||
mc::cat_deref(_, _, mc::region_ptr(_, r)) => {
|
||||
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) => {
|
||||
r
|
||||
}
|
||||
mc::cat_downcast(cmt) |
|
||||
mc::cat_deref(cmt, _, mc::uniq_ptr) |
|
||||
mc::cat_deref(cmt, _, mc::gc_ptr) |
|
||||
mc::cat_deref(cmt, _, mc::OwnedPtr) |
|
||||
mc::cat_deref(cmt, _, mc::GcPtr) |
|
||||
mc::cat_interior(cmt, _) |
|
||||
mc::cat_stack_upvar(cmt) |
|
||||
mc::cat_discr(cmt, _) => {
|
||||
self.scope(cmt)
|
||||
}
|
||||
@ -322,10 +323,9 @@ impl<'a> GuaranteeLifetimeContext<'a> {
|
||||
}
|
||||
|
||||
fn report_error(&self, code: bckerr_code) {
|
||||
self.bccx.report(BckError {
|
||||
cmt: self.cmt_original,
|
||||
span: self.span,
|
||||
code: code
|
||||
});
|
||||
self.bccx.report(BckError { cmt: self.cmt_original,
|
||||
span: self.span,
|
||||
cause: self.cause,
|
||||
code: code });
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,10 @@
|
||||
// their associated scopes. In phase two, checking loans, we will then make
|
||||
// sure that all of these loans are honored.
|
||||
|
||||
|
||||
use middle::borrowck::*;
|
||||
use middle::borrowck::move_data::MoveData;
|
||||
use mc = middle::mem_categorization;
|
||||
use middle::moves;
|
||||
use middle::pat_util;
|
||||
use middle::ty::{ty_region};
|
||||
use middle::ty;
|
||||
@ -28,6 +28,7 @@ use util::ppaux::{Repr};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::ast_util::IdRange;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::print::pprust;
|
||||
@ -127,22 +128,15 @@ fn add_pat_to_id_range(this: &mut GatherLoanCtxt,
|
||||
visit::walk_pat(this, p, ());
|
||||
}
|
||||
|
||||
fn gather_loans_in_fn(this: &mut GatherLoanCtxt, fk: &FnKind,
|
||||
decl: &ast::FnDecl, body: &ast::Block,
|
||||
sp: Span, id: ast::NodeId) {
|
||||
match fk {
|
||||
&visit::FkItemFn(..) | &visit::FkMethod(..) => {
|
||||
fail!("cannot occur, due to visit_item override");
|
||||
}
|
||||
|
||||
// Visit closures as part of the containing item.
|
||||
&visit::FkFnBlock(..) => {
|
||||
this.push_repeating_id(body.id);
|
||||
visit::walk_fn(this, fk, decl, body, sp, id, ());
|
||||
this.pop_repeating_id(body.id);
|
||||
this.gather_fn_arg_patterns(decl, body);
|
||||
}
|
||||
}
|
||||
fn gather_loans_in_fn(_v: &mut GatherLoanCtxt,
|
||||
_fk: &FnKind,
|
||||
_decl: &ast::FnDecl,
|
||||
_body: &ast::Block,
|
||||
_sp: Span,
|
||||
_id: ast::NodeId) {
|
||||
// Do not visit closures or fn items here, the outer loop in
|
||||
// borrowck/mod will visit them for us in turn.
|
||||
return;
|
||||
}
|
||||
|
||||
fn gather_loans_in_block(this: &mut GatherLoanCtxt,
|
||||
@ -232,8 +226,9 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
|
||||
this.guarantee_valid(ex.id,
|
||||
ex.span,
|
||||
base_cmt,
|
||||
LoanMutability::from_ast_mutability(mutbl),
|
||||
scope_r);
|
||||
mutbl,
|
||||
scope_r,
|
||||
AddrOf);
|
||||
}
|
||||
visit::walk_expr(this, ex, ());
|
||||
}
|
||||
@ -278,8 +273,9 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
|
||||
this.guarantee_valid(arg.id,
|
||||
arg.span,
|
||||
arg_cmt,
|
||||
ImmutableMutability,
|
||||
scope_r);
|
||||
ast::MutImmutable,
|
||||
scope_r,
|
||||
AutoRef);
|
||||
visit::walk_expr(this, ex, ());
|
||||
}
|
||||
|
||||
@ -305,6 +301,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
|
||||
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
||||
gather_moves::gather_captures(this.bccx, &this.move_data, ex);
|
||||
this.guarantee_captures(ex);
|
||||
visit::walk_expr(this, ex, ());
|
||||
}
|
||||
|
||||
@ -367,49 +364,48 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
ty::AutoDerefRef {
|
||||
autoref: Some(ref autoref),
|
||||
autoderefs: autoderefs}) => {
|
||||
let mcx = &mc::mem_categorization_ctxt {
|
||||
tcx: self.tcx(),
|
||||
method_map: self.bccx.method_map};
|
||||
let cmt = mcx.cat_expr_autoderefd(expr, autoderefs);
|
||||
let mut mc = self.bccx.mc();
|
||||
let cmt = match mc.cat_expr_autoderefd(expr, autoderefs) {
|
||||
Ok(v) => v,
|
||||
Err(()) => self.tcx().sess.span_bug(expr.span, "Err from mc")
|
||||
};
|
||||
debug!("after autoderef, cmt={}", cmt.repr(self.tcx()));
|
||||
|
||||
match *autoref {
|
||||
ty::AutoPtr(r, m) => {
|
||||
let loan_mutability =
|
||||
LoanMutability::from_ast_mutability(m);
|
||||
self.guarantee_valid(expr.id,
|
||||
expr.span,
|
||||
cmt,
|
||||
loan_mutability,
|
||||
r)
|
||||
m,
|
||||
r,
|
||||
AutoRef)
|
||||
}
|
||||
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
|
||||
let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1);
|
||||
let loan_mutability =
|
||||
LoanMutability::from_ast_mutability(m);
|
||||
let cmt_index = mc.cat_index(expr, cmt, autoderefs+1);
|
||||
self.guarantee_valid(expr.id,
|
||||
expr.span,
|
||||
cmt_index,
|
||||
loan_mutability,
|
||||
r)
|
||||
m,
|
||||
r,
|
||||
AutoRef)
|
||||
}
|
||||
ty::AutoBorrowFn(r) => {
|
||||
let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
|
||||
let cmt_deref = mc.cat_deref_fn_or_obj(expr, cmt, 0);
|
||||
self.guarantee_valid(expr.id,
|
||||
expr.span,
|
||||
cmt_deref,
|
||||
ImmutableMutability,
|
||||
r)
|
||||
ast::MutImmutable,
|
||||
r,
|
||||
AutoRef)
|
||||
}
|
||||
ty::AutoBorrowObj(r, m) => {
|
||||
let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
|
||||
let loan_mutability =
|
||||
LoanMutability::from_ast_mutability(m);
|
||||
let cmt_deref = mc.cat_deref_fn_or_obj(expr, cmt, 0);
|
||||
self.guarantee_valid(expr.id,
|
||||
expr.span,
|
||||
cmt_deref,
|
||||
loan_mutability,
|
||||
r)
|
||||
m,
|
||||
r,
|
||||
AutoRef)
|
||||
}
|
||||
ty::AutoUnsafe(_) => {}
|
||||
}
|
||||
@ -421,22 +417,71 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Guarantees that addr_of(cmt) will be valid for the duration of
|
||||
// `static_scope_r`, or reports an error. This may entail taking
|
||||
// out loans, which will be added to the `req_loan_map`. This can
|
||||
// also entail "rooting" GC'd pointers, which means ensuring
|
||||
// dynamically that they are not freed.
|
||||
fn guarantee_captures(&mut self,
|
||||
closure_expr: &ast::Expr) {
|
||||
let capture_map = self.bccx.capture_map.borrow();
|
||||
let captured_vars = capture_map.get().get(&closure_expr.id);
|
||||
for captured_var in captured_vars.borrow().iter() {
|
||||
match captured_var.mode {
|
||||
moves::CapCopy | moves::CapMove => { continue; }
|
||||
moves::CapRef => { }
|
||||
}
|
||||
|
||||
let var_id = ast_util::def_id_of_def(captured_var.def).node;
|
||||
let var_cmt = self.bccx.cat_captured_var(closure_expr.id,
|
||||
closure_expr.span,
|
||||
captured_var);
|
||||
|
||||
// Lookup the kind of borrow the callee requires
|
||||
let upvar_id = ty::UpvarId { var_id: var_id,
|
||||
closure_expr_id: closure_expr.id };
|
||||
let upvar_borrow_map = self.tcx().upvar_borrow_map.borrow();
|
||||
let upvar_borrow = upvar_borrow_map.get().get_copy(&upvar_id);
|
||||
|
||||
self.guarantee_valid_kind(closure_expr.id,
|
||||
closure_expr.span,
|
||||
var_cmt,
|
||||
upvar_borrow.kind,
|
||||
upvar_borrow.region,
|
||||
ClosureCapture(captured_var.span));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn guarantee_valid(&mut self,
|
||||
borrow_id: ast::NodeId,
|
||||
borrow_span: Span,
|
||||
cmt: mc::cmt,
|
||||
req_mutbl: LoanMutability,
|
||||
loan_region: ty::Region) {
|
||||
req_mutbl: ast::Mutability,
|
||||
loan_region: ty::Region,
|
||||
cause: LoanCause) {
|
||||
self.guarantee_valid_kind(borrow_id,
|
||||
borrow_span,
|
||||
cmt,
|
||||
ty::BorrowKind::from_mutbl(req_mutbl),
|
||||
loan_region,
|
||||
cause);
|
||||
}
|
||||
|
||||
fn guarantee_valid_kind(&mut self,
|
||||
borrow_id: ast::NodeId,
|
||||
borrow_span: Span,
|
||||
cmt: mc::cmt,
|
||||
req_kind: ty::BorrowKind,
|
||||
loan_region: ty::Region,
|
||||
cause: LoanCause) {
|
||||
/*!
|
||||
* Guarantees that `addr_of(cmt)` will be valid for the duration of
|
||||
* `static_scope_r`, or reports an error. This may entail taking
|
||||
* out loans, which will be added to the `req_loan_map`. This can
|
||||
* also entail "rooting" GC'd pointers, which means ensuring
|
||||
* dynamically that they are not freed.
|
||||
*/
|
||||
|
||||
debug!("guarantee_valid(borrow_id={:?}, cmt={}, \
|
||||
req_mutbl={:?}, loan_region={:?})",
|
||||
borrow_id,
|
||||
cmt.repr(self.tcx()),
|
||||
req_mutbl,
|
||||
req_kind,
|
||||
loan_region);
|
||||
|
||||
// a loan for the empty region can never be dereferenced, so
|
||||
@ -450,26 +495,28 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
// Check that the lifetime of the borrow does not exceed
|
||||
// the lifetime of the data being borrowed.
|
||||
if lifetime::guarantee_lifetime(self.bccx, self.item_ub, root_ub,
|
||||
borrow_span, cmt, loan_region,
|
||||
req_mutbl).is_err() {
|
||||
borrow_span, cause, cmt, loan_region,
|
||||
req_kind).is_err() {
|
||||
return; // reported an error, no sense in reporting more.
|
||||
}
|
||||
|
||||
// Check that we don't allow mutable borrows of non-mutable data.
|
||||
if check_mutability(self.bccx, borrow_span, cmt, req_mutbl).is_err() {
|
||||
if check_mutability(self.bccx, borrow_span, cause,
|
||||
cmt, req_kind).is_err() {
|
||||
return; // reported an error, no sense in reporting more.
|
||||
}
|
||||
|
||||
// Check that we don't allow mutable borrows of aliasable data.
|
||||
if check_aliasability(self.bccx, borrow_span, cmt, req_mutbl).is_err() {
|
||||
if check_aliasability(self.bccx, borrow_span, cause,
|
||||
cmt, req_kind).is_err() {
|
||||
return; // reported an error, no sense in reporting more.
|
||||
}
|
||||
|
||||
// Compute the restrictions that are required to enforce the
|
||||
// loan is safe.
|
||||
let restr = restrictions::compute_restrictions(
|
||||
self.bccx, borrow_span,
|
||||
cmt, loan_region, self.restriction_set(req_mutbl));
|
||||
self.bccx, borrow_span, cause,
|
||||
cmt, loan_region, self.restriction_set(req_kind));
|
||||
|
||||
// Create the loan record (if needed).
|
||||
let loan = match restr {
|
||||
@ -512,7 +559,7 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
let kill_scope = self.compute_kill_scope(loan_scope, loan_path);
|
||||
debug!("kill_scope = {:?}", kill_scope);
|
||||
|
||||
if req_mutbl == MutableMutability {
|
||||
if req_kind == ty::MutBorrow {
|
||||
self.mark_loan_path_as_mutated(loan_path);
|
||||
}
|
||||
|
||||
@ -521,11 +568,12 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
index: all_loans.get().len(),
|
||||
loan_path: loan_path,
|
||||
cmt: cmt,
|
||||
mutbl: req_mutbl,
|
||||
kind: req_kind,
|
||||
gen_scope: gen_scope,
|
||||
kill_scope: kill_scope,
|
||||
span: borrow_span,
|
||||
restrictions: restrictions
|
||||
restrictions: restrictions,
|
||||
cause: cause,
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -568,23 +616,33 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
|
||||
fn check_mutability(bccx: &BorrowckCtxt,
|
||||
borrow_span: Span,
|
||||
cause: LoanCause,
|
||||
cmt: mc::cmt,
|
||||
req_mutbl: LoanMutability) -> Result<(),()> {
|
||||
req_kind: ty::BorrowKind)
|
||||
-> Result<(),()> {
|
||||
//! Implements the M-* rules in doc.rs.
|
||||
|
||||
match req_mutbl {
|
||||
ImmutableMutability => {
|
||||
// both imm and mut data can be lent as imm;
|
||||
// for mutable data, this is a freeze
|
||||
Ok(())
|
||||
match req_kind {
|
||||
ty::UniqueImmBorrow | ty::ImmBorrow => {
|
||||
match cmt.mutbl {
|
||||
// I am intentionally leaving this here to help
|
||||
// refactoring if, in the future, we should add new
|
||||
// kinds of mutability.
|
||||
mc::McImmutable | mc::McDeclared | mc::McInherited => {
|
||||
// both imm and mut data can be lent as imm;
|
||||
// for mutable data, this is a freeze
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MutableMutability => {
|
||||
ty::MutBorrow => {
|
||||
// Only mutable data can be lent as mutable.
|
||||
if !cmt.mutbl.is_mutable() {
|
||||
Err(bccx.report(BckError {span: borrow_span,
|
||||
cmt: cmt,
|
||||
code: err_mutbl(req_mutbl)}))
|
||||
Err(bccx.report(BckError { span: borrow_span,
|
||||
cause: cause,
|
||||
cmt: cmt,
|
||||
code: err_mutbl }))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -594,18 +652,18 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
|
||||
fn check_aliasability(bccx: &BorrowckCtxt,
|
||||
borrow_span: Span,
|
||||
loan_cause: LoanCause,
|
||||
cmt: mc::cmt,
|
||||
req_mutbl: LoanMutability) -> Result<(),()> {
|
||||
req_kind: ty::BorrowKind)
|
||||
-> Result<(),()> {
|
||||
//! Implements the A-* rules in doc.rs.
|
||||
|
||||
match req_mutbl {
|
||||
ImmutableMutability => {
|
||||
// both imm and mut data can be lent as imm;
|
||||
// for mutable data, this is a freeze
|
||||
match req_kind {
|
||||
ty::ImmBorrow => {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
MutableMutability => {
|
||||
ty::UniqueImmBorrow | ty::MutBorrow => {
|
||||
// Check for those cases where we cannot control
|
||||
// the aliasing and make sure that we are not
|
||||
// being asked to.
|
||||
@ -620,11 +678,11 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
// unsafe. At your own peril and all that.
|
||||
Ok(())
|
||||
}
|
||||
Some(cause) => {
|
||||
Some(alias_cause) => {
|
||||
bccx.report_aliasability_violation(
|
||||
borrow_span,
|
||||
BorrowViolation,
|
||||
cause);
|
||||
BorrowViolation(loan_cause),
|
||||
alias_cause);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
@ -633,11 +691,18 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restriction_set(&self, req_mutbl: LoanMutability)
|
||||
-> RestrictionSet {
|
||||
match req_mutbl {
|
||||
ImmutableMutability => RESTR_MUTATE | RESTR_CLAIM,
|
||||
MutableMutability => RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE,
|
||||
fn restriction_set(&self, req_kind: ty::BorrowKind) -> RestrictionSet {
|
||||
match req_kind {
|
||||
// If borrowing data as immutable, no mutation allowed:
|
||||
ty::ImmBorrow => RESTR_MUTATE,
|
||||
|
||||
// If borrowing data as mutable, no mutation nor other
|
||||
// borrows allowed:
|
||||
ty::MutBorrow => RESTR_MUTATE | RESTR_FREEZE,
|
||||
|
||||
// If borrowing data as unique imm, no mutation nor other
|
||||
// borrows allowed:
|
||||
ty::UniqueImmBorrow => RESTR_MUTATE | RESTR_FREEZE,
|
||||
}
|
||||
}
|
||||
|
||||
@ -719,11 +784,11 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
* `gather_pat()`.
|
||||
*/
|
||||
|
||||
let mc_ctxt = self.bccx.mc_ctxt();
|
||||
let mut mc = self.bccx.mc();
|
||||
for arg in decl.inputs.iter() {
|
||||
let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id);
|
||||
|
||||
let arg_cmt = mc_ctxt.cat_rvalue(
|
||||
let arg_cmt = mc.cat_rvalue(
|
||||
arg.id,
|
||||
arg.pat.span,
|
||||
ty::ReScope(body.id), // Args live only as long as the fn body.
|
||||
@ -735,7 +800,7 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
|
||||
fn gather_pat(&mut self,
|
||||
discr_cmt: mc::cmt,
|
||||
root_pat: &ast::Pat,
|
||||
root_pat: @ast::Pat,
|
||||
arm_match_ids: Option<(ast::NodeId, ast::NodeId)>) {
|
||||
/*!
|
||||
* Walks patterns, examining the bindings to determine if they
|
||||
@ -774,13 +839,12 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
}
|
||||
}
|
||||
};
|
||||
let loan_mutability =
|
||||
LoanMutability::from_ast_mutability(mutbl);
|
||||
self.guarantee_valid(pat.id,
|
||||
pat.span,
|
||||
cmt_discr,
|
||||
loan_mutability,
|
||||
scope_r);
|
||||
mutbl,
|
||||
scope_r,
|
||||
RefBinding);
|
||||
}
|
||||
ast::BindByValue(_) => {
|
||||
// No borrows here, but there may be moves
|
||||
@ -797,14 +861,15 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
// original vector. This is effectively a borrow of
|
||||
// the elements of the vector being matched.
|
||||
|
||||
let slice_ty = ty::node_id_to_type(self.tcx(),
|
||||
slice_pat.id);
|
||||
let (slice_mutbl, slice_r) =
|
||||
self.vec_slice_info(slice_pat, slice_ty);
|
||||
let mcx = self.bccx.mc_ctxt();
|
||||
let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
|
||||
let slice_loan_mutability =
|
||||
LoanMutability::from_ast_mutability(slice_mutbl);
|
||||
let (slice_cmt, slice_borrow_kind, slice_r) = {
|
||||
match self.bccx.mc().cat_slice_pattern(cmt, slice_pat) {
|
||||
Ok(v) => v,
|
||||
Err(()) => {
|
||||
self.tcx().sess.span_bug(slice_pat.span,
|
||||
"Err from mc")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Note: We declare here that the borrow occurs upon
|
||||
// entering the `[...]` pattern. This implies that
|
||||
@ -823,11 +888,9 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
// trans do the right thing, and it would only work
|
||||
// for `~` vectors. It seems simpler to just require
|
||||
// that people call `vec.pop()` or `vec.unshift()`.
|
||||
self.guarantee_valid(pat.id,
|
||||
pat.span,
|
||||
cmt_index,
|
||||
slice_loan_mutability,
|
||||
slice_r);
|
||||
self.guarantee_valid(pat.id, pat.span,
|
||||
slice_cmt, slice_borrow_kind, slice_r,
|
||||
RefBinding);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
@ -835,33 +898,6 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn vec_slice_info(&self, pat: &ast::Pat, slice_ty: ty::t)
|
||||
-> (ast::Mutability, ty::Region) {
|
||||
/*!
|
||||
*
|
||||
* In a pattern like [a, b, ..c], normally `c` has slice type,
|
||||
* but if you have [a, b, ..ref c], then the type of `ref c`
|
||||
* will be `&&[]`, so to extract the slice details we have
|
||||
* to recurse through rptrs.
|
||||
*/
|
||||
|
||||
match ty::get(slice_ty).sty {
|
||||
ty::ty_vec(slice_mt, ty::vstore_slice(slice_r)) => {
|
||||
(slice_mt.mutbl, slice_r)
|
||||
}
|
||||
|
||||
ty::ty_rptr(_, ref mt) => {
|
||||
self.vec_slice_info(pat, mt.ty)
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.tcx().sess.span_bug(
|
||||
pat.span,
|
||||
format!("type of slice pattern is not a slice"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pat_is_binding(&self, pat: &ast::Pat) -> bool {
|
||||
pat_util::pat_is_binding(self.bccx.tcx.def_map, pat)
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ use std::vec;
|
||||
use middle::borrowck::*;
|
||||
use mc = middle::mem_categorization;
|
||||
use middle::ty;
|
||||
use syntax::ast::{MutImmutable, MutMutable};
|
||||
use syntax::codemap::Span;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
pub enum RestrictionResult {
|
||||
Safe,
|
||||
@ -26,12 +26,14 @@ pub enum RestrictionResult {
|
||||
|
||||
pub fn compute_restrictions(bccx: &BorrowckCtxt,
|
||||
span: Span,
|
||||
cause: LoanCause,
|
||||
cmt: mc::cmt,
|
||||
loan_region: ty::Region,
|
||||
restr: RestrictionSet) -> RestrictionResult {
|
||||
let ctxt = RestrictionsContext {
|
||||
bccx: bccx,
|
||||
span: span,
|
||||
cause: cause,
|
||||
cmt_original: cmt,
|
||||
loan_region: loan_region,
|
||||
};
|
||||
@ -47,12 +49,17 @@ struct RestrictionsContext<'a> {
|
||||
span: Span,
|
||||
cmt_original: mc::cmt,
|
||||
loan_region: ty::Region,
|
||||
cause: LoanCause,
|
||||
}
|
||||
|
||||
impl<'a> RestrictionsContext<'a> {
|
||||
fn restrict(&self,
|
||||
cmt: mc::cmt,
|
||||
restrictions: RestrictionSet) -> RestrictionResult {
|
||||
debug!("restrict(cmt={}, restrictions={})",
|
||||
cmt.repr(self.bccx.tcx),
|
||||
restrictions.repr(self.bccx.tcx));
|
||||
|
||||
match cmt.cat {
|
||||
mc::cat_rvalue(..) => {
|
||||
// Effectively, rvalues are stored into a
|
||||
@ -64,7 +71,8 @@ impl<'a> RestrictionsContext<'a> {
|
||||
}
|
||||
|
||||
mc::cat_local(local_id) |
|
||||
mc::cat_arg(local_id) => {
|
||||
mc::cat_arg(local_id) |
|
||||
mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => {
|
||||
// R-Variable
|
||||
let lp = @LpVar(local_id);
|
||||
SafeIf(lp, ~[Restriction {loan_path: lp,
|
||||
@ -77,7 +85,7 @@ impl<'a> RestrictionsContext<'a> {
|
||||
// could cause the type of the memory to change.
|
||||
self.restrict(
|
||||
cmt_base,
|
||||
restrictions | RESTR_MUTATE | RESTR_CLAIM)
|
||||
restrictions | RESTR_MUTATE)
|
||||
}
|
||||
|
||||
mc::cat_interior(cmt_base, i) => {
|
||||
@ -90,7 +98,7 @@ impl<'a> RestrictionsContext<'a> {
|
||||
self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
|
||||
}
|
||||
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::uniq_ptr) => {
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) => {
|
||||
// R-Deref-Send-Pointer
|
||||
//
|
||||
// When we borrow the interior of an owned pointer, we
|
||||
@ -98,7 +106,7 @@ impl<'a> RestrictionsContext<'a> {
|
||||
// would cause the unique pointer to be freed.
|
||||
let result = self.restrict(
|
||||
cmt_base,
|
||||
restrictions | RESTR_MUTATE | RESTR_CLAIM);
|
||||
restrictions | RESTR_MUTATE);
|
||||
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
|
||||
}
|
||||
|
||||
@ -107,12 +115,14 @@ impl<'a> RestrictionsContext<'a> {
|
||||
Safe
|
||||
}
|
||||
|
||||
mc::cat_deref(cmt_base, _, mc::region_ptr(MutImmutable, lt)) => {
|
||||
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
|
||||
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => {
|
||||
// R-Deref-Imm-Borrowed
|
||||
if !self.bccx.is_subregion_of(self.loan_region, lt) {
|
||||
self.bccx.report(
|
||||
BckError {
|
||||
span: self.span,
|
||||
cause: self.cause,
|
||||
cmt: cmt_base,
|
||||
code: err_borrowed_pointer_too_short(
|
||||
self.loan_region, lt, restrictions)});
|
||||
@ -121,17 +131,18 @@ impl<'a> RestrictionsContext<'a> {
|
||||
Safe
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::gc_ptr) => {
|
||||
mc::cat_deref(_, _, mc::GcPtr) => {
|
||||
// R-Deref-Imm-Managed
|
||||
Safe
|
||||
}
|
||||
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::region_ptr(MutMutable, lt)) => {
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => {
|
||||
// R-Deref-Mut-Borrowed
|
||||
if !self.bccx.is_subregion_of(self.loan_region, lt) {
|
||||
self.bccx.report(
|
||||
BckError {
|
||||
span: self.span,
|
||||
cause: self.cause,
|
||||
cmt: cmt_base,
|
||||
code: err_borrowed_pointer_too_short(
|
||||
self.loan_region, lt, restrictions)});
|
||||
@ -142,12 +153,11 @@ impl<'a> RestrictionsContext<'a> {
|
||||
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
|
||||
// We are very trusting when working with unsafe pointers.
|
||||
Safe
|
||||
}
|
||||
|
||||
mc::cat_stack_upvar(cmt_base) |
|
||||
mc::cat_discr(cmt_base, _) => {
|
||||
self.restrict(cmt_base, restrictions)
|
||||
}
|
||||
|
@ -120,41 +120,32 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
|
||||
body: &ast::Block,
|
||||
sp: Span,
|
||||
id: ast::NodeId) {
|
||||
match fk {
|
||||
&visit::FkFnBlock(..) => {
|
||||
// Closures are checked as part of their containing fn item.
|
||||
}
|
||||
debug!("borrowck_fn(id={})", id);
|
||||
|
||||
&visit::FkItemFn(..) | &visit::FkMethod(..) => {
|
||||
debug!("borrowck_fn(id={:?})", id);
|
||||
|
||||
// Check the body of fn items.
|
||||
let (id_range, all_loans, move_data) =
|
||||
gather_loans::gather_loans(this, decl, body);
|
||||
|
||||
let all_loans = all_loans.borrow();
|
||||
let mut loan_dfcx = DataFlowContext::new(this.tcx,
|
||||
this.method_map,
|
||||
LoanDataFlowOperator,
|
||||
id_range,
|
||||
all_loans.get().len());
|
||||
for (loan_idx, loan) in all_loans.get().iter().enumerate() {
|
||||
loan_dfcx.add_gen(loan.gen_scope, loan_idx);
|
||||
loan_dfcx.add_kill(loan.kill_scope, loan_idx);
|
||||
}
|
||||
|
||||
loan_dfcx.propagate(body);
|
||||
|
||||
let flowed_moves = move_data::FlowedMoveData::new(move_data,
|
||||
this.tcx,
|
||||
this.method_map,
|
||||
id_range,
|
||||
body);
|
||||
|
||||
check_loans::check_loans(this, &loan_dfcx, flowed_moves,
|
||||
*all_loans.get(), body);
|
||||
}
|
||||
// Check the body of fn items.
|
||||
let (id_range, all_loans, move_data) =
|
||||
gather_loans::gather_loans(this, decl, body);
|
||||
let all_loans = all_loans.borrow();
|
||||
let mut loan_dfcx =
|
||||
DataFlowContext::new(this.tcx,
|
||||
this.method_map,
|
||||
LoanDataFlowOperator,
|
||||
id_range,
|
||||
all_loans.get().len());
|
||||
for (loan_idx, loan) in all_loans.get().iter().enumerate() {
|
||||
loan_dfcx.add_gen(loan.gen_scope, loan_idx);
|
||||
loan_dfcx.add_kill(loan.kill_scope, loan_idx);
|
||||
}
|
||||
loan_dfcx.propagate(body);
|
||||
|
||||
let flowed_moves = move_data::FlowedMoveData::new(move_data,
|
||||
this.tcx,
|
||||
this.method_map,
|
||||
id_range,
|
||||
body);
|
||||
|
||||
check_loans::check_loans(this, &loan_dfcx, flowed_moves,
|
||||
*all_loans.get(), body);
|
||||
|
||||
visit::walk_fn(this, fk, decl, body, sp, id, ());
|
||||
}
|
||||
@ -211,41 +202,25 @@ pub enum PartialTotal {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Loans and loan paths
|
||||
|
||||
#[deriving(Clone, Eq)]
|
||||
pub enum LoanMutability {
|
||||
ImmutableMutability,
|
||||
MutableMutability,
|
||||
}
|
||||
|
||||
impl LoanMutability {
|
||||
pub fn from_ast_mutability(ast_mutability: ast::Mutability)
|
||||
-> LoanMutability {
|
||||
match ast_mutability {
|
||||
ast::MutImmutable => ImmutableMutability,
|
||||
ast::MutMutable => MutableMutability,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToStr for LoanMutability {
|
||||
fn to_str(&self) -> ~str {
|
||||
match *self {
|
||||
ImmutableMutability => ~"immutable",
|
||||
MutableMutability => ~"mutable",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Record of a loan that was issued.
|
||||
pub struct Loan {
|
||||
index: uint,
|
||||
loan_path: @LoanPath,
|
||||
cmt: mc::cmt,
|
||||
mutbl: LoanMutability,
|
||||
kind: ty::BorrowKind,
|
||||
restrictions: ~[Restriction],
|
||||
gen_scope: ast::NodeId,
|
||||
kill_scope: ast::NodeId,
|
||||
span: Span,
|
||||
cause: LoanCause,
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum LoanCause {
|
||||
ClosureCapture(Span),
|
||||
AddrOf,
|
||||
AutoRef,
|
||||
RefBinding,
|
||||
}
|
||||
|
||||
#[deriving(Eq, IterBytes)]
|
||||
@ -283,7 +258,9 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
|
||||
None
|
||||
}
|
||||
|
||||
mc::cat_local(id) | mc::cat_arg(id) => {
|
||||
mc::cat_local(id) |
|
||||
mc::cat_arg(id) |
|
||||
mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
|
||||
Some(@LpVar(id))
|
||||
}
|
||||
|
||||
@ -300,7 +277,6 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
|
||||
}
|
||||
|
||||
mc::cat_downcast(cmt_base) |
|
||||
mc::cat_stack_upvar(cmt_base) |
|
||||
mc::cat_discr(cmt_base, _) => {
|
||||
opt_loan_path(cmt_base)
|
||||
}
|
||||
@ -313,8 +289,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
|
||||
// Borrowing an lvalue often results in *restrictions* that limit what
|
||||
// can be done with this lvalue during the scope of the loan:
|
||||
//
|
||||
// - `RESTR_MUTATE`: The lvalue may not be modified.
|
||||
// - `RESTR_CLAIM`: `&mut` borrows of the lvalue are forbidden.
|
||||
// - `RESTR_MUTATE`: The lvalue may not be modified or `&mut` borrowed.
|
||||
// - `RESTR_FREEZE`: `&` borrows of the lvalue are forbidden.
|
||||
//
|
||||
// In addition, no value which is restricted may be moved. Therefore,
|
||||
@ -333,8 +308,7 @@ pub struct RestrictionSet {
|
||||
|
||||
pub static RESTR_EMPTY: RestrictionSet = RestrictionSet {bits: 0b0000};
|
||||
pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b0001};
|
||||
pub static RESTR_CLAIM: RestrictionSet = RestrictionSet {bits: 0b0010};
|
||||
pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0100};
|
||||
pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b0010};
|
||||
|
||||
impl RestrictionSet {
|
||||
pub fn intersects(&self, restr: RestrictionSet) -> bool {
|
||||
@ -358,6 +332,12 @@ impl BitAnd<RestrictionSet,RestrictionSet> for RestrictionSet {
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for RestrictionSet {
|
||||
fn repr(&self, _tcx: ty::ctxt) -> ~str {
|
||||
format!("RestrictionSet(0x{:x})", self.bits as uint)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Rooting of managed boxes
|
||||
//
|
||||
@ -393,10 +373,9 @@ pub fn root_map() -> root_map {
|
||||
// Errors that can occur
|
||||
#[deriving(Eq)]
|
||||
pub enum bckerr_code {
|
||||
err_mutbl(LoanMutability),
|
||||
err_mutbl,
|
||||
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
|
||||
err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
|
||||
err_freeze_aliasable_const,
|
||||
err_borrowed_pointer_too_short(
|
||||
ty::Region, ty::Region, RestrictionSet), // loan, ptr
|
||||
}
|
||||
@ -406,13 +385,14 @@ pub enum bckerr_code {
|
||||
#[deriving(Eq)]
|
||||
pub struct BckError {
|
||||
span: Span,
|
||||
cause: LoanCause,
|
||||
cmt: mc::cmt,
|
||||
code: bckerr_code
|
||||
}
|
||||
|
||||
pub enum AliasableViolationKind {
|
||||
MutabilityViolation,
|
||||
BorrowViolation
|
||||
BorrowViolation(LoanCause)
|
||||
}
|
||||
|
||||
pub enum MovedValueUseKind {
|
||||
@ -439,29 +419,55 @@ impl BorrowckCtxt {
|
||||
moves_map.get().contains(&id)
|
||||
}
|
||||
|
||||
pub fn mc(&self) -> mc::MemCategorizationContext<TcxTyper> {
|
||||
mc::MemCategorizationContext {
|
||||
typer: TcxTyper {
|
||||
tcx: self.tcx,
|
||||
method_map: self.method_map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_expr(&self, expr: &ast::Expr) -> mc::cmt {
|
||||
mc::cat_expr(self.tcx, self.method_map, expr)
|
||||
match self.mc().cat_expr(expr) {
|
||||
Ok(c) => c,
|
||||
Err(()) => {
|
||||
self.tcx.sess.span_bug(expr.span, "error in mem categorization");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> mc::cmt {
|
||||
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
|
||||
match self.mc().cat_expr_unadjusted(expr) {
|
||||
Ok(c) => c,
|
||||
Err(()) => {
|
||||
self.tcx.sess.span_bug(expr.span, "error in mem categorization");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_expr_autoderefd(&self,
|
||||
expr: &ast::Expr,
|
||||
adj: &ty::AutoAdjustment)
|
||||
-> mc::cmt {
|
||||
match *adj {
|
||||
let r = match *adj {
|
||||
ty::AutoAddEnv(..) | ty::AutoObject(..) => {
|
||||
// no autoderefs
|
||||
mc::cat_expr_unadjusted(self.tcx, self.method_map, expr)
|
||||
self.mc().cat_expr_unadjusted(expr)
|
||||
}
|
||||
|
||||
ty::AutoDerefRef(
|
||||
ty::AutoDerefRef {
|
||||
autoderefs: autoderefs, ..}) => {
|
||||
mc::cat_expr_autoderefd(self.tcx, self.method_map, expr,
|
||||
autoderefs)
|
||||
self.mc().cat_expr_autoderefd(expr, autoderefs)
|
||||
}
|
||||
};
|
||||
|
||||
match r {
|
||||
Ok(c) => c,
|
||||
Err(()) => {
|
||||
self.tcx.sess.span_bug(expr.span,
|
||||
"error in mem categorization");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -472,7 +478,23 @@ impl BorrowckCtxt {
|
||||
ty: ty::t,
|
||||
def: ast::Def)
|
||||
-> mc::cmt {
|
||||
mc::cat_def(self.tcx, self.method_map, id, span, ty, def)
|
||||
match self.mc().cat_def(id, span, ty, def) {
|
||||
Ok(c) => c,
|
||||
Err(()) => {
|
||||
self.tcx.sess.span_bug(span, "error in mem categorization");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_captured_var(&self,
|
||||
id: ast::NodeId,
|
||||
span: Span,
|
||||
captured_var: &moves::CaptureVar) -> mc::cmt {
|
||||
// Create the cmt for the variable being borrowed, from the
|
||||
// caller's perspective
|
||||
let var_id = ast_util::def_id_of_def(captured_var.def).node;
|
||||
let var_ty = ty::node_id_to_type(self.tcx, var_id);
|
||||
self.cat_def(id, span, var_ty, captured_var.def)
|
||||
}
|
||||
|
||||
pub fn cat_discr(&self, cmt: mc::cmt, match_id: ast::NodeId) -> mc::cmt {
|
||||
@ -481,17 +503,12 @@ impl BorrowckCtxt {
|
||||
..*cmt}
|
||||
}
|
||||
|
||||
pub fn mc_ctxt(&self) -> mc::mem_categorization_ctxt {
|
||||
mc::mem_categorization_ctxt {tcx: self.tcx,
|
||||
method_map: self.method_map}
|
||||
}
|
||||
|
||||
pub fn cat_pattern(&self,
|
||||
cmt: mc::cmt,
|
||||
pat: &ast::Pat,
|
||||
pat: @ast::Pat,
|
||||
op: |mc::cmt, &ast::Pat|) {
|
||||
let mc = self.mc_ctxt();
|
||||
mc.cat_pattern(cmt, pat, op);
|
||||
let r = self.mc().cat_pattern(cmt, pat, |_,x,y| op(x,y));
|
||||
assert!(r.is_ok());
|
||||
}
|
||||
|
||||
pub fn report(&self, err: BckError) {
|
||||
@ -622,24 +639,35 @@ impl BorrowckCtxt {
|
||||
|
||||
pub fn bckerr_to_str(&self, err: BckError) -> ~str {
|
||||
match err.code {
|
||||
err_mutbl(lk) => {
|
||||
format!("cannot borrow {} {} as {}",
|
||||
err.cmt.mutbl.to_user_str(),
|
||||
self.cmt_to_str(err.cmt),
|
||||
self.mut_to_str(lk))
|
||||
err_mutbl => {
|
||||
let descr = match opt_loan_path(err.cmt) {
|
||||
None => format!("{} {}",
|
||||
err.cmt.mutbl.to_user_str(),
|
||||
self.cmt_to_str(err.cmt)),
|
||||
Some(lp) => format!("{} {} `{}`",
|
||||
err.cmt.mutbl.to_user_str(),
|
||||
self.cmt_to_str(err.cmt),
|
||||
self.loan_path_to_str(lp)),
|
||||
};
|
||||
|
||||
match err.cause {
|
||||
ClosureCapture(_) => {
|
||||
format!("closure cannot assign to {}", descr)
|
||||
}
|
||||
AddrOf | RefBinding | AutoRef => {
|
||||
format!("cannot borrow {} as mutable", descr)
|
||||
}
|
||||
}
|
||||
}
|
||||
err_out_of_root_scope(..) => {
|
||||
format!("cannot root managed value long enough")
|
||||
}
|
||||
err_out_of_scope(..) => {
|
||||
format!("borrowed value does not live long enough")
|
||||
}
|
||||
err_freeze_aliasable_const => {
|
||||
// Means that the user borrowed a ~T or enum value
|
||||
// residing in &const or @const pointer. Terrible
|
||||
// error message, but then &const and @const are
|
||||
// supposed to be going away.
|
||||
format!("unsafe borrow of aliasable, const value")
|
||||
let msg = match opt_loan_path(err.cmt) {
|
||||
None => format!("borrowed value"),
|
||||
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
|
||||
};
|
||||
format!("{} does not live long enough", msg)
|
||||
}
|
||||
err_borrowed_pointer_too_short(..) => {
|
||||
let descr = match opt_loan_path(err.cmt) {
|
||||
@ -659,8 +687,24 @@ impl BorrowckCtxt {
|
||||
kind: AliasableViolationKind,
|
||||
cause: mc::AliasableReason) {
|
||||
let prefix = match kind {
|
||||
MutabilityViolation => "cannot assign to data",
|
||||
BorrowViolation => "cannot borrow data mutably"
|
||||
MutabilityViolation => {
|
||||
"cannot assign to data"
|
||||
}
|
||||
BorrowViolation(ClosureCapture(_)) => {
|
||||
// I don't think we can get aliasability violations
|
||||
// with closure captures, so no need to come up with a
|
||||
// good error message. The reason this cannot happen
|
||||
// is because we only capture local variables in
|
||||
// closures, and those are never aliasable.
|
||||
self.tcx.sess.span_bug(
|
||||
span,
|
||||
"aliasability violation with closure");
|
||||
}
|
||||
BorrowViolation(AddrOf) |
|
||||
BorrowViolation(AutoRef) |
|
||||
BorrowViolation(RefBinding) => {
|
||||
"cannot borrow data mutably"
|
||||
}
|
||||
};
|
||||
|
||||
match cause {
|
||||
@ -680,7 +724,7 @@ impl BorrowckCtxt {
|
||||
span,
|
||||
format!("{} in a `@` pointer", prefix));
|
||||
}
|
||||
mc::AliasableBorrowed(_) => {
|
||||
mc::AliasableBorrowed => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("{} in a `&` reference", prefix));
|
||||
@ -691,7 +735,7 @@ impl BorrowckCtxt {
|
||||
pub fn note_and_explain_bckerr(&self, err: BckError) {
|
||||
let code = err.code;
|
||||
match code {
|
||||
err_mutbl(..) | err_freeze_aliasable_const(..) => {}
|
||||
err_mutbl(..) => { }
|
||||
|
||||
err_out_of_root_scope(super_scope, sub_scope) => {
|
||||
note_and_explain_region(
|
||||
@ -738,52 +782,16 @@ impl BorrowckCtxt {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_loan_path_to_str_from_interior(&self,
|
||||
loan_path: &LoanPath,
|
||||
out: &mut ~str) {
|
||||
match *loan_path {
|
||||
LpExtend(_, _, LpDeref(_)) => {
|
||||
out.push_char('(');
|
||||
self.append_loan_path_to_str(loan_path, out);
|
||||
out.push_char(')');
|
||||
}
|
||||
LpExtend(_, _, LpInterior(_)) |
|
||||
LpVar(_) => {
|
||||
self.append_loan_path_to_str(loan_path, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_loan_path_to_str(&self,
|
||||
loan_path: &LoanPath,
|
||||
out: &mut ~str) {
|
||||
match *loan_path {
|
||||
LpVar(id) => {
|
||||
match self.tcx.items.find(id) {
|
||||
Some(ast_map::NodeLocal(pat)) => {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
let ident = ast_util::path_to_ident(path);
|
||||
let string = token::get_ident(ident.name);
|
||||
out.push_str(string.get());
|
||||
}
|
||||
_ => {
|
||||
self.tcx.sess.bug(
|
||||
format!("loan path LpVar({:?}) maps to {:?}, not local",
|
||||
id, pat));
|
||||
}
|
||||
}
|
||||
}
|
||||
r => {
|
||||
self.tcx.sess.bug(
|
||||
format!("loan path LpVar({:?}) maps to {:?}, not local",
|
||||
id, r));
|
||||
}
|
||||
}
|
||||
out.push_str(ty::local_var_name_str(self.tcx, id).get());
|
||||
}
|
||||
|
||||
LpExtend(lp_base, _, LpInterior(mc::InteriorField(fname))) => {
|
||||
self.append_loan_path_to_str_from_interior(lp_base, out);
|
||||
self.append_autoderefd_loan_path_to_str(lp_base, out);
|
||||
match fname {
|
||||
mc::NamedField(ref fname) => {
|
||||
let string = token::get_ident(*fname);
|
||||
@ -798,8 +806,8 @@ impl BorrowckCtxt {
|
||||
}
|
||||
|
||||
LpExtend(lp_base, _, LpInterior(mc::InteriorElement(_))) => {
|
||||
self.append_loan_path_to_str_from_interior(lp_base, out);
|
||||
out.push_str("[]");
|
||||
self.append_autoderefd_loan_path_to_str(lp_base, out);
|
||||
out.push_str("[..]");
|
||||
}
|
||||
|
||||
LpExtend(lp_base, _, LpDeref(_)) => {
|
||||
@ -809,6 +817,23 @@ impl BorrowckCtxt {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_autoderefd_loan_path_to_str(&self,
|
||||
loan_path: &LoanPath,
|
||||
out: &mut ~str) {
|
||||
match *loan_path {
|
||||
LpExtend(lp_base, _, LpDeref(_)) => {
|
||||
// For a path like `(*x).f` or `(*x)[3]`, autoderef
|
||||
// rules would normally allow users to omit the `*x`.
|
||||
// So just serialize such paths to `x.f` or x[3]` respectively.
|
||||
self.append_autoderefd_loan_path_to_str(lp_base, out)
|
||||
}
|
||||
|
||||
LpVar(..) | LpExtend(_, _, LpInterior(..)) => {
|
||||
self.append_loan_path_to_str(loan_path, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn loan_path_to_str(&self, loan_path: &LoanPath) -> ~str {
|
||||
let mut result = ~"";
|
||||
self.append_loan_path_to_str(loan_path, &mut result);
|
||||
@ -816,13 +841,11 @@ impl BorrowckCtxt {
|
||||
}
|
||||
|
||||
pub fn cmt_to_str(&self, cmt: mc::cmt) -> ~str {
|
||||
let mc = &mc::mem_categorization_ctxt {tcx: self.tcx,
|
||||
method_map: self.method_map};
|
||||
mc.cmt_to_str(cmt)
|
||||
self.mc().cmt_to_str(cmt)
|
||||
}
|
||||
|
||||
pub fn mut_to_str(&self, mutbl: LoanMutability) -> ~str {
|
||||
mutbl.to_str()
|
||||
pub fn mut_to_str(&self, mutbl: ast::Mutability) -> ~str {
|
||||
self.mc().mut_to_str(mutbl)
|
||||
}
|
||||
|
||||
pub fn mut_to_keyword(&self, mutbl: ast::Mutability) -> &'static str {
|
||||
@ -843,11 +866,6 @@ impl DataFlowOperator for LoanDataFlowOperator {
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // loans from both preds are in scope
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn walk_closures(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for Loan {
|
||||
@ -855,7 +873,7 @@ impl Repr for Loan {
|
||||
format!("Loan_{:?}({}, {:?}, {:?}-{:?}, {})",
|
||||
self.index,
|
||||
self.loan_path.repr(tcx),
|
||||
self.mutbl,
|
||||
self.kind,
|
||||
self.gen_scope,
|
||||
self.kill_scope,
|
||||
self.restrictions.repr(tcx))
|
||||
@ -890,3 +908,39 @@ impl Repr for LoanPath {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TcxTyper {
|
||||
tcx: ty::ctxt,
|
||||
method_map: typeck::method_map,
|
||||
}
|
||||
|
||||
impl mc::Typer for TcxTyper {
|
||||
fn tcx(&self) -> ty::ctxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn node_ty(&mut self, id: ast::NodeId) -> mc::McResult<ty::t> {
|
||||
Ok(ty::node_id_to_type(self.tcx, id))
|
||||
}
|
||||
|
||||
fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
|
||||
let adjustments = self.tcx.adjustments.borrow();
|
||||
adjustments.get().find_copy(&id)
|
||||
}
|
||||
|
||||
fn is_method_call(&mut self, id: ast::NodeId) -> bool {
|
||||
let method_map = self.method_map.borrow();
|
||||
method_map.get().contains_key(&id)
|
||||
}
|
||||
|
||||
fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
|
||||
self.tcx.region_maps.temporary_scope(id)
|
||||
}
|
||||
|
||||
fn upvar_borrow(&mut self, id: ty::UpvarId) -> ty::UpvarBorrow {
|
||||
let upvar_borrow_map = self.tcx.upvar_borrow_map.borrow();
|
||||
upvar_borrow_map.get().get_copy(&id)
|
||||
}
|
||||
}
|
||||
|
@ -722,11 +722,6 @@ impl DataFlowOperator for MoveDataFlowOperator {
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // moves from both preds are in scope
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn walk_closures(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl DataFlowOperator for AssignDataFlowOperator {
|
||||
@ -739,9 +734,4 @@ impl DataFlowOperator for AssignDataFlowOperator {
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // moves from both preds are in scope
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn walk_closures(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
*/
|
||||
|
||||
|
||||
use std::cast;
|
||||
use std::io;
|
||||
use std::uint;
|
||||
use std::vec;
|
||||
@ -72,9 +71,6 @@ pub trait DataFlowOperator {
|
||||
|
||||
/// Joins two predecessor bits together, typically either `|` or `&`
|
||||
fn join(&self, succ: uint, pred: uint) -> uint;
|
||||
|
||||
/// True if we should propagate through closures
|
||||
fn walk_closures(&self) -> bool;
|
||||
}
|
||||
|
||||
struct PropagationContext<'a, O> {
|
||||
@ -373,8 +369,8 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
blk: &ast::Block,
|
||||
in_out: &mut [uint],
|
||||
loop_scopes: &mut ~[LoopScope]) {
|
||||
debug!("DataFlowContext::walk_block(blk.id={:?}, in_out={})",
|
||||
blk.id, bits_to_str(reslice(in_out)));
|
||||
debug!("DataFlowContext::walk_block(blk.id={}, in_out={})",
|
||||
blk.id, bits_to_str(in_out));
|
||||
|
||||
self.merge_with_entry_set(blk.id, in_out);
|
||||
|
||||
@ -425,99 +421,12 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
in_out: &mut [uint],
|
||||
loop_scopes: &mut ~[LoopScope]) {
|
||||
debug!("DataFlowContext::walk_expr(expr={}, in_out={})",
|
||||
expr.repr(self.dfcx.tcx), bits_to_str(reslice(in_out)));
|
||||
expr.repr(self.dfcx.tcx), bits_to_str(in_out));
|
||||
|
||||
self.merge_with_entry_set(expr.id, in_out);
|
||||
|
||||
match expr.node {
|
||||
ast::ExprFnBlock(ref decl, body) |
|
||||
ast::ExprProc(ref decl, body) => {
|
||||
if self.dfcx.oper.walk_closures() {
|
||||
// In the absence of once fns, we must assume that
|
||||
// every function body will execute more than
|
||||
// once. Thus we treat every function body like a
|
||||
// loop.
|
||||
//
|
||||
// What is subtle and a bit tricky, also, is how
|
||||
// to deal with the "output" bits---that is, what
|
||||
// do we consider to be the successor of a
|
||||
// function body, given that it could be called
|
||||
// from any point within its lifetime? What we do
|
||||
// is to add their effects immediately as of the
|
||||
// point of creation. Of course we have to ensure
|
||||
// that this is sound for the analyses which make
|
||||
// use of dataflow.
|
||||
//
|
||||
// In the case of the initedness checker (which
|
||||
// does not currently use dataflow, but I hope to
|
||||
// convert at some point), we will simply not walk
|
||||
// closures at all, so it's a moot point.
|
||||
//
|
||||
// In the case of the borrow checker, this means
|
||||
// the loans which would be created by calling a
|
||||
// function come into effect immediately when the
|
||||
// function is created. This is guaranteed to be
|
||||
// earlier than the point at which the loan
|
||||
// actually comes into scope (which is the point
|
||||
// at which the closure is *called*). Because
|
||||
// loans persist until the scope of the loans is
|
||||
// exited, it is always a safe approximation to
|
||||
// have a loan begin earlier than it actually will
|
||||
// at runtime, so this should be sound.
|
||||
//
|
||||
// We stil have to be careful in the region
|
||||
// checker and borrow checker to treat function
|
||||
// bodies like loops, which implies some
|
||||
// limitations. For example, a closure cannot root
|
||||
// a managed box for longer than its body.
|
||||
//
|
||||
// General control flow looks like this:
|
||||
//
|
||||
// +- (expr) <----------+
|
||||
// | | |
|
||||
// | v |
|
||||
// | (body) -----------+--> (exit)
|
||||
// | | |
|
||||
// | + (break/loop) -+
|
||||
// | |
|
||||
// +--------------------+
|
||||
//
|
||||
// This is a bit more conservative than a loop.
|
||||
// Note that we must assume that even after a
|
||||
// `break` occurs (e.g., in a `for` loop) that the
|
||||
// closure may be reinvoked.
|
||||
//
|
||||
// One difference from other loops is that `loop`
|
||||
// and `break` statements which target a closure
|
||||
// both simply add to the `break_bits`.
|
||||
|
||||
// func_bits represents the state when the function
|
||||
// returns
|
||||
let mut func_bits = reslice(in_out).to_owned();
|
||||
|
||||
loop_scopes.push(LoopScope {
|
||||
loop_id: expr.id,
|
||||
break_bits: reslice(in_out).to_owned()
|
||||
});
|
||||
for input in decl.inputs.iter() {
|
||||
self.walk_pat(input.pat, func_bits, loop_scopes);
|
||||
}
|
||||
self.walk_block(body, func_bits, loop_scopes);
|
||||
|
||||
// add the bits from any early return via `break`,
|
||||
// `continue`, or `return` into `func_bits`
|
||||
let loop_scope = loop_scopes.pop().unwrap();
|
||||
join_bits(&self.dfcx.oper, loop_scope.break_bits, func_bits);
|
||||
|
||||
// add `func_bits` to the entry bits for `expr`,
|
||||
// since we must assume the function may be called
|
||||
// more than once
|
||||
self.add_to_entry_set(expr.id, reslice(func_bits));
|
||||
|
||||
// the final exit bits include whatever was present
|
||||
// in the original, joined with the bits from the function
|
||||
join_bits(&self.dfcx.oper, func_bits, in_out);
|
||||
}
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) => {
|
||||
}
|
||||
|
||||
ast::ExprIf(cond, then, els) => {
|
||||
@ -536,7 +445,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
//
|
||||
self.walk_expr(cond, in_out, loop_scopes);
|
||||
|
||||
let mut then_bits = reslice(in_out).to_owned();
|
||||
let mut then_bits = in_out.to_owned();
|
||||
self.walk_block(then, then_bits, loop_scopes);
|
||||
|
||||
self.walk_opt_expr(els, in_out, loop_scopes);
|
||||
@ -558,10 +467,10 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
|
||||
self.walk_expr(cond, in_out, loop_scopes);
|
||||
|
||||
let mut body_bits = reslice(in_out).to_owned();
|
||||
let mut body_bits = in_out.to_owned();
|
||||
loop_scopes.push(LoopScope {
|
||||
loop_id: expr.id,
|
||||
break_bits: reslice(in_out).to_owned()
|
||||
break_bits: in_out.to_owned()
|
||||
});
|
||||
self.walk_block(blk, body_bits, loop_scopes);
|
||||
self.add_to_entry_set(expr.id, body_bits);
|
||||
@ -581,11 +490,11 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
// <--+ (break)
|
||||
//
|
||||
|
||||
let mut body_bits = reslice(in_out).to_owned();
|
||||
let mut body_bits = in_out.to_owned();
|
||||
self.reset(in_out);
|
||||
loop_scopes.push(LoopScope {
|
||||
loop_id: expr.id,
|
||||
break_bits: reslice(in_out).to_owned()
|
||||
break_bits: in_out.to_owned()
|
||||
});
|
||||
self.walk_block(blk, body_bits, loop_scopes);
|
||||
self.add_to_entry_set(expr.id, body_bits);
|
||||
@ -609,7 +518,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
//
|
||||
self.walk_expr(discr, in_out, loop_scopes);
|
||||
|
||||
let mut guards = reslice(in_out).to_owned();
|
||||
let mut guards = in_out.to_owned();
|
||||
|
||||
// We know that exactly one arm will be taken, so we
|
||||
// can start out with a blank slate and just union
|
||||
@ -622,7 +531,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
|
||||
// determine the bits for the body and then union
|
||||
// them into `in_out`, which reflects all bodies to date
|
||||
let mut body = reslice(guards).to_owned();
|
||||
let mut body = guards.to_owned();
|
||||
self.walk_pat_alternatives(arm.pats, body, loop_scopes);
|
||||
self.walk_block(arm.body, body, loop_scopes);
|
||||
join_bits(&self.dfcx.oper, body, in_out);
|
||||
@ -643,7 +552,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
ast::ExprAgain(label) => {
|
||||
let scope = self.find_scope(expr, label, loop_scopes);
|
||||
self.pop_scopes(expr, scope, in_out);
|
||||
self.add_to_entry_set(scope.loop_id, reslice(in_out));
|
||||
self.add_to_entry_set(scope.loop_id, in_out);
|
||||
self.reset(in_out);
|
||||
}
|
||||
|
||||
@ -693,7 +602,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
|
||||
ast::ExprBinary(_, op, l, r) if ast_util::lazy_binop(op) => {
|
||||
self.walk_expr(l, in_out, loop_scopes);
|
||||
let temp = reslice(in_out).to_owned();
|
||||
let temp = in_out.to_owned();
|
||||
self.walk_expr(r, in_out, loop_scopes);
|
||||
join_bits(&self.dfcx.oper, temp, in_out);
|
||||
}
|
||||
@ -756,7 +665,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
|
||||
debug!("pop_scopes(from_expr={}, to_scope={:?}, in_out={})",
|
||||
from_expr.repr(tcx), to_scope.loop_id,
|
||||
bits_to_str(reslice(in_out)));
|
||||
bits_to_str(in_out));
|
||||
|
||||
let mut id = from_expr.id;
|
||||
while id != to_scope.loop_id {
|
||||
@ -781,11 +690,11 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
in_out: &mut [uint]) {
|
||||
self.pop_scopes(from_expr, to_scope, in_out);
|
||||
self.dfcx.apply_kill(from_expr.id, in_out);
|
||||
join_bits(&self.dfcx.oper, reslice(in_out), to_scope.break_bits);
|
||||
debug!("break_from_to(from_expr={}, to_scope={:?}) final break_bits={}",
|
||||
join_bits(&self.dfcx.oper, in_out, to_scope.break_bits);
|
||||
debug!("break_from_to(from_expr={}, to_scope={}) final break_bits={}",
|
||||
from_expr.repr(self.tcx()),
|
||||
to_scope.loop_id,
|
||||
bits_to_str(reslice(in_out)));
|
||||
bits_to_str(in_out));
|
||||
}
|
||||
|
||||
fn walk_exprs(&mut self,
|
||||
@ -830,10 +739,10 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
in_out: &mut [uint],
|
||||
_loop_scopes: &mut ~[LoopScope]) {
|
||||
debug!("DataFlowContext::walk_pat(pat={}, in_out={})",
|
||||
pat.repr(self.dfcx.tcx), bits_to_str(reslice(in_out)));
|
||||
pat.repr(self.dfcx.tcx), bits_to_str(in_out));
|
||||
|
||||
ast_util::walk_pat(pat, |p| {
|
||||
debug!(" p.id={:?} in_out={}", p.id, bits_to_str(reslice(in_out)));
|
||||
debug!(" p.id={} in_out={}", p.id, bits_to_str(in_out));
|
||||
self.merge_with_entry_set(p.id, in_out);
|
||||
self.dfcx.apply_gen_kill(p.id, in_out);
|
||||
true
|
||||
@ -852,7 +761,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
// In the general case, the patterns in `pats` are
|
||||
// alternatives, so we must treat this like an N-way select
|
||||
// statement.
|
||||
let initial_state = reslice(in_out).to_owned();
|
||||
let initial_state = in_out.to_owned();
|
||||
for &pat in pats.iter() {
|
||||
let mut temp = initial_state.clone();
|
||||
self.walk_pat(pat, temp, loop_scopes);
|
||||
@ -929,8 +838,8 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
let (start, end) = self.dfcx.compute_id_range(id);
|
||||
let changed = { // FIXME(#5074) awkward construction
|
||||
let on_entry = self.dfcx.on_entry.mut_slice(start, end);
|
||||
let changed = join_bits(&self.dfcx.oper, reslice(pred_bits), on_entry);
|
||||
copy_bits(reslice(on_entry), pred_bits);
|
||||
let changed = join_bits(&self.dfcx.oper, pred_bits, on_entry);
|
||||
copy_bits(on_entry, pred_bits);
|
||||
changed
|
||||
};
|
||||
if changed {
|
||||
@ -942,7 +851,7 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
|
||||
}
|
||||
|
||||
fn mut_bits_to_str(words: &mut [uint]) -> ~str {
|
||||
bits_to_str(reslice(words))
|
||||
bits_to_str(words)
|
||||
}
|
||||
|
||||
fn bits_to_str(words: &[uint]) -> ~str {
|
||||
@ -1007,9 +916,3 @@ fn bit_str(bit: uint) -> ~str {
|
||||
format!("[{}:{}-{:02x}]", bit, byte, lobits)
|
||||
}
|
||||
|
||||
fn reslice<'a>(v: &'a mut [uint]) -> &'a [uint] {
|
||||
// bFIXME(#5074) this function should not be necessary at all
|
||||
unsafe {
|
||||
cast::transmute(v)
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,19 +36,42 @@ use syntax::ast_util::{stmt_id};
|
||||
/**
|
||||
The region maps encode information about region relationships.
|
||||
|
||||
- `scope_map` maps from:
|
||||
- an expression to the expression or block encoding the maximum
|
||||
(static) lifetime of a value produced by that expression. This is
|
||||
generally the innermost call, statement, match, or block.
|
||||
- a variable or binding id to the block in which that variable is declared.
|
||||
- `free_region_map` maps from:
|
||||
- a free region `a` to a list of free regions `bs` such that
|
||||
`a <= b for all b in bs`
|
||||
- `scope_map` maps from a scope id to the enclosing scope id; this is
|
||||
usually corresponding to the lexical nesting, though in the case of
|
||||
closures the parent scope is the innermost conditinal expression or repeating
|
||||
block
|
||||
|
||||
- `var_map` maps from a variable or binding id to the block in which
|
||||
that variable is declared.
|
||||
|
||||
- `free_region_map` maps from a free region `a` to a list of free
|
||||
regions `bs` such that `a <= b for all b in bs`
|
||||
- the free region map is populated during type check as we check
|
||||
each function. See the function `relate_free_regions` for
|
||||
more information.
|
||||
- `temporary_scopes` includes scopes where cleanups for temporaries occur.
|
||||
These are statements and loop/fn bodies.
|
||||
|
||||
- `rvalue_scopes` includes entries for those expressions whose cleanup
|
||||
scope is larger than the default. The map goes from the expression
|
||||
id to the cleanup scope id. For rvalues not present in this table,
|
||||
the appropriate cleanup scope is the innermost enclosing statement,
|
||||
conditional expression, or repeating block (see `terminating_scopes`).
|
||||
|
||||
- `terminating_scopes` is a set containing the ids of each statement,
|
||||
or conditional/repeating expression. These scopes are calling "terminating
|
||||
scopes" because, when attempting to find the scope of a temporary, by
|
||||
default we search up the enclosing scopes until we encounter the
|
||||
terminating scope. A conditional/repeating
|
||||
expression is one which is not guaranteed to execute exactly once
|
||||
upon entering the parent scope. This could be because the expression
|
||||
only executes conditionally, such as the expression `b` in `a && b`,
|
||||
or because the expression may execute many times, such as a loop
|
||||
body. The reason that we distinguish such expressions is that, upon
|
||||
exiting the parent scope, we cannot statically know how many times
|
||||
the expression executed, and thus if the expression creates
|
||||
temporaries we cannot know statically how many such temporaries we
|
||||
would have to cleanup. Therefore we ensure that the temporaries never
|
||||
outlast the conditional/repeating expression, preventing the need
|
||||
for dynamic checks and/or arbitrary amounts of stack space.
|
||||
*/
|
||||
pub struct RegionMaps {
|
||||
priv scope_map: RefCell<HashMap<ast::NodeId, ast::NodeId>>,
|
||||
@ -840,7 +863,16 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
|
||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
||||
Context {parent: None, var_parent: None, ..cx}
|
||||
}
|
||||
visit::FkFnBlock(..) => cx
|
||||
visit::FkFnBlock(..) => {
|
||||
// FIXME(#3696) -- at present we are place the closure body
|
||||
// within the region hierarchy exactly where it appears lexically.
|
||||
// This is wrong because the closure may live longer
|
||||
// than the enclosing expression. We should probably fix this,
|
||||
// but the correct fix is a bit subtle, and I am also not sure
|
||||
// that the present approach is unsound -- it may not permit
|
||||
// any illegal programs. See issue for more details.
|
||||
cx
|
||||
}
|
||||
};
|
||||
visitor.visit_block(body, body_cx);
|
||||
}
|
||||
|
@ -2567,52 +2567,15 @@ impl Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
let merge_import_resolution = |name, name_bindings: @NameBindings| {
|
||||
let dest_import_resolution;
|
||||
let mut import_resolutions = module_.import_resolutions
|
||||
.borrow_mut();
|
||||
match import_resolutions.get().find(&name) {
|
||||
None => {
|
||||
// Create a new import resolution from this child.
|
||||
dest_import_resolution =
|
||||
@ImportResolution::new(id, is_public);
|
||||
import_resolutions.get().insert(name,
|
||||
dest_import_resolution);
|
||||
}
|
||||
Some(&existing_import_resolution) => {
|
||||
dest_import_resolution = existing_import_resolution;
|
||||
}
|
||||
}
|
||||
|
||||
debug!("(resolving glob import) writing resolution `{}` in `{}` \
|
||||
to `{}`",
|
||||
token::get_ident(name).get().to_str(),
|
||||
self.module_to_str(containing_module),
|
||||
self.module_to_str(module_));
|
||||
|
||||
// Merge the child item into the import resolution.
|
||||
if name_bindings.defined_in_public_namespace(ValueNS) {
|
||||
debug!("(resolving glob import) ... for value target");
|
||||
dest_import_resolution.value_target.set(
|
||||
Some(Target::new(containing_module, name_bindings)));
|
||||
dest_import_resolution.value_id.set(id);
|
||||
}
|
||||
if name_bindings.defined_in_public_namespace(TypeNS) {
|
||||
debug!("(resolving glob import) ... for type target");
|
||||
dest_import_resolution.type_target.set(
|
||||
Some(Target::new(containing_module, name_bindings)));
|
||||
dest_import_resolution.type_id.set(id);
|
||||
}
|
||||
dest_import_resolution.is_public.set(is_public);
|
||||
};
|
||||
|
||||
// Add all children from the containing module.
|
||||
self.populate_module_if_necessary(containing_module);
|
||||
|
||||
{
|
||||
let children = containing_module.children.borrow();
|
||||
for (&name, name_bindings) in children.get().iter() {
|
||||
merge_import_resolution(name, *name_bindings);
|
||||
self.merge_import_resolution(module_, containing_module,
|
||||
id, is_public,
|
||||
name, *name_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2623,7 +2586,9 @@ impl Resolver {
|
||||
for (&name, module) in external_module_children.get().iter() {
|
||||
let name_bindings =
|
||||
@Resolver::create_name_bindings_from_module(*module);
|
||||
merge_import_resolution(name, name_bindings);
|
||||
self.merge_import_resolution(module_, containing_module,
|
||||
id, is_public,
|
||||
name, name_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2641,6 +2606,50 @@ impl Resolver {
|
||||
return Success(());
|
||||
}
|
||||
|
||||
fn merge_import_resolution(&mut self,
|
||||
module_: @Module,
|
||||
containing_module: @Module,
|
||||
id: NodeId,
|
||||
is_public: bool,
|
||||
name: Name,
|
||||
name_bindings: @NameBindings) {
|
||||
let dest_import_resolution;
|
||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||
match import_resolutions.get().find(&name) {
|
||||
None => {
|
||||
// Create a new import resolution from this child.
|
||||
dest_import_resolution =
|
||||
@ImportResolution::new(id, is_public);
|
||||
import_resolutions.get().insert(name,
|
||||
dest_import_resolution);
|
||||
}
|
||||
Some(&existing_import_resolution) => {
|
||||
dest_import_resolution = existing_import_resolution;
|
||||
}
|
||||
}
|
||||
|
||||
debug!("(resolving glob import) writing resolution `{}` in `{}` \
|
||||
to `{}`",
|
||||
token::get_ident(name).get().to_str(),
|
||||
self.module_to_str(containing_module),
|
||||
self.module_to_str(module_));
|
||||
|
||||
// Merge the child item into the import resolution.
|
||||
if name_bindings.defined_in_public_namespace(ValueNS) {
|
||||
debug!("(resolving glob import) ... for value target");
|
||||
dest_import_resolution.value_target.set(
|
||||
Some(Target::new(containing_module, name_bindings)));
|
||||
dest_import_resolution.value_id.set(id);
|
||||
}
|
||||
if name_bindings.defined_in_public_namespace(TypeNS) {
|
||||
debug!("(resolving glob import) ... for type target");
|
||||
dest_import_resolution.type_target.set(
|
||||
Some(Target::new(containing_module, name_bindings)));
|
||||
dest_import_resolution.type_id.set(id);
|
||||
}
|
||||
dest_import_resolution.is_public.set(is_public);
|
||||
}
|
||||
|
||||
/// Resolves the given module path from the given root `module_`.
|
||||
fn resolve_module_path_from_root(&mut self,
|
||||
module_: @Module,
|
||||
|
@ -480,9 +480,9 @@ impl Datum<Expr> {
|
||||
* no cleanup scheduled).
|
||||
*/
|
||||
|
||||
let mut bcx = bcx;
|
||||
self.match_kind(
|
||||
|l| {
|
||||
let mut bcx = bcx;
|
||||
match l.appropriate_rvalue_mode(bcx.ccx()) {
|
||||
ByRef => {
|
||||
let scratch = rvalue_scratch_datum(bcx, l.ty, name);
|
||||
|
@ -45,6 +45,7 @@ use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::{ast, ast_map};
|
||||
use syntax::opt_vec::OptVec;
|
||||
use syntax::opt_vec;
|
||||
@ -350,6 +351,9 @@ pub struct ctxt_ {
|
||||
// is used for lazy resolution of traits.
|
||||
populated_external_traits: RefCell<HashSet<ast::DefId>>,
|
||||
|
||||
// Borrows
|
||||
upvar_borrow_map: RefCell<UpvarBorrowMap>,
|
||||
|
||||
// These two caches are used by const_eval when decoding external statics
|
||||
// and variants that are found.
|
||||
extern_const_statics: RefCell<HashMap<ast::DefId, Option<@ast::Expr>>>,
|
||||
@ -493,6 +497,120 @@ pub enum Region {
|
||||
ReEmpty,
|
||||
}
|
||||
|
||||
/**
|
||||
* Upvars do not get their own node-id. Instead, we use the pair of
|
||||
* the original var id (that is, the root variable that is referenced
|
||||
* by the upvar) and the id of the closure expression.
|
||||
*/
|
||||
#[deriving(Clone, Eq, IterBytes)]
|
||||
pub struct UpvarId {
|
||||
var_id: ast::NodeId,
|
||||
closure_expr_id: ast::NodeId,
|
||||
}
|
||||
|
||||
#[deriving(Clone, Eq, IterBytes)]
|
||||
pub enum BorrowKind {
|
||||
/// Data must be immutable and is aliasable.
|
||||
ImmBorrow,
|
||||
|
||||
/// Data must be immutable but not aliasable. This kind of borrow
|
||||
/// cannot currently be expressed by the user and is used only in
|
||||
/// implicit closure bindings. It is needed when you the closure
|
||||
/// is borrowing or mutating a mutable referent, e.g.:
|
||||
///
|
||||
/// let x: &mut int = ...;
|
||||
/// let y = || *x += 5;
|
||||
///
|
||||
/// If we were to try to translate this closure into a more explicit
|
||||
/// form, we'd encounter an error with the code as written:
|
||||
///
|
||||
/// struct Env { x: & &mut int }
|
||||
/// let x: &mut int = ...;
|
||||
/// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn
|
||||
/// fn fn_ptr(env: &mut Env) { **env.x += 5; }
|
||||
///
|
||||
/// This is then illegal because you cannot mutate a `&mut` found
|
||||
/// in an aliasable location. To solve, you'd have to translate with
|
||||
/// an `&mut` borrow:
|
||||
///
|
||||
/// struct Env { x: & &mut int }
|
||||
/// let x: &mut int = ...;
|
||||
/// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x
|
||||
/// fn fn_ptr(env: &mut Env) { **env.x += 5; }
|
||||
///
|
||||
/// Now the assignment to `**env.x` is legal, but creating a
|
||||
/// mutable pointer to `x` is not because `x` is not mutable. We
|
||||
/// could fix this by declaring `x` as `let mut x`. This is ok in
|
||||
/// user code, if awkward, but extra weird for closures, since the
|
||||
/// borrow is hidden.
|
||||
///
|
||||
/// So we introduce a "unique imm" borrow -- the referent is
|
||||
/// immutable, but not aliasable. This solves the problem. For
|
||||
/// simplicity, we don't give users the way to express this
|
||||
/// borrow, it's just used when translating closures.
|
||||
UniqueImmBorrow,
|
||||
|
||||
/// Data is mutable and not aliasable.
|
||||
MutBorrow
|
||||
}
|
||||
|
||||
/**
|
||||
* Information describing the borrowing of an upvar. This is computed
|
||||
* during `typeck`, specifically by `regionck`. The general idea is
|
||||
* that the compiler analyses treat closures like:
|
||||
*
|
||||
* let closure: &'e fn() = || {
|
||||
* x = 1; // upvar x is assigned to
|
||||
* use(y); // upvar y is read
|
||||
* foo(&z); // upvar z is borrowed immutably
|
||||
* };
|
||||
*
|
||||
* as if they were "desugared" to something loosely like:
|
||||
*
|
||||
* struct Vars<'x,'y,'z> { x: &'x mut int,
|
||||
* y: &'y const int,
|
||||
* z: &'z int }
|
||||
* let closure: &'e fn() = {
|
||||
* fn f(env: &Vars) {
|
||||
* *env.x = 1;
|
||||
* use(*env.y);
|
||||
* foo(env.z);
|
||||
* }
|
||||
* let env: &'e mut Vars<'x,'y,'z> = &mut Vars { x: &'x mut x,
|
||||
* y: &'y const y,
|
||||
* z: &'z z };
|
||||
* (env, f)
|
||||
* };
|
||||
*
|
||||
* This is basically what happens at runtime. The closure is basically
|
||||
* an existentially quantified version of the `(env, f)` pair.
|
||||
*
|
||||
* This data structure indicates the region and mutability of a single
|
||||
* one of the `x...z` borrows.
|
||||
*
|
||||
* It may not be obvious why each borrowed variable gets its own
|
||||
* lifetime (in the desugared version of the example, these are indicated
|
||||
* by the lifetime parameters `'x`, `'y`, and `'z` in the `Vars` definition).
|
||||
* Each such lifetime must encompass the lifetime `'e` of the closure itself,
|
||||
* but need not be identical to it. The reason that this makes sense:
|
||||
*
|
||||
* - Callers are only permitted to invoke the closure, and hence to
|
||||
* use the pointers, within the lifetime `'e`, so clearly `'e` must
|
||||
* be a sublifetime of `'x...'z`.
|
||||
* - The closure creator knows which upvars were borrowed by the closure
|
||||
* and thus `x...z` will be reserved for `'x...'z` respectively.
|
||||
* - Through mutation, the borrowed upvars can actually escape the
|
||||
* the closure, so sometimes it is necessary for them to be larger
|
||||
* than the closure lifetime itself.
|
||||
*/
|
||||
#[deriving(Eq, Clone)]
|
||||
pub struct UpvarBorrow {
|
||||
kind: BorrowKind,
|
||||
region: ty::Region,
|
||||
}
|
||||
|
||||
pub type UpvarBorrowMap = HashMap<UpvarId, UpvarBorrow>;
|
||||
|
||||
impl Region {
|
||||
pub fn is_bound(&self) -> bool {
|
||||
match self {
|
||||
@ -998,7 +1116,7 @@ pub fn mk_ctxt(s: session::Session,
|
||||
impl_vtables: RefCell::new(HashMap::new()),
|
||||
populated_external_types: RefCell::new(HashSet::new()),
|
||||
populated_external_traits: RefCell::new(HashSet::new()),
|
||||
|
||||
upvar_borrow_map: RefCell::new(HashMap::new()),
|
||||
extern_const_statics: RefCell::new(HashMap::new()),
|
||||
extern_const_variants: RefCell::new(HashMap::new()),
|
||||
}
|
||||
@ -2668,8 +2786,13 @@ pub fn node_id_to_trait_ref(cx: ctxt, id: ast::NodeId) -> @ty::TraitRef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_node_id_to_type(cx: ctxt, id: ast::NodeId) -> Option<t> {
|
||||
let node_types = cx.node_types.borrow();
|
||||
node_types.get().find_copy(&(id as uint))
|
||||
}
|
||||
|
||||
pub fn node_id_to_type(cx: ctxt, id: ast::NodeId) -> t {
|
||||
match node_id_to_type_opt(cx, id) {
|
||||
match try_node_id_to_type(cx, id) {
|
||||
Some(t) => t,
|
||||
None => cx.sess.bug(
|
||||
format!("node_id_to_type: no type for node `{}`",
|
||||
@ -2883,6 +3006,45 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
|
||||
adjust_ty(cx, expr.span, unadjusted_ty, adjustment)
|
||||
}
|
||||
|
||||
pub fn expr_span(cx: ctxt, id: NodeId) -> Span {
|
||||
match cx.items.find(id) {
|
||||
Some(ast_map::NodeExpr(e)) => {
|
||||
e.span
|
||||
}
|
||||
Some(f) => {
|
||||
cx.sess.bug(format!("Node id {} is not an expr: {:?}",
|
||||
id, f));
|
||||
}
|
||||
None => {
|
||||
cx.sess.bug(format!("Node id {} is not present \
|
||||
in the node map", id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local_var_name_str(cx: ctxt, id: NodeId) -> InternedString {
|
||||
match cx.items.find(id) {
|
||||
Some(ast_map::NodeLocal(pat)) => {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, ref path, _) => {
|
||||
let ident = ast_util::path_to_ident(path);
|
||||
token::get_ident(ident.name)
|
||||
}
|
||||
_ => {
|
||||
cx.sess.bug(
|
||||
format!("Variable id {} maps to {:?}, not local",
|
||||
id, pat));
|
||||
}
|
||||
}
|
||||
}
|
||||
r => {
|
||||
cx.sess.bug(
|
||||
format!("Variable id {} maps to {:?}, not local",
|
||||
id, r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_ty(cx: ctxt,
|
||||
span: Span,
|
||||
unadjusted_ty: ty::t,
|
||||
@ -5055,3 +5217,28 @@ impl substs {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorrowKind {
|
||||
pub fn from_mutbl(m: ast::Mutability) -> BorrowKind {
|
||||
match m {
|
||||
ast::MutMutable => MutBorrow,
|
||||
ast::MutImmutable => ImmBorrow,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_user_str(&self) -> &'static str {
|
||||
match *self {
|
||||
MutBorrow => "mutable",
|
||||
ImmBorrow => "immutable",
|
||||
UniqueImmBorrow => "uniquely immutable",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_short_str(&self) -> &'static str {
|
||||
match *self {
|
||||
MutBorrow => "mut",
|
||||
ImmBorrow => "imm",
|
||||
UniqueImmBorrow => "own",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,6 +164,7 @@ pub struct Inherited {
|
||||
adjustments: RefCell<HashMap<ast::NodeId, @ty::AutoAdjustment>>,
|
||||
method_map: method_map,
|
||||
vtable_map: vtable_map,
|
||||
upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
@ -266,6 +267,7 @@ impl Inherited {
|
||||
adjustments: RefCell::new(HashMap::new()),
|
||||
method_map: @RefCell::new(HashMap::new()),
|
||||
vtable_map: @RefCell::new(HashMap::new()),
|
||||
upvar_borrow_map: RefCell::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -378,10 +378,45 @@ impl Visitor<()> for WbCtxt {
|
||||
fn visit_ty(&mut self, _t: &ast::Ty, _: ()) {}
|
||||
}
|
||||
|
||||
fn resolve_upvar_borrow_map(wbcx: &mut WbCtxt) {
|
||||
if !wbcx.success {
|
||||
return;
|
||||
}
|
||||
|
||||
let fcx = wbcx.fcx;
|
||||
let tcx = fcx.tcx();
|
||||
let upvar_borrow_map = fcx.inh.upvar_borrow_map.borrow();
|
||||
for (upvar_id, upvar_borrow) in upvar_borrow_map.get().iter() {
|
||||
let r = upvar_borrow.region;
|
||||
match resolve_region(fcx.infcx(), r, resolve_all | force_all) {
|
||||
Ok(r) => {
|
||||
let new_upvar_borrow = ty::UpvarBorrow {
|
||||
kind: upvar_borrow.kind,
|
||||
region: r
|
||||
};
|
||||
debug!("Upvar borrow for {} resolved to {}",
|
||||
upvar_id.repr(tcx), new_upvar_borrow.repr(tcx));
|
||||
let mut tcx_upvar_borrow_map = tcx.upvar_borrow_map.borrow_mut();
|
||||
tcx_upvar_borrow_map.get().insert(*upvar_id, new_upvar_borrow);
|
||||
}
|
||||
Err(e) => {
|
||||
let span = ty::expr_span(tcx, upvar_id.closure_expr_id);
|
||||
fcx.ccx.tcx.sess.span_err(
|
||||
span, format!("cannot resolve lifetime for \
|
||||
captured variable `{}`: {}",
|
||||
ty::local_var_name_str(tcx, upvar_id.var_id).get().to_str(),
|
||||
infer::fixup_err_to_str(e)));
|
||||
wbcx.success = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_type_vars_in_expr(fcx: @FnCtxt, e: &ast::Expr) -> bool {
|
||||
let mut wbcx = WbCtxt { fcx: fcx, success: true };
|
||||
let wbcx = &mut wbcx;
|
||||
wbcx.visit_expr(e, ());
|
||||
resolve_upvar_borrow_map(wbcx);
|
||||
return wbcx.success;
|
||||
}
|
||||
|
||||
@ -397,5 +432,6 @@ pub fn resolve_type_vars_in_fn(fcx: @FnCtxt, decl: &ast::FnDecl,
|
||||
resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id);
|
||||
}
|
||||
}
|
||||
resolve_upvar_borrow_map(wbcx);
|
||||
return wbcx.success;
|
||||
}
|
||||
|
@ -237,6 +237,24 @@ impl ErrorReporting for InferCtxt {
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
format!("lifetime of borrowed pointer outlives \
|
||||
lifetime of captured variable `{}`...",
|
||||
ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_str()));
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"...the borrowed pointer is valid for ",
|
||||
sub,
|
||||
"...");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
format!("...but `{}` is only valid for ",
|
||||
ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_str()),
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::InfStackClosure(span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
@ -272,10 +290,12 @@ impl ErrorReporting for InferCtxt {
|
||||
sup,
|
||||
"");
|
||||
}
|
||||
infer::FreeVariable(span) => {
|
||||
infer::FreeVariable(span, id) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
"captured variable does not outlive the enclosing closure");
|
||||
format!("captured variable `{}` does not \
|
||||
outlive the enclosing closure",
|
||||
ty::local_var_name_str(self.tcx, id).get().to_str()));
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"captured variable is valid for ",
|
||||
@ -473,6 +493,10 @@ impl ErrorReportingHelpers for InferCtxt {
|
||||
infer::BoundRegionInCoherence(..) => {
|
||||
format!(" for coherence check")
|
||||
}
|
||||
infer::UpvarRegion(ref upvar_id, _) => {
|
||||
format!(" for capture of `{}` by closure",
|
||||
ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_str())
|
||||
}
|
||||
};
|
||||
|
||||
self.tcx.sess.span_err(
|
||||
@ -533,6 +557,12 @@ impl ErrorReportingHelpers for InferCtxt {
|
||||
"...so that reference does not outlive \
|
||||
borrowed content");
|
||||
}
|
||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
format!("...so that closure can access `{}`",
|
||||
ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_str()))
|
||||
}
|
||||
infer::InfStackClosure(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
@ -549,11 +579,12 @@ impl ErrorReportingHelpers for InferCtxt {
|
||||
"...so that pointer is not dereferenced \
|
||||
outside its lifetime");
|
||||
}
|
||||
infer::FreeVariable(span) => {
|
||||
infer::FreeVariable(span, id) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that captured variable does not outlive the \
|
||||
enclosing closure");
|
||||
format!("...so that captured variable `{}` \
|
||||
does not outlive the enclosing closure",
|
||||
ty::local_var_name_str(self.tcx, id).get().to_str()));
|
||||
}
|
||||
infer::IndexSlice(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
|
@ -160,7 +160,7 @@ pub enum SubregionOrigin {
|
||||
DerefPointer(Span),
|
||||
|
||||
// Closure bound must not outlive captured free variables
|
||||
FreeVariable(Span),
|
||||
FreeVariable(Span, ast::NodeId),
|
||||
|
||||
// Index into slice must be within its lifetime
|
||||
IndexSlice(Span),
|
||||
@ -172,6 +172,9 @@ pub enum SubregionOrigin {
|
||||
// Creating a pointer `b` to contents of another reference
|
||||
Reborrow(Span),
|
||||
|
||||
// Creating a pointer `b` to contents of an upvar
|
||||
ReborrowUpvar(Span, ty::UpvarId),
|
||||
|
||||
// (&'a &'b T) where a >= b
|
||||
ReferenceOutlivesReferent(ty::t, Span),
|
||||
|
||||
@ -225,6 +228,8 @@ pub enum RegionVariableOrigin {
|
||||
// when doing subtyping/lub/glb computations
|
||||
BoundRegionInFnType(Span, ty::BoundRegion),
|
||||
|
||||
UpvarRegion(ty::UpvarId, Span),
|
||||
|
||||
BoundRegionInTypeOrImpl(Span),
|
||||
|
||||
BoundRegionInCoherence,
|
||||
@ -876,10 +881,11 @@ impl SubregionOrigin {
|
||||
InfStackClosure(a) => a,
|
||||
InvokeClosure(a) => a,
|
||||
DerefPointer(a) => a,
|
||||
FreeVariable(a) => a,
|
||||
FreeVariable(a, _) => a,
|
||||
IndexSlice(a) => a,
|
||||
RelateObjectBound(a) => a,
|
||||
Reborrow(a) => a,
|
||||
ReborrowUpvar(a, _) => a,
|
||||
ReferenceOutlivesReferent(_, a) => a,
|
||||
BindingTypeIsNotValidAtDecl(a) => a,
|
||||
CallRcvr(a) => a,
|
||||
@ -898,10 +904,11 @@ impl Repr for SubregionOrigin {
|
||||
InfStackClosure(a) => format!("InfStackClosure({})", a.repr(tcx)),
|
||||
InvokeClosure(a) => format!("InvokeClosure({})", a.repr(tcx)),
|
||||
DerefPointer(a) => format!("DerefPointer({})", a.repr(tcx)),
|
||||
FreeVariable(a) => format!("FreeVariable({})", a.repr(tcx)),
|
||||
FreeVariable(a, b) => format!("FreeVariable({}, {})", a.repr(tcx), b),
|
||||
IndexSlice(a) => format!("IndexSlice({})", a.repr(tcx)),
|
||||
RelateObjectBound(a) => format!("RelateObjectBound({})", a.repr(tcx)),
|
||||
Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
|
||||
ReborrowUpvar(a, b) => format!("ReborrowUpvar({},{:?})", a.repr(tcx), b),
|
||||
ReferenceOutlivesReferent(_, a) =>
|
||||
format!("ReferenceOutlivesReferent({})", a.repr(tcx)),
|
||||
BindingTypeIsNotValidAtDecl(a) =>
|
||||
@ -928,6 +935,7 @@ impl RegionVariableOrigin {
|
||||
BoundRegionInFnType(a, _) => a,
|
||||
BoundRegionInTypeOrImpl(a) => a,
|
||||
BoundRegionInCoherence => codemap::DUMMY_SP,
|
||||
UpvarRegion(_, a) => a
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -948,6 +956,9 @@ impl Repr for RegionVariableOrigin {
|
||||
BoundRegionInTypeOrImpl(a) => format!("bound_regionInTypeOrImpl({})",
|
||||
a.repr(tcx)),
|
||||
BoundRegionInCoherence => format!("bound_regionInCoherence"),
|
||||
UpvarRegion(a, b) => format!("UpvarRegion({}, {})",
|
||||
a.repr(tcx),
|
||||
b.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +270,11 @@ impl RegionVarBindings {
|
||||
// cannot add constraints once regions are resolved
|
||||
assert!(self.values_are_none());
|
||||
|
||||
debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup);
|
||||
debug!("RegionVarBindings: make_subregion({}, {}) due to {}",
|
||||
sub.repr(self.tcx),
|
||||
sup.repr(self.tcx),
|
||||
origin.repr(self.tcx));
|
||||
|
||||
match (sub, sup) {
|
||||
(ReEarlyBound(..), _) |
|
||||
(ReLateBound(..), _) |
|
||||
|
@ -565,11 +565,26 @@ impl<T:Repr> Repr for Option<T> {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
match self {
|
||||
&None => ~"None",
|
||||
&Some(ref t) => format!("Some({})", t.repr(tcx))
|
||||
&Some(ref t) => t.repr(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Repr,U:Repr> Repr for Result<T,U> {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
match self {
|
||||
&Ok(ref t) => t.repr(tcx),
|
||||
&Err(ref u) => format!("Err({})", u.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for () {
|
||||
fn repr(&self, _tcx: ctxt) -> ~str {
|
||||
~"()"
|
||||
}
|
||||
}
|
||||
|
||||
impl<T:Repr> Repr for @T {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
(&**self).repr(tcx)
|
||||
@ -1021,3 +1036,32 @@ impl UserString for AbiSet {
|
||||
self.to_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::UpvarId {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
format!("UpvarId({};`{}`;{})",
|
||||
self.var_id,
|
||||
ty::local_var_name_str(tcx, self.var_id),
|
||||
self.closure_expr_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ast::Mutability {
|
||||
fn repr(&self, _tcx: ctxt) -> ~str {
|
||||
format!("{:?}", *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::BorrowKind {
|
||||
fn repr(&self, _tcx: ctxt) -> ~str {
|
||||
format!("{:?}", *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for ty::UpvarBorrow {
|
||||
fn repr(&self, tcx: ctxt) -> ~str {
|
||||
format!("UpvarBorrow({}, {})",
|
||||
self.kind.repr(tcx),
|
||||
self.region.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +453,8 @@ impl Engine256 {
|
||||
assert!(!self.finished)
|
||||
// Assumes that input.len() can be converted to u64 without overflow
|
||||
self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64);
|
||||
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
|
||||
let self_state = &mut self.state;
|
||||
self.buffer.input(input, |input: &[u8]| { self_state.process_block(input) });
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
@ -461,10 +462,11 @@ impl Engine256 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.buffer.standard_padding(8, |input: &[u8]| { self.state.process_block(input) });
|
||||
let self_state = &mut self.state;
|
||||
self.buffer.standard_padding(8, |input: &[u8]| { self_state.process_block(input) });
|
||||
write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 );
|
||||
write_u32_be(self.buffer.next(4), self.length_bits as u32);
|
||||
self.state.process_block(self.buffer.full_buffer());
|
||||
self_state.process_block(self.buffer.full_buffer());
|
||||
|
||||
self.finished = true;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ pub trait DocFolder {
|
||||
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
|
||||
let Item { attrs, name, source, visibility, id, inner } = item;
|
||||
let inner = inner;
|
||||
let c = |x| self.fold_item(x);
|
||||
let inner = match inner {
|
||||
StructItem(mut i) => {
|
||||
let mut foo = ~[]; swap(&mut foo, &mut i.fields);
|
||||
@ -72,6 +71,7 @@ pub trait DocFolder {
|
||||
StructVariant(mut j) => {
|
||||
let mut foo = ~[]; swap(&mut foo, &mut j.fields);
|
||||
let num_fields = foo.len();
|
||||
let c = |x| self.fold_item(x);
|
||||
j.fields.extend(&mut foo.move_iter().filter_map(c));
|
||||
j.fields_stripped |= num_fields != j.fields.len();
|
||||
VariantItem(Variant {kind: StructVariant(j), ..i2})
|
||||
|
@ -510,8 +510,9 @@ impl rtio::RtioUdpSocket for UdpWatcher {
|
||||
buf: Some(slice_to_uv_buf(buf)),
|
||||
result: None,
|
||||
};
|
||||
let handle = self.handle;
|
||||
wait_until_woken_after(&mut cx.task, || {
|
||||
unsafe { uvll::set_data_for_uv_handle(self.handle, &cx) }
|
||||
unsafe { uvll::set_data_for_uv_handle(handle, &cx) }
|
||||
});
|
||||
match cx.result.take_unwrap() {
|
||||
(n, _) if n < 0 =>
|
||||
|
@ -277,7 +277,7 @@ use str::{StrSlice, OwnedStr};
|
||||
use str;
|
||||
use to_str::ToStr;
|
||||
use uint;
|
||||
use unstable::finally::Finally;
|
||||
use unstable::finally::try_finally;
|
||||
use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCloneableVector};
|
||||
use vec;
|
||||
|
||||
@ -473,25 +473,33 @@ pub trait Reader {
|
||||
/// pushed on to the vector, otherwise the amount `len` bytes couldn't be
|
||||
/// read (an error was encountered), and the error is returned.
|
||||
fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> {
|
||||
struct State<'a> {
|
||||
buf: &'a mut ~[u8],
|
||||
total_read: uint
|
||||
}
|
||||
|
||||
let start_len = buf.len();
|
||||
let mut total_read = 0;
|
||||
let mut s = State { buf: buf, total_read: 0 };
|
||||
|
||||
buf.reserve_additional(len);
|
||||
unsafe { buf.set_len(start_len + len); }
|
||||
s.buf.reserve_additional(len);
|
||||
unsafe { s.buf.set_len(start_len + len); }
|
||||
|
||||
(|| {
|
||||
while total_read < len {
|
||||
let len = buf.len();
|
||||
let slice = buf.mut_slice(start_len + total_read, len);
|
||||
match self.read(slice) {
|
||||
Ok(nread) => {
|
||||
total_read += nread;
|
||||
try_finally(
|
||||
&mut s, (),
|
||||
|s, _| {
|
||||
while s.total_read < len {
|
||||
let len = s.buf.len();
|
||||
let slice = s.buf.mut_slice(start_len + s.total_read, len);
|
||||
match self.read(slice) {
|
||||
Ok(nread) => {
|
||||
s.total_read += nread;
|
||||
}
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}).finally(|| unsafe { buf.set_len(start_len + total_read) })
|
||||
Ok(())
|
||||
},
|
||||
|s| unsafe { s.buf.set_len(start_len + s.total_read) })
|
||||
}
|
||||
|
||||
/// Reads `len` bytes and gives you back a new vector of length `len`
|
||||
|
@ -83,7 +83,8 @@ impl Reader for UdpStream {
|
||||
|
||||
impl Writer for UdpStream {
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
|
||||
self.as_socket(|sock| sock.sendto(buf, self.connectedTo))
|
||||
let connectedTo = self.connectedTo;
|
||||
self.as_socket(|sock| sock.sendto(buf, connectedTo))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,15 +625,17 @@ impl<'a> Iterator<char> for Normalizations<'a> {
|
||||
|
||||
if !self.sorted {
|
||||
for ch in self.iter {
|
||||
let buffer = &mut self.buffer;
|
||||
let sorted = &mut self.sorted;
|
||||
decomposer(ch, |d| {
|
||||
let class = canonical_combining_class(d);
|
||||
if class == 0 && !self.sorted {
|
||||
canonical_sort(self.buffer);
|
||||
self.sorted = true;
|
||||
if class == 0 && !*sorted {
|
||||
canonical_sort(*buffer);
|
||||
*sorted = true;
|
||||
}
|
||||
self.buffer.push((d, class));
|
||||
buffer.push((d, class));
|
||||
});
|
||||
if self.sorted { break }
|
||||
if *sorted { break }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,11 @@
|
||||
The Finally trait provides a method, `finally` on
|
||||
stack closures that emulates Java-style try/finally blocks.
|
||||
|
||||
Using the `finally` method is sometimes convenient, but the type rules
|
||||
prohibit any shared, mutable state between the "try" case and the
|
||||
"finally" case. For advanced cases, the `try_finally` function can
|
||||
also be used. See that function for more details.
|
||||
|
||||
# Example
|
||||
|
||||
```
|
||||
@ -31,53 +36,89 @@ pub trait Finally<T> {
|
||||
fn finally(&self, dtor: ||) -> T;
|
||||
}
|
||||
|
||||
macro_rules! finally_fn {
|
||||
($fnty:ty) => {
|
||||
impl<T> Finally<T> for $fnty {
|
||||
fn finally(&self, dtor: ||) -> T {
|
||||
let _d = Finallyalizer {
|
||||
dtor: dtor
|
||||
};
|
||||
(*self)()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,T> Finally<T> for 'a || -> T {
|
||||
fn finally(&self, dtor: ||) -> T {
|
||||
let _d = Finallyalizer {
|
||||
dtor: dtor
|
||||
};
|
||||
|
||||
(*self)()
|
||||
try_finally(&mut (), (),
|
||||
|_, _| (*self)(),
|
||||
|_| dtor())
|
||||
}
|
||||
}
|
||||
|
||||
finally_fn!(extern "Rust" fn() -> T)
|
||||
impl<T> Finally<T> for fn() -> T {
|
||||
fn finally(&self, dtor: ||) -> T {
|
||||
try_finally(&mut (), (),
|
||||
|_, _| (*self)(),
|
||||
|_| dtor())
|
||||
}
|
||||
}
|
||||
|
||||
struct Finallyalizer<'a> {
|
||||
dtor: 'a ||
|
||||
/**
|
||||
* The most general form of the `finally` functions. The function
|
||||
* `try_fn` will be invoked first; whether or not it fails, the
|
||||
* function `finally_fn` will be invoked next. The two parameters
|
||||
* `mutate` and `drop` are used to thread state through the two
|
||||
* closures. `mutate` is used for any shared, mutable state that both
|
||||
* closures require access to; `drop` is used for any state that the
|
||||
* `try_fn` requires ownership of.
|
||||
*
|
||||
* **WARNING:** While shared, mutable state between the try and finally
|
||||
* function is often necessary, one must be very careful; the `try`
|
||||
* function could have failed at any point, so the values of the shared
|
||||
* state may be inconsistent.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ```
|
||||
* struct State<'a> { buffer: &'a mut [u8], len: uint }
|
||||
* let mut state = State { buffer: buf, len: 0 };
|
||||
* try_finally(
|
||||
* &mut state, (),
|
||||
* |state, ()| {
|
||||
* // use state.buffer, state.len
|
||||
* }
|
||||
* |state| {
|
||||
* // use state.buffer, state.len to cleanup
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
pub fn try_finally<T,U,R>(mutate: &mut T,
|
||||
drop: U,
|
||||
try_fn: |&mut T, U| -> R,
|
||||
finally_fn: |&mut T|)
|
||||
-> R {
|
||||
let f = Finallyalizer {
|
||||
mutate: mutate,
|
||||
dtor: finally_fn,
|
||||
};
|
||||
try_fn(&mut *f.mutate, drop)
|
||||
}
|
||||
|
||||
struct Finallyalizer<'a,A> {
|
||||
mutate: &'a mut A,
|
||||
dtor: 'a |&mut A|
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'a> Drop for Finallyalizer<'a> {
|
||||
impl<'a,A> Drop for Finallyalizer<'a,A> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
(self.dtor)();
|
||||
(self.dtor)(self.mutate);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_success() {
|
||||
let mut i = 0;
|
||||
(|| {
|
||||
i = 10;
|
||||
}).finally(|| {
|
||||
assert!(!failing());
|
||||
assert_eq!(i, 10);
|
||||
i = 20;
|
||||
});
|
||||
try_finally(
|
||||
&mut i, (),
|
||||
|i, ()| {
|
||||
*i = 10;
|
||||
},
|
||||
|i| {
|
||||
assert!(!failing());
|
||||
assert_eq!(*i, 10);
|
||||
*i = 20;
|
||||
});
|
||||
assert_eq!(i, 20);
|
||||
}
|
||||
|
||||
@ -85,13 +126,16 @@ fn test_success() {
|
||||
#[should_fail]
|
||||
fn test_fail() {
|
||||
let mut i = 0;
|
||||
(|| {
|
||||
i = 10;
|
||||
fail!();
|
||||
}).finally(|| {
|
||||
assert!(failing());
|
||||
assert_eq!(i, 10);
|
||||
})
|
||||
try_finally(
|
||||
&mut i, (),
|
||||
|i, ()| {
|
||||
*i = 10;
|
||||
fail!();
|
||||
},
|
||||
|i| {
|
||||
assert!(failing());
|
||||
assert_eq!(*i, 10);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -119,7 +119,7 @@ use mem;
|
||||
use mem::size_of;
|
||||
use kinds::marker;
|
||||
use uint;
|
||||
use unstable::finally::Finally;
|
||||
use unstable::finally::try_finally;
|
||||
use unstable::raw::{Repr, Slice, Vec};
|
||||
|
||||
/**
|
||||
@ -132,15 +132,16 @@ pub fn from_fn<T>(n_elts: uint, op: |uint| -> T) -> ~[T] {
|
||||
unsafe {
|
||||
let mut v = with_capacity(n_elts);
|
||||
let p = v.as_mut_ptr();
|
||||
let mut i: uint = 0u;
|
||||
(|| {
|
||||
while i < n_elts {
|
||||
mem::move_val_init(&mut(*ptr::mut_offset(p, i as int)), op(i));
|
||||
i += 1u;
|
||||
}
|
||||
}).finally(|| {
|
||||
v.set_len(i);
|
||||
});
|
||||
let mut i = 0;
|
||||
try_finally(
|
||||
&mut i, (),
|
||||
|i, ()| while *i < n_elts {
|
||||
mem::move_val_init(
|
||||
&mut(*ptr::mut_offset(p, *i as int)),
|
||||
op(*i));
|
||||
*i += 1u;
|
||||
},
|
||||
|i| v.set_len(*i));
|
||||
v
|
||||
}
|
||||
}
|
||||
@ -160,14 +161,15 @@ pub fn from_elem<T:Clone>(n_elts: uint, t: T) -> ~[T] {
|
||||
let mut v = with_capacity(n_elts);
|
||||
let p = v.as_mut_ptr();
|
||||
let mut i = 0u;
|
||||
(|| {
|
||||
while i < n_elts {
|
||||
mem::move_val_init(&mut(*ptr::mut_offset(p, i as int)), t.clone());
|
||||
i += 1u;
|
||||
}
|
||||
}).finally(|| {
|
||||
v.set_len(i);
|
||||
});
|
||||
try_finally(
|
||||
&mut i, (),
|
||||
|i, ()| while *i < n_elts {
|
||||
mem::move_val_init(
|
||||
&mut(*ptr::mut_offset(p, *i as int)),
|
||||
t.clone());
|
||||
*i += 1u;
|
||||
},
|
||||
|i| v.set_len(*i));
|
||||
v
|
||||
}
|
||||
}
|
||||
@ -294,7 +296,8 @@ impl<'a, T> Iterator<&'a [T]> for RevSplits<'a, T> {
|
||||
return Some(self.v);
|
||||
}
|
||||
|
||||
match self.v.iter().rposition(|x| (self.pred)(x)) {
|
||||
let pred = &mut self.pred;
|
||||
match self.v.iter().rposition(|x| (*pred)(x)) {
|
||||
None => {
|
||||
self.finished = true;
|
||||
Some(self.v)
|
||||
|
@ -580,10 +580,12 @@ impl<'a> MethodDef<'a> {
|
||||
ast::SelfStatic => None,
|
||||
_ => Some(ast::Arg::new_self(trait_.span, ast::MutImmutable))
|
||||
};
|
||||
let args = arg_types.move_iter().map(|(name, ty)| {
|
||||
cx.arg(trait_.span, name, ty)
|
||||
});
|
||||
let args = self_arg.move_iter().chain(args).collect();
|
||||
let args = {
|
||||
let args = arg_types.move_iter().map(|(name, ty)| {
|
||||
cx.arg(trait_.span, name, ty)
|
||||
});
|
||||
self_arg.move_iter().chain(args).collect()
|
||||
};
|
||||
|
||||
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
|
||||
|
||||
|
@ -60,7 +60,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
|
||||
cx.ident_of("Rand"),
|
||||
cx.ident_of("rand")
|
||||
];
|
||||
let rand_call = |span| {
|
||||
let rand_call = |cx: &mut ExtCtxt, span| {
|
||||
cx.expr_call_global(span,
|
||||
rand_ident.clone(),
|
||||
~[ rng[0] ])
|
||||
@ -111,7 +111,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
|
||||
let i_expr = cx.expr_uint(v_span, i);
|
||||
let pat = cx.pat_lit(v_span, i_expr);
|
||||
|
||||
let thing = rand_thing(cx, v_span, ident, summary, |sp| rand_call(sp));
|
||||
let thing = rand_thing(cx, v_span, ident, summary, |cx, sp| rand_call(cx, sp));
|
||||
cx.arm(v_span, ~[ pat ], thing)
|
||||
}).collect::<~[ast::Arm]>();
|
||||
|
||||
@ -130,20 +130,21 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
|
||||
trait_span: Span,
|
||||
ctor_ident: Ident,
|
||||
summary: &StaticFields,
|
||||
rand_call: |Span| -> @Expr)
|
||||
rand_call: |&mut ExtCtxt, Span| -> @Expr)
|
||||
-> @Expr {
|
||||
match *summary {
|
||||
Unnamed(ref fields) => {
|
||||
if fields.is_empty() {
|
||||
cx.expr_ident(trait_span, ctor_ident)
|
||||
} else {
|
||||
let exprs = fields.map(|span| rand_call(*span));
|
||||
let exprs = fields.map(|span| rand_call(cx, *span));
|
||||
cx.expr_call_ident(trait_span, ctor_ident, exprs)
|
||||
}
|
||||
}
|
||||
Named(ref fields) => {
|
||||
let rand_fields = fields.map(|&(ident, span)| {
|
||||
cx.field_imm(span, ident, rand_call(span))
|
||||
let e = rand_call(cx, span);
|
||||
cx.field_imm(span, ident, e)
|
||||
});
|
||||
cx.expr_struct_ident(trait_span, ctor_ident, rand_fields)
|
||||
}
|
||||
|
@ -67,31 +67,32 @@ fn to_str_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure)
|
||||
let mut stmts = ~[cx.stmt_let(span, true, buf, init)];
|
||||
let push_str = cx.ident_of("push_str");
|
||||
|
||||
let push = |s: @Expr| {
|
||||
let ebuf = cx.expr_ident(span, buf);
|
||||
let call = cx.expr_method_call(span, ebuf, push_str, ~[s]);
|
||||
stmts.push(cx.stmt_expr(call));
|
||||
};
|
||||
{
|
||||
let push = |s: @Expr| {
|
||||
let ebuf = cx.expr_ident(span, buf);
|
||||
let call = cx.expr_method_call(span, ebuf, push_str, ~[s]);
|
||||
stmts.push(cx.stmt_expr(call));
|
||||
};
|
||||
|
||||
for (i, &FieldInfo {name, span, self_, .. }) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
push(cx.expr_str(span, InternedString::new(", ")));
|
||||
}
|
||||
match name {
|
||||
None => {}
|
||||
Some(id) => {
|
||||
let interned_id = token::get_ident(id.name);
|
||||
let name = interned_id.get() + ": ";
|
||||
push(cx.expr_str(span,
|
||||
token::intern_and_get_ident(name)));
|
||||
for (i, &FieldInfo {name, span, self_, .. }) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
push(cx.expr_str(span, InternedString::new(", ")));
|
||||
}
|
||||
match name {
|
||||
None => {}
|
||||
Some(id) => {
|
||||
let interned_id = token::get_ident(id.name);
|
||||
let name = interned_id.get() + ": ";
|
||||
push(cx.expr_str(span,
|
||||
token::intern_and_get_ident(name)));
|
||||
}
|
||||
}
|
||||
push(cx.expr_method_call(span, self_, to_str, ~[]));
|
||||
}
|
||||
push(cx.expr_method_call(span, self_, to_str, ~[]));
|
||||
push(cx.expr_str(span, end));
|
||||
}
|
||||
push(cx.expr_str(span, end));
|
||||
|
||||
cx.expr_block(cx.block(span, stmts, Some(cx.expr_ident(span,
|
||||
buf))))
|
||||
cx.expr_block(cx.block(span, stmts, Some(cx.expr_ident(span, buf))))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -709,14 +709,15 @@ pub fn expand_block(blk: &Block, fld: &mut MacroExpander) -> P<Block> {
|
||||
// expand the elements of a block.
|
||||
pub fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P<Block> {
|
||||
let new_view_items = b.view_items.map(|x| fld.fold_view_item(x));
|
||||
let new_stmts = b.stmts.iter()
|
||||
.map(|x| {
|
||||
let new_stmts =
|
||||
b.stmts.iter().flat_map(|x| {
|
||||
let renamed_stmt = {
|
||||
let pending_renames = &mut fld.extsbox.info().pending_renames;
|
||||
let mut rename_fld = renames_to_fold(pending_renames);
|
||||
rename_fld.fold_stmt(*x).expect_one("rename_fold didn't return one value")
|
||||
})
|
||||
.flat_map(|x| fld.fold_stmt(x).move_iter())
|
||||
.collect();
|
||||
};
|
||||
fld.fold_stmt(renamed_stmt).move_iter()
|
||||
}).collect();
|
||||
let new_expr = b.expr.map(|x| {
|
||||
let expr = {
|
||||
let pending_renames = &mut fld.extsbox.info().pending_renames;
|
||||
|
@ -367,157 +367,167 @@ impl<'a> Context<'a> {
|
||||
return ~[unnamed, allow_dead_code];
|
||||
}
|
||||
|
||||
/// Translate a `parse::Piece` to a static `rt::Piece`
|
||||
fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
|
||||
let sp = self.fmtsp;
|
||||
let parsepath = |s: &str| {
|
||||
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
|
||||
self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
|
||||
};
|
||||
let rtpath = |s: &str| {
|
||||
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
|
||||
self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
|
||||
};
|
||||
let ctpath = |s: &str| {
|
||||
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
|
||||
self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
|
||||
};
|
||||
let none = self.ecx.path_global(sp, ~[
|
||||
fn parsepath(&self, s: &str) -> ~[ast::Ident] {
|
||||
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
|
||||
self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
|
||||
}
|
||||
|
||||
fn rtpath(&self, s: &str) -> ~[ast::Ident] {
|
||||
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
|
||||
self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
|
||||
}
|
||||
|
||||
fn ctpath(&self, s: &str) -> ~[ast::Ident] {
|
||||
~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
|
||||
self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
|
||||
}
|
||||
|
||||
fn none(&self) -> @ast::Expr {
|
||||
let none = self.ecx.path_global(self.fmtsp, ~[
|
||||
self.ecx.ident_of("std"),
|
||||
self.ecx.ident_of("option"),
|
||||
self.ecx.ident_of("None")]);
|
||||
let none = self.ecx.expr_path(none);
|
||||
let some = |e: @ast::Expr| {
|
||||
let p = self.ecx.path_global(sp, ~[
|
||||
self.ecx.expr_path(none)
|
||||
}
|
||||
|
||||
fn some(&self, e: @ast::Expr) -> @ast::Expr {
|
||||
let p = self.ecx.path_global(self.fmtsp, ~[
|
||||
self.ecx.ident_of("std"),
|
||||
self.ecx.ident_of("option"),
|
||||
self.ecx.ident_of("Some")]);
|
||||
let p = self.ecx.expr_path(p);
|
||||
self.ecx.expr_call(sp, p, ~[e])
|
||||
};
|
||||
let trans_count = |c: parse::Count| {
|
||||
match c {
|
||||
parse::CountIs(i) => {
|
||||
self.ecx.expr_call_global(sp, rtpath("CountIs"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
parse::CountIsParam(i) => {
|
||||
self.ecx.expr_call_global(sp, rtpath("CountIsParam"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
parse::CountImplied => {
|
||||
let path = self.ecx.path_global(sp, rtpath("CountImplied"));
|
||||
self.ecx.expr_path(path)
|
||||
}
|
||||
parse::CountIsNextParam => {
|
||||
let path = self.ecx.path_global(sp, rtpath("CountIsNextParam"));
|
||||
self.ecx.expr_path(path)
|
||||
}
|
||||
parse::CountIsName(n) => {
|
||||
let i = match self.name_positions.find_equiv(&n) {
|
||||
Some(&i) => i,
|
||||
None => 0, // error already emitted elsewhere
|
||||
};
|
||||
let i = i + self.args.len();
|
||||
self.ecx.expr_call_global(sp, rtpath("CountIsParam"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
let p = self.ecx.expr_path(p);
|
||||
self.ecx.expr_call(self.fmtsp, p, ~[e])
|
||||
}
|
||||
|
||||
fn trans_count(&self, c: parse::Count) -> @ast::Expr {
|
||||
let sp = self.fmtsp;
|
||||
match c {
|
||||
parse::CountIs(i) => {
|
||||
self.ecx.expr_call_global(sp, self.rtpath("CountIs"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
};
|
||||
let trans_method = |method: &parse::Method| {
|
||||
let method = match *method {
|
||||
parse::Select(ref arms, ref default) => {
|
||||
let arms = arms.iter().map(|arm| {
|
||||
let p = self.ecx.path_global(sp, rtpath("SelectArm"));
|
||||
parse::CountIsParam(i) => {
|
||||
self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
parse::CountImplied => {
|
||||
let path = self.ecx.path_global(sp, self.rtpath("CountImplied"));
|
||||
self.ecx.expr_path(path)
|
||||
}
|
||||
parse::CountIsNextParam => {
|
||||
let path = self.ecx.path_global(sp, self.rtpath("CountIsNextParam"));
|
||||
self.ecx.expr_path(path)
|
||||
}
|
||||
parse::CountIsName(n) => {
|
||||
let i = match self.name_positions.find_equiv(&n) {
|
||||
Some(&i) => i,
|
||||
None => 0, // error already emitted elsewhere
|
||||
};
|
||||
let i = i + self.args.len();
|
||||
self.ecx.expr_call_global(sp, self.rtpath("CountIsParam"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_method(&mut self, method: &parse::Method) -> @ast::Expr {
|
||||
let sp = self.fmtsp;
|
||||
let method = match *method {
|
||||
parse::Select(ref arms, ref default) => {
|
||||
let arms = arms.iter().map(|arm| {
|
||||
let p = self.ecx.path_global(sp, self.rtpath("SelectArm"));
|
||||
let result = arm.result.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
let s = token::intern_and_get_ident(arm.selector);
|
||||
let selector = self.ecx.expr_str(sp, s);
|
||||
self.ecx.expr_struct(sp, p, ~[
|
||||
self.ecx.field_imm(sp,
|
||||
self.ecx.ident_of("selector"),
|
||||
selector),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("result"),
|
||||
self.ecx.expr_vec_slice(sp, result)),
|
||||
])
|
||||
self.ecx.field_imm(sp,
|
||||
self.ecx.ident_of("selector"),
|
||||
selector),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("result"),
|
||||
self.ecx.expr_vec_slice(sp, result)),
|
||||
])
|
||||
}).collect();
|
||||
let default = default.iter().map(|p| {
|
||||
let default = default.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
self.ecx.expr_call_global(sp, rtpath("Select"), ~[
|
||||
self.ecx.expr_call_global(sp, self.rtpath("Select"), ~[
|
||||
self.ecx.expr_vec_slice(sp, arms),
|
||||
self.ecx.expr_vec_slice(sp, default),
|
||||
])
|
||||
}
|
||||
parse::Plural(offset, ref arms, ref default) => {
|
||||
let offset = match offset {
|
||||
Some(i) => { some(self.ecx.expr_uint(sp, i)) }
|
||||
None => { none.clone() }
|
||||
};
|
||||
let arms = arms.iter().map(|arm| {
|
||||
let p = self.ecx.path_global(sp, rtpath("PluralArm"));
|
||||
])
|
||||
}
|
||||
parse::Plural(offset, ref arms, ref default) => {
|
||||
let offset = match offset {
|
||||
Some(i) => { self.some(self.ecx.expr_uint(sp, i)) }
|
||||
None => { self.none() }
|
||||
};
|
||||
let arms = arms.iter().map(|arm| {
|
||||
let p = self.ecx.path_global(sp, self.rtpath("PluralArm"));
|
||||
let result = arm.result.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
let (lr, selarg) = match arm.selector {
|
||||
parse::Keyword(t) => {
|
||||
let p = ctpath(format!("{:?}", t));
|
||||
let p = self.ctpath(format!("{:?}", t));
|
||||
let p = self.ecx.path_global(sp, p);
|
||||
(rtpath("Keyword"), self.ecx.expr_path(p))
|
||||
(self.rtpath("Keyword"), self.ecx.expr_path(p))
|
||||
}
|
||||
parse::Literal(i) => {
|
||||
(rtpath("Literal"), self.ecx.expr_uint(sp, i))
|
||||
(self.rtpath("Literal"), self.ecx.expr_uint(sp, i))
|
||||
}
|
||||
};
|
||||
let selector = self.ecx.expr_call_global(sp,
|
||||
lr, ~[selarg]);
|
||||
lr, ~[selarg]);
|
||||
self.ecx.expr_struct(sp, p, ~[
|
||||
self.ecx.field_imm(sp,
|
||||
self.ecx.ident_of("selector"),
|
||||
selector),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("result"),
|
||||
self.ecx.expr_vec_slice(sp, result)),
|
||||
])
|
||||
self.ecx.field_imm(sp,
|
||||
self.ecx.ident_of("selector"),
|
||||
selector),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("result"),
|
||||
self.ecx.expr_vec_slice(sp, result)),
|
||||
])
|
||||
}).collect();
|
||||
let default = default.iter().map(|p| {
|
||||
let default = default.iter().map(|p| {
|
||||
self.trans_piece(p)
|
||||
}).collect();
|
||||
self.ecx.expr_call_global(sp, rtpath("Plural"), ~[
|
||||
self.ecx.expr_call_global(sp, self.rtpath("Plural"), ~[
|
||||
offset,
|
||||
self.ecx.expr_vec_slice(sp, arms),
|
||||
self.ecx.expr_vec_slice(sp, default),
|
||||
])
|
||||
}
|
||||
};
|
||||
let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
|
||||
let ty = self.ecx.ty_path(self.ecx.path_all(
|
||||
])
|
||||
}
|
||||
};
|
||||
let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
|
||||
let ty = self.ecx.ty_path(self.ecx.path_all(
|
||||
sp,
|
||||
true,
|
||||
rtpath("Method"),
|
||||
self.rtpath("Method"),
|
||||
opt_vec::with(life),
|
||||
~[]
|
||||
), None);
|
||||
let st = ast::ItemStatic(ty, ast::MutImmutable, method);
|
||||
let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}",
|
||||
self.method_statics.len()));
|
||||
let item = self.ecx.item(sp, static_name, self.static_attrs(), st);
|
||||
self.method_statics.push(item);
|
||||
self.ecx.expr_ident(sp, static_name)
|
||||
};
|
||||
), None);
|
||||
let st = ast::ItemStatic(ty, ast::MutImmutable, method);
|
||||
let static_name = self.ecx.ident_of(format!("__STATIC_METHOD_{}",
|
||||
self.method_statics.len()));
|
||||
let item = self.ecx.item(sp, static_name, self.static_attrs(), st);
|
||||
self.method_statics.push(item);
|
||||
self.ecx.expr_ident(sp, static_name)
|
||||
}
|
||||
|
||||
/// Translate a `parse::Piece` to a static `rt::Piece`
|
||||
fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
|
||||
let sp = self.fmtsp;
|
||||
match *piece {
|
||||
parse::String(s) => {
|
||||
let s = token::intern_and_get_ident(s);
|
||||
self.ecx.expr_call_global(sp,
|
||||
rtpath("String"),
|
||||
self.rtpath("String"),
|
||||
~[
|
||||
self.ecx.expr_str(sp, s)
|
||||
])
|
||||
}
|
||||
parse::CurrentArgument => {
|
||||
let nil = self.ecx.expr_lit(sp, ast::LitNil);
|
||||
self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil])
|
||||
self.ecx.expr_call_global(sp, self.rtpath("CurrentArgument"), ~[nil])
|
||||
}
|
||||
parse::Argument(ref arg) => {
|
||||
// Translate the position
|
||||
@ -525,11 +535,11 @@ impl<'a> Context<'a> {
|
||||
// These two have a direct mapping
|
||||
parse::ArgumentNext => {
|
||||
let path = self.ecx.path_global(sp,
|
||||
rtpath("ArgumentNext"));
|
||||
self.rtpath("ArgumentNext"));
|
||||
self.ecx.expr_path(path)
|
||||
}
|
||||
parse::ArgumentIs(i) => {
|
||||
self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
|
||||
self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
// Named arguments are converted to positional arguments at
|
||||
@ -540,7 +550,7 @@ impl<'a> Context<'a> {
|
||||
None => 0, // error already emitted elsewhere
|
||||
};
|
||||
let i = i + self.args.len();
|
||||
self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
|
||||
self.ecx.expr_call_global(sp, self.rtpath("ArgumentIs"),
|
||||
~[self.ecx.expr_uint(sp, i)])
|
||||
}
|
||||
};
|
||||
@ -550,20 +560,20 @@ impl<'a> Context<'a> {
|
||||
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill as u32));
|
||||
let align = match arg.format.align {
|
||||
parse::AlignLeft => {
|
||||
self.ecx.path_global(sp, parsepath("AlignLeft"))
|
||||
self.ecx.path_global(sp, self.parsepath("AlignLeft"))
|
||||
}
|
||||
parse::AlignRight => {
|
||||
self.ecx.path_global(sp, parsepath("AlignRight"))
|
||||
self.ecx.path_global(sp, self.parsepath("AlignRight"))
|
||||
}
|
||||
parse::AlignUnknown => {
|
||||
self.ecx.path_global(sp, parsepath("AlignUnknown"))
|
||||
self.ecx.path_global(sp, self.parsepath("AlignUnknown"))
|
||||
}
|
||||
};
|
||||
let align = self.ecx.expr_path(align);
|
||||
let flags = self.ecx.expr_uint(sp, arg.format.flags);
|
||||
let prec = trans_count(arg.format.precision);
|
||||
let width = trans_count(arg.format.width);
|
||||
let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
|
||||
let prec = self.trans_count(arg.format.precision);
|
||||
let width = self.trans_count(arg.format.width);
|
||||
let path = self.ecx.path_global(sp, self.rtpath("FormatSpec"));
|
||||
let fmt = self.ecx.expr_struct(sp, path, ~[
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
|
||||
@ -574,19 +584,19 @@ impl<'a> Context<'a> {
|
||||
|
||||
// Translate the method (if any)
|
||||
let method = match arg.method {
|
||||
None => { none.clone() }
|
||||
None => { self.none() }
|
||||
Some(ref m) => {
|
||||
let m = trans_method(*m);
|
||||
some(self.ecx.expr_addr_of(sp, m))
|
||||
let m = self.trans_method(*m);
|
||||
self.some(self.ecx.expr_addr_of(sp, m))
|
||||
}
|
||||
};
|
||||
let path = self.ecx.path_global(sp, rtpath("Argument"));
|
||||
let path = self.ecx.path_global(sp, self.rtpath("Argument"));
|
||||
let s = self.ecx.expr_struct(sp, path, ~[
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
|
||||
self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
|
||||
]);
|
||||
self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s])
|
||||
self.ecx.expr_call_global(sp, self.rtpath("Argument"), ~[s])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,14 +75,12 @@ pub trait Folder {
|
||||
}
|
||||
|
||||
fn fold_struct_field(&mut self, sf: &StructField) -> StructField {
|
||||
let fold_attribute = |x| fold_attribute_(x, self);
|
||||
|
||||
Spanned {
|
||||
node: ast::StructField_ {
|
||||
kind: sf.node.kind,
|
||||
id: self.new_id(sf.node.id),
|
||||
ty: self.fold_ty(sf.node.ty),
|
||||
attrs: sf.node.attrs.map(|e| fold_attribute(*e))
|
||||
attrs: sf.node.attrs.map(|e| fold_attribute_(*e, self))
|
||||
},
|
||||
span: self.new_span(sf.span)
|
||||
}
|
||||
@ -225,8 +223,7 @@ pub trait Folder {
|
||||
}
|
||||
}
|
||||
|
||||
let fold_attribute = |x| fold_attribute_(x, self);
|
||||
let attrs = v.node.attrs.map(|x| fold_attribute(*x));
|
||||
let attrs = v.node.attrs.map(|x| fold_attribute_(*x, self));
|
||||
|
||||
let de = match v.node.disr_expr {
|
||||
Some(e) => Some(self.fold_expr(e)),
|
||||
@ -323,8 +320,7 @@ fn fold_meta_item_<T: Folder>(mi: @MetaItem, fld: &mut T) -> @MetaItem {
|
||||
match mi.node {
|
||||
MetaWord(ref id) => MetaWord((*id).clone()),
|
||||
MetaList(ref id, ref mis) => {
|
||||
let fold_meta_item = |x| fold_meta_item_(x, fld);
|
||||
MetaList((*id).clone(), mis.map(|e| fold_meta_item(*e)))
|
||||
MetaList((*id).clone(), mis.map(|e| fold_meta_item_(*e, fld)))
|
||||
}
|
||||
MetaNameValue(ref id, ref s) => {
|
||||
MetaNameValue((*id).clone(), (*s).clone())
|
||||
@ -604,23 +600,18 @@ pub fn noop_fold_mod<T: Folder>(m: &Mod, folder: &mut T) -> Mod {
|
||||
}
|
||||
|
||||
pub fn noop_fold_crate<T: Folder>(c: Crate, folder: &mut T) -> Crate {
|
||||
let fold_meta_item = |x| fold_meta_item_(x, folder);
|
||||
let fold_attribute = |x| fold_attribute_(x, folder);
|
||||
|
||||
Crate {
|
||||
module: folder.fold_mod(&c.module),
|
||||
attrs: c.attrs.map(|x| fold_attribute(*x)),
|
||||
config: c.config.map(|x| fold_meta_item(*x)),
|
||||
attrs: c.attrs.map(|x| fold_attribute_(*x, folder)),
|
||||
config: c.config.map(|x| fold_meta_item_(*x, folder)),
|
||||
span: folder.new_span(c.span),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_fold_item<T: Folder>(i: &Item, folder: &mut T) -> SmallVector<@Item> {
|
||||
let fold_attribute = |x| fold_attribute_(x, folder);
|
||||
|
||||
SmallVector::one(@Item {
|
||||
ident: folder.fold_ident(i.ident),
|
||||
attrs: i.attrs.map(|e| fold_attribute(*e)),
|
||||
attrs: i.attrs.map(|e| fold_attribute_(*e, folder)),
|
||||
id: folder.new_id(i.id),
|
||||
node: folder.fold_item_underscore(&i.node),
|
||||
vis: i.vis,
|
||||
@ -711,8 +702,6 @@ pub fn noop_fold_pat<T: Folder>(p: @Pat, folder: &mut T) -> @Pat {
|
||||
}
|
||||
|
||||
pub fn noop_fold_expr<T: Folder>(e: @Expr, folder: &mut T) -> @Expr {
|
||||
let fold_field = |x| fold_field_(x, folder);
|
||||
|
||||
let node = match e.node {
|
||||
ExprVstore(e, v) => {
|
||||
ExprVstore(folder.fold_expr(e), v)
|
||||
@ -824,7 +813,7 @@ pub fn noop_fold_expr<T: Folder>(e: @Expr, folder: &mut T) -> @Expr {
|
||||
ExprMac(ref mac) => ExprMac(folder.fold_mac(mac)),
|
||||
ExprStruct(ref path, ref fields, maybe_expr) => {
|
||||
ExprStruct(folder.fold_path(path),
|
||||
fields.map(|x| fold_field(*x)),
|
||||
fields.map(|x| fold_field_(*x, folder)),
|
||||
maybe_expr.map(|x| folder.fold_expr(x)))
|
||||
},
|
||||
ExprParen(ex) => ExprParen(folder.fold_expr(ex))
|
||||
|
@ -15,7 +15,7 @@ fn main() {
|
||||
let mut y = None;
|
||||
x.write_downgrade(|write_mode| {
|
||||
y = Some(x.downgrade(write_mode));
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
});
|
||||
y.unwrap();
|
||||
// Adding this line causes a method unification failure instead
|
||||
|
@ -32,9 +32,9 @@ fn b() {
|
||||
|
||||
let mut p = ~[1];
|
||||
|
||||
borrow(p, || {
|
||||
p[0] = 5; //~ ERROR cannot assign to
|
||||
});
|
||||
borrow(
|
||||
p,
|
||||
|| p[0] = 5); //~ ERROR cannot borrow `p` as mutable
|
||||
}
|
||||
|
||||
fn c() {
|
||||
|
@ -21,13 +21,14 @@ impl X {
|
||||
|
||||
fn main() {
|
||||
let mut x = X(Right(main));
|
||||
(&mut x).with(|opt| {
|
||||
match opt {
|
||||
&Right(ref f) => {
|
||||
x = X(Left((0,0))); //~ ERROR cannot assign to `x`
|
||||
(*f)()
|
||||
},
|
||||
_ => fail!()
|
||||
}
|
||||
})
|
||||
(&mut x).with(
|
||||
|opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time
|
||||
match opt {
|
||||
&Right(ref f) => {
|
||||
x = X(Left((0,0)));
|
||||
(*f)()
|
||||
},
|
||||
_ => fail!()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ trait Foo {
|
||||
|
||||
fn test(x: &mut Foo) {
|
||||
let _y = x.f1();
|
||||
x.f2(); //~ ERROR cannot borrow `*x` because it is already borrowed as mutable
|
||||
x.f2(); //~ ERROR cannot borrow `*x` as mutable
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
79
src/test/compile-fail/borrowck-closures-mut-and-imm.rs
Normal file
79
src/test/compile-fail/borrowck-closures-mut-and-imm.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tests that two closures cannot simultaneously have mutable
|
||||
// and immutable access to the variable. Issue #6801.
|
||||
|
||||
fn get(x: &int) -> int {
|
||||
*x
|
||||
}
|
||||
|
||||
fn set(x: &mut int) {
|
||||
*x = 4;
|
||||
}
|
||||
|
||||
fn a() {
|
||||
let mut x = 3;
|
||||
let c1 = || x = 4;
|
||||
let c2 = || x * 5; //~ ERROR cannot borrow `x`
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let mut x = 3;
|
||||
let c1 = || set(&mut x);
|
||||
let c2 = || get(&x); //~ ERROR cannot borrow `x`
|
||||
}
|
||||
|
||||
fn c() {
|
||||
let mut x = 3;
|
||||
let c1 = || set(&mut x);
|
||||
let c2 = || x * 5; //~ ERROR cannot borrow `x`
|
||||
}
|
||||
|
||||
fn d() {
|
||||
let mut x = 3;
|
||||
let c2 = || x * 5;
|
||||
x = 5; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn e() {
|
||||
let mut x = 3;
|
||||
let c1 = || get(&x);
|
||||
x = 5; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let mut x = ~3;
|
||||
let c1 = || get(&*x);
|
||||
*x = 5; //~ ERROR cannot assign
|
||||
}
|
||||
|
||||
fn g() {
|
||||
struct Foo {
|
||||
f: ~int
|
||||
}
|
||||
|
||||
let mut x = ~Foo { f: ~3 };
|
||||
let c1 = || get(&*x.f);
|
||||
*x.f = 5; //~ ERROR cannot assign to `*x.f`
|
||||
}
|
||||
|
||||
fn h() {
|
||||
struct Foo {
|
||||
f: ~int
|
||||
}
|
||||
|
||||
let mut x = ~Foo { f: ~3 };
|
||||
let c1 = || get(&*x.f);
|
||||
let c2 = || *x.f = 5; //~ ERROR cannot borrow `x` as mutable
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
31
src/test/compile-fail/borrowck-closures-mut-of-imm.rs
Normal file
31
src/test/compile-fail/borrowck-closures-mut-of-imm.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tests that two closures cannot simultaneously have mutable
|
||||
// and immutable access to the variable. Issue #6801.
|
||||
|
||||
fn get(x: &int) -> int {
|
||||
*x
|
||||
}
|
||||
|
||||
fn set(x: &mut int) {
|
||||
*x = 4;
|
||||
}
|
||||
|
||||
fn a(x: &int) {
|
||||
let c1 = || set(&mut *x);
|
||||
//~^ ERROR cannot borrow
|
||||
let c2 = || set(&mut *x);
|
||||
//~^ ERROR closure requires unique access to `x`
|
||||
//~^^ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
56
src/test/compile-fail/borrowck-closures-two-mut.rs
Normal file
56
src/test/compile-fail/borrowck-closures-two-mut.rs
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tests that two closures cannot simultaneously have mutable
|
||||
// access to the variable, whether that mutable access be used
|
||||
// for direct assignment or for taking mutable ref. Issue #6801.
|
||||
|
||||
fn a() {
|
||||
let mut x = 3;
|
||||
let c1 = || x = 4;
|
||||
let c2 = || x = 5; //~ ERROR cannot borrow `x` as mutable more than once
|
||||
}
|
||||
|
||||
fn set(x: &mut int) {
|
||||
*x = 4;
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let mut x = 3;
|
||||
let c1 = || set(&mut x);
|
||||
let c2 = || set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once
|
||||
}
|
||||
|
||||
fn c() {
|
||||
let mut x = 3;
|
||||
let c1 = || x = 5;
|
||||
let c2 = || set(&mut x); //~ ERROR cannot borrow `x` as mutable more than once
|
||||
}
|
||||
|
||||
fn d() {
|
||||
let mut x = 3;
|
||||
let c1 = || x = 5;
|
||||
let c2 = || { let _y = || set(&mut x); }; // (nested closure)
|
||||
//~^ ERROR cannot borrow `x` as mutable more than once
|
||||
}
|
||||
|
||||
fn g() {
|
||||
struct Foo {
|
||||
f: ~int
|
||||
}
|
||||
|
||||
let mut x = ~Foo { f: ~3 };
|
||||
let c1 = || set(&mut *x.f);
|
||||
let c2 = || set(&mut *x.f);
|
||||
//~^ ERROR cannot borrow `x` as mutable more than once
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
50
src/test/compile-fail/borrowck-closures-unique.rs
Normal file
50
src/test/compile-fail/borrowck-closures-unique.rs
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tests that a closure which requires mutable access to the referent
|
||||
// of an `&mut` requires a "unique" borrow -- that is, the variable to
|
||||
// be borrowed (here, `x`) will not be borrowed *mutably*, but
|
||||
// may be *immutable*, but we cannot allow
|
||||
// multiple borrows.
|
||||
|
||||
fn get(x: &int) -> int {
|
||||
*x
|
||||
}
|
||||
|
||||
fn set(x: &mut int) -> int {
|
||||
*x
|
||||
}
|
||||
|
||||
fn a(x: &mut int) {
|
||||
let c1 = || get(x);
|
||||
let c2 = || get(x);
|
||||
}
|
||||
|
||||
fn b(x: &mut int) {
|
||||
let c1 = || get(x);
|
||||
let c2 = || set(x); //~ ERROR closure requires unique access to `x`
|
||||
}
|
||||
|
||||
fn c(x: &mut int) {
|
||||
let c1 = || get(x);
|
||||
let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x`
|
||||
}
|
||||
|
||||
fn d(x: &mut int) {
|
||||
let c1 = || set(x);
|
||||
let c2 = || set(x); //~ ERROR closure requires unique access to `x`
|
||||
}
|
||||
|
||||
fn e(x: &mut int) {
|
||||
let c1: || = || x = fail!(); //~ ERROR closure cannot assign to immutable argument `x`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
31
src/test/compile-fail/borrowck-closures-use-after-free.rs
Normal file
31
src/test/compile-fail/borrowck-closures-use-after-free.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tests that a closure which mutates a local variable
|
||||
// cannot also be supplied a borrowed version of that
|
||||
// variable's contents. Issue #11192.
|
||||
|
||||
struct Foo {
|
||||
x: int
|
||||
}
|
||||
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
println!("drop {}", self.x);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut ptr = ~Foo { x: 0 };
|
||||
let test = |foo: &Foo| {
|
||||
ptr = ~Foo { x: ptr.x + 1 };
|
||||
};
|
||||
test(ptr); //~ ERROR cannot borrow `*ptr`
|
||||
}
|
@ -23,9 +23,10 @@ impl Foo {
|
||||
}
|
||||
|
||||
fn bar(f: &mut Foo) {
|
||||
f.foo(|a| {
|
||||
f.n.insert(*a); //~ ERROR cannot borrow
|
||||
})
|
||||
f.foo(
|
||||
|a| { //~ ERROR closure requires unique access to `f`
|
||||
f.n.insert(*a);
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -21,7 +21,9 @@ fn box_imm() {
|
||||
info!("v={}", *v);
|
||||
//~^ ERROR cannot move `v` into closure
|
||||
});
|
||||
}
|
||||
|
||||
fn box_imm_explicit() {
|
||||
let v = ~3;
|
||||
let _w = &v;
|
||||
task::spawn(proc() {
|
||||
|
@ -14,11 +14,12 @@ fn borrow(v: &int, f: |x: &int|) {
|
||||
|
||||
fn box_imm() {
|
||||
let mut v = ~3;
|
||||
borrow(v, |w| {
|
||||
v = ~4; //~ ERROR cannot assign to `v` because it is borrowed
|
||||
assert_eq!(*v, 3);
|
||||
assert_eq!(*w, 4);
|
||||
})
|
||||
borrow(v,
|
||||
|w| { //~ ERROR cannot borrow `v` as mutable
|
||||
v = ~4;
|
||||
assert_eq!(*v, 3);
|
||||
assert_eq!(*w, 4);
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -32,8 +32,8 @@ fn a() {
|
||||
p.impurem();
|
||||
|
||||
// But in this case we do not honor the loan:
|
||||
p.blockm(|| {
|
||||
p.x = 10; //~ ERROR cannot assign
|
||||
p.blockm(|| { //~ ERROR cannot borrow `p` as mutable
|
||||
p.x = 10;
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,11 @@ fn has_mut_vec_and_does_not_try_to_change_it() {
|
||||
|
||||
fn has_mut_vec_but_tries_to_change_it() {
|
||||
let mut v = ~[1, 2, 3];
|
||||
takes_imm_elt(&v[0], || {
|
||||
v[1] = 4; //~ ERROR cannot assign
|
||||
})
|
||||
takes_imm_elt(
|
||||
&v[0],
|
||||
|| { //~ ERROR cannot borrow `v` as mutable
|
||||
v[1] = 4;
|
||||
})
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -9,10 +9,8 @@
|
||||
// except according to those terms.
|
||||
|
||||
pub fn main() {
|
||||
// FIXME(#2202) - Due to the way that borrowck treats closures,
|
||||
// you get two error reports here.
|
||||
let bar = ~3;
|
||||
let _g = || { //~ ERROR capture of moved value
|
||||
let _h: proc() -> int = proc() *bar; //~ ERROR capture of moved value
|
||||
let _g = || {
|
||||
let _h: proc() -> int = proc() *bar; //~ ERROR cannot move out of captured outer variable
|
||||
};
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ fn borrowed_receiver<'a>(x: &'a Foo) -> &'a () {
|
||||
}
|
||||
|
||||
fn owned_receiver(x: ~Foo) -> &() {
|
||||
x.borrowed() //~ ERROR borrowed value does not live long enough
|
||||
x.borrowed() //~ ERROR `*x` does not live long enough
|
||||
}
|
||||
|
||||
fn mut_owned_receiver(mut x: ~Foo) {
|
||||
|
@ -14,6 +14,6 @@ fn main() {
|
||||
[1, 2, ..tail] => tail,
|
||||
_ => unreachable!()
|
||||
};
|
||||
a[0] = 0; //~ ERROR cannot assign to `a[]` because it is borrowed
|
||||
a[0] = 0; //~ ERROR cannot assign to `a[..]` because it is borrowed
|
||||
t[0];
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ fn a() {
|
||||
let mut vec = ~[~1, ~2, ~3];
|
||||
match vec {
|
||||
[~ref _a] => {
|
||||
vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed
|
||||
vec[0] = ~4; //~ ERROR cannot assign
|
||||
}
|
||||
_ => fail!("foo")
|
||||
}
|
||||
@ -22,7 +22,7 @@ fn b() {
|
||||
let mut vec = ~[~1, ~2, ~3];
|
||||
match vec {
|
||||
[.._b] => {
|
||||
vec[0] = ~4; //~ ERROR cannot assign to `(*vec)[]` because it is borrowed
|
||||
vec[0] = ~4; //~ ERROR cannot assign
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
fn a() -> &int {
|
||||
let vec = ~[1, 2, 3, 4];
|
||||
let tail = match vec {
|
||||
[_a, ..tail] => &tail[0], //~ ERROR borrowed value does not live long enough
|
||||
[_a, ..tail] => &tail[0], //~ ERROR `vec[..]` does not live long enough
|
||||
_ => fail!("foo")
|
||||
};
|
||||
tail
|
||||
|
@ -13,7 +13,7 @@ struct thing<'a, Q> {
|
||||
}
|
||||
|
||||
fn thing<Q>(x: &Q) -> thing<Q> {
|
||||
thing{ x: x } //~ ERROR cannot infer an appropriate lifetime
|
||||
thing{ x: x } //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -11,7 +11,7 @@
|
||||
fn id<T>(t: T) -> T { t }
|
||||
|
||||
fn f<'r, T>(v: &'r T) -> 'r || -> T {
|
||||
id(|| *v) //~ ERROR cannot infer an appropriate lifetime
|
||||
id(|| *v) //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -24,7 +24,7 @@ fn main() {
|
||||
|
||||
let y = {
|
||||
let tmp0 = 3;
|
||||
let tmp1 = &tmp0; //~ ERROR borrowed value does not live long enough
|
||||
let tmp1 = &tmp0; //~ ERROR `tmp0` does not live long enough
|
||||
repeater(tmp1)
|
||||
};
|
||||
assert!(3 == *(y.get()));
|
||||
|
@ -17,13 +17,13 @@ fn touch<A>(_a: &A) {}
|
||||
|
||||
fn f10() {
|
||||
let x = Foo { f: ~"hi", y: 3 };
|
||||
consume(x.f); //~ NOTE `x.f` moved here
|
||||
consume(x.f);
|
||||
touch(&x.y); //~ ERROR use of partially moved value: `x`
|
||||
}
|
||||
|
||||
fn f20() {
|
||||
let x = ~[~"hi"];
|
||||
consume(x[0]); //~ NOTE `(*x)[]` moved here
|
||||
consume(x[0]);
|
||||
touch(&x[0]); //~ ERROR use of partially moved value: `x`
|
||||
}
|
||||
|
||||
|
@ -14,5 +14,5 @@ fn main() {
|
||||
let m = RefCell::new(0);
|
||||
let mut b = m.borrow_mut();
|
||||
let b1 = b.get();
|
||||
let b2 = b.get(); //~ ERROR cannot borrow `b` because it is already borrowed as mutable
|
||||
let b2 = b.get(); //~ ERROR cannot borrow
|
||||
}
|
||||
|
@ -15,6 +15,6 @@ fn main() {
|
||||
let p;
|
||||
{
|
||||
let b = m.borrow();
|
||||
p = b.get(); //~ ERROR borrowed value does not live long enough
|
||||
p = b.get(); //~ ERROR `b` does not live long enough
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ fn env<'a>(_: &'a uint, blk: |p: 'a |||) {
|
||||
|
||||
let mut state = 0;
|
||||
let statep = &mut state;
|
||||
blk(|| *statep = 1); //~ ERROR cannot infer an appropriate lifetime
|
||||
blk(|| *statep = 1); //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn no_env_no_for<'a>(_: &'a uint, blk: |p: 'a |||) {
|
||||
@ -40,7 +40,7 @@ fn repeating_loop() {
|
||||
let state = 0;
|
||||
|
||||
loop {
|
||||
closure = || state; //~ ERROR cannot infer an appropriate lifetime
|
||||
closure = || state; //~ ERROR cannot infer
|
||||
break;
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ fn repeating_while() {
|
||||
let state = 0;
|
||||
|
||||
while true {
|
||||
closure = || state; //~ ERROR cannot infer an appropriate lifetime
|
||||
closure = || state; //~ ERROR cannot infer
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
// bounded by the current function call.
|
||||
|
||||
fn foo(a: int) {
|
||||
let _p: &'static int = &a; //~ ERROR borrowed value does not live long enough
|
||||
let _p: &'static int = &a; //~ ERROR `a` does not live long enough
|
||||
}
|
||||
|
||||
fn bar(a: int) {
|
||||
@ -20,7 +20,7 @@ fn bar(a: int) {
|
||||
}
|
||||
|
||||
fn zed<'a>(a: int) -> &'a int {
|
||||
&a //~ ERROR borrowed value does not live long enough
|
||||
&a //~ ERROR `a` does not live long enough
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -14,8 +14,7 @@ struct dog {
|
||||
|
||||
impl dog {
|
||||
pub fn chase_cat(&mut self) {
|
||||
let p: &'static mut uint = &mut self.cats_chased;
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
let p: &'static mut uint = &mut self.cats_chased; //~ ERROR cannot infer
|
||||
*p += 1u;
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,7 @@ struct dog {
|
||||
impl dog {
|
||||
pub fn chase_cat(&mut self) {
|
||||
let _f = || {
|
||||
let p: &'static mut uint = &mut self.food;
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
let p: &'static mut uint = &mut self.food; //~ ERROR cannot infer
|
||||
*p = 3u;
|
||||
};
|
||||
}
|
||||
|
@ -17,12 +17,12 @@ struct a_class<'a> { x:&'a int }
|
||||
|
||||
fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> {
|
||||
return e; //~ ERROR mismatched types: expected `an_enum<'b>` but found `an_enum<'a>`
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> {
|
||||
return e; //~ ERROR mismatched types: expected `a_class<'b>` but found `a_class<'a>`
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -14,7 +14,7 @@ enum ast<'a> {
|
||||
}
|
||||
|
||||
fn mk_add_bad1<'a,'b>(x: &'a ast<'a>, y: &'b ast<'b>) -> ast<'a> {
|
||||
add(x, y) //~ ERROR cannot infer an appropriate lifetime
|
||||
add(x, y) //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -14,7 +14,7 @@ enum ast<'a> {
|
||||
}
|
||||
|
||||
fn mk_add_bad2<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast {
|
||||
add(x, y) //~ ERROR cannot infer an appropriate lifetime
|
||||
add(x, y) //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -18,6 +18,6 @@ fn main() {
|
||||
|
||||
loop {
|
||||
let x = 1 + *p;
|
||||
p = &x; //~ ERROR borrowed value does not live long enough
|
||||
p = &x; //~ ERROR `x` does not live long enough
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ fn broken() {
|
||||
let mut _y = ~[&mut x];
|
||||
while x < 10 {
|
||||
let mut z = x;
|
||||
_y.push(&mut z); //~ ERROR borrowed value does not live long enough
|
||||
_y.push(&mut z); //~ ERROR `z` does not live long enough
|
||||
x += 1; //~ ERROR cannot assign
|
||||
}
|
||||
}
|
||||
|
@ -20,13 +20,13 @@ fn ordering1<'a, 'b>(x: &'a &'b uint) -> &'a uint {
|
||||
|
||||
fn ordering2<'a, 'b>(x: &'a &'b uint, y: &'a uint) -> &'b uint {
|
||||
// However, it is not safe to assume that 'b <= 'a
|
||||
&*y //~ ERROR cannot infer an appropriate lifetime
|
||||
&*y //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint {
|
||||
// Do not infer an ordering from the return value.
|
||||
let z: &'b uint = &*x;
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
fail!();
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ fn call1<'a>(x: &'a uint) {
|
||||
let y: uint = 3;
|
||||
let z: &'a & uint = &(&y);
|
||||
//~^ ERROR borrowed value does not live long enough
|
||||
//~^^ ERROR borrowed value does not live long enough
|
||||
//~^^ ERROR `y` does not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -24,7 +24,7 @@ impl<'b, T> Node<'b, T> {
|
||||
fn get<'a>(&'a self) -> &'b T {
|
||||
match self.next {
|
||||
Some(ref next) => next.get(),
|
||||
None => &self.val //~ ERROR cannot infer an appropriate lifetime
|
||||
None => &self.val //~ ERROR cannot infer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,7 @@ fn wants_static_fn(_x: 'static ||) {}
|
||||
|
||||
fn main() {
|
||||
let i = 3;
|
||||
wants_static_fn(|| {
|
||||
//~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
|
||||
wants_static_fn(|| { //~ ERROR cannot infer
|
||||
info!("i={}", i);
|
||||
})
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ mod argparse {
|
||||
|
||||
impl<'a> Flag<'a> {
|
||||
pub fn set_desc(self, s: &str) -> Flag<'a> {
|
||||
Flag { //~ ERROR cannot infer an appropriate lifetime
|
||||
Flag { //~ ERROR cannot infer
|
||||
name: self.name,
|
||||
desc: s,
|
||||
max_count: self.max_count,
|
||||
|
@ -22,7 +22,7 @@ struct not_parameterized2 {
|
||||
|
||||
fn take1(p: parameterized1) -> parameterized1 { p }
|
||||
//~^ ERROR mismatched types
|
||||
//~^^ ERROR cannot infer an appropriate lifetime
|
||||
//~^^ ERROR cannot infer
|
||||
|
||||
fn take3(p: not_parameterized1) -> not_parameterized1 { p }
|
||||
fn take4(p: not_parameterized2) -> not_parameterized2 { p }
|
||||
|
@ -16,7 +16,7 @@ fn with<T>(f: |x: &int| -> T) -> T {
|
||||
|
||||
fn manip<'a>(x: &'a int) -> int {
|
||||
let z = with(|y| { select(x, y) });
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
*z
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,11 @@ struct indirect2<'a> {
|
||||
}
|
||||
|
||||
fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
|
||||
fn take_indirect1(p: indirect1) -> indirect1 { p }
|
||||
|
||||
fn take_indirect2(p: indirect2) -> indirect2 { p } //~ ERROR mismatched types
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
|
||||
fn main() {}
|
||||
|
@ -32,7 +32,7 @@ impl<'a> set_f<'a> for c<'a> {
|
||||
|
||||
fn set_f_bad(&self, b: @b) {
|
||||
self.f = b; //~ ERROR mismatched types: expected `@@&'a int` but found `@@&int`
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,10 @@ fn ignore(_f: <'z>|&'z int| -> &'z int) {}
|
||||
|
||||
fn nested() {
|
||||
let y = 3;
|
||||
ignore(|z| {
|
||||
if false { &y } else { z } //~ ERROR borrowed value does not live long enough
|
||||
});
|
||||
ignore(
|
||||
|z| { //~ ERROR `y` does not live long enough
|
||||
if false { &y } else { z }
|
||||
});
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -12,7 +12,7 @@ fn ignore<T>(t: T) {}
|
||||
|
||||
fn nested<'x>(x: &'x int) {
|
||||
let y = 3;
|
||||
let mut ay = &y; //~ ERROR cannot infer an appropriate lifetime
|
||||
let mut ay = &y; //~ ERROR cannot infer
|
||||
|
||||
ignore::< <'z>|&'z int|>(|z| {
|
||||
ay = x;
|
||||
@ -22,7 +22,7 @@ fn nested<'x>(x: &'x int) {
|
||||
|
||||
ignore::< <'z>|&'z int| -> &'z int>(|z| {
|
||||
if false { return x; } //~ ERROR mismatched types
|
||||
//~^ ERROR cannot infer an appropriate lifetime
|
||||
//~^ ERROR cannot infer
|
||||
if false { return ay; }
|
||||
return z;
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ fn with<R>(f: <'a>|x: &'a int| -> R) -> R {
|
||||
fn return_it<'a>() -> &'a int {
|
||||
with(|o| o) //~ ERROR mismatched types
|
||||
//~^ ERROR lifetime of return value does not outlive the function call
|
||||
//~^^ ERROR cannot infer an appropriate lifetime
|
||||
//~^^ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -22,7 +22,7 @@ fn with<R>(f: |x: &int| -> R) -> R {
|
||||
fn return_it() -> &int {
|
||||
with(|o| o) //~ ERROR mismatched types
|
||||
//~^ ERROR lifetime of return value does not outlive the function call
|
||||
//~^^ ERROR cannot infer an appropriate lifetime
|
||||
//~^^ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -19,7 +19,7 @@ fn box_it<'r>(x: 'r ||) -> closure_box<'r> {
|
||||
fn main() {
|
||||
let cl_box = {
|
||||
let mut i = 3;
|
||||
box_it(|| i += 1) //~ ERROR cannot infer an appropriate lifetime
|
||||
box_it(|| i += 1) //~ ERROR cannot infer
|
||||
};
|
||||
(cl_box.cl)();
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ impl get_ctxt for Foo<'a> {
|
||||
}
|
||||
|
||||
fn make_gc2<'a,'b>(foo: Foo<'a>) -> @get_ctxt<'b> {
|
||||
return @foo as @get_ctxt; //~ ERROR cannot infer an appropriate lifetime
|
||||
return @foo as @get_ctxt; //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: cannot infer an appropriate lifetime
|
||||
// error-pattern: cannot infer
|
||||
extern mod sync;
|
||||
use sync::RWLock;
|
||||
fn main() {
|
||||
|
@ -24,7 +24,7 @@ impl Trait<&'static str> for Struct {
|
||||
|
||||
fn main() {
|
||||
let person = ~"Fred";
|
||||
let person: &str = person; //~ ERROR borrowed value does not live long enough
|
||||
let person: &str = person; //~ ERROR `person[..]` does not live long enough
|
||||
let s: ~Trait<&'static str> = ~Struct { person: person };
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,6 @@ fn main() {
|
||||
let mut xs = ~[1, 2, 3, 4];
|
||||
|
||||
for x in xs.mut_iter() {
|
||||
xs.push(1) //~ ERROR cannot borrow `xs` because it is already borrowed as mutable
|
||||
xs.push(1) //~ ERROR cannot borrow `xs`
|
||||
}
|
||||
}
|
||||
|
49
src/test/run-pass/borrowck-closures-two-imm.rs
Normal file
49
src/test/run-pass/borrowck-closures-two-imm.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Tests that two closures can simultaneously have immutable
|
||||
// access to the variable, whether that immutable access be used
|
||||
// for direct reads or for taking immutable ref. Also check
|
||||
// that the main function can read the variable too while
|
||||
// the closures are in scope. Issue #6801.
|
||||
|
||||
fn a() -> int {
|
||||
let mut x = 3;
|
||||
x += 1;
|
||||
let c1 = || x * 4;
|
||||
let c2 = || x * 5;
|
||||
c1() * c2() * x
|
||||
}
|
||||
|
||||
fn get(x: &int) -> int {
|
||||
*x * 4
|
||||
}
|
||||
|
||||
fn b() -> int {
|
||||
let mut x = 3;
|
||||
x += 1;
|
||||
let c1 = || get(&x);
|
||||
let c2 = || get(&x);
|
||||
c1() * c2() * x
|
||||
}
|
||||
|
||||
fn c() -> int {
|
||||
let mut x = 3;
|
||||
x += 1;
|
||||
let c1 = || x * 5;
|
||||
let c2 = || get(&x);
|
||||
c1() * c2() * x
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(a(), 1280);
|
||||
assert_eq!(b(), 1024);
|
||||
assert_eq!(c(), 1280);
|
||||
}
|
@ -16,5 +16,6 @@ struct Refs { refs: ~[int], n: int }
|
||||
pub fn main() {
|
||||
let mut e = Refs{refs: ~[], n: 0};
|
||||
let _f: || = || error!("{}", e.n);
|
||||
e.refs.push(1);
|
||||
let x: &[int] = e.refs;
|
||||
assert_eq!(x.len(), 0);
|
||||
}
|
||||
|
@ -1,627 +0,0 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-fast
|
||||
|
||||
#[feature(managed_boxes)];
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::libc::c_void;
|
||||
use std::ptr;
|
||||
use std::mem;
|
||||
use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Disr, Opaque};
|
||||
use std::unstable::raw::Vec;
|
||||
|
||||
#[doc = "High-level interfaces to `std::unstable::intrinsics::visit_ty` reflection system."]
|
||||
|
||||
/// Trait for visitor that wishes to reflect on data.
|
||||
trait movable_ptr {
|
||||
fn move_ptr(&mut self, adjustment: |*c_void| -> *c_void);
|
||||
}
|
||||
|
||||
/// Helper function for alignment calculation.
|
||||
#[inline(always)]
|
||||
fn align(size: uint, align: uint) -> uint {
|
||||
((size + align) - 1u) & !(align - 1u)
|
||||
}
|
||||
|
||||
struct ptr_visit_adaptor<V>(Inner<V>);
|
||||
|
||||
impl<V:TyVisitor + movable_ptr> ptr_visit_adaptor<V> {
|
||||
fn inner<'a>(&'a mut self) -> &'a mut V {
|
||||
let ptr_visit_adaptor(ref mut i) = *self;
|
||||
&mut i.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<V:TyVisitor + movable_ptr> ptr_visit_adaptor<V> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bump(&mut self, sz: uint) {
|
||||
self.inner().move_ptr(|p| ((p as uint) + sz) as *c_void)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn align(&mut self, a: uint) {
|
||||
self.inner().move_ptr(|p| align(p as uint, a) as *c_void)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn align_to<T>(&mut self) {
|
||||
self.align(mem::min_align_of::<T>());
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bump_past<T>(&mut self) {
|
||||
self.bump(mem::size_of::<T>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
|
||||
|
||||
fn visit_bot(&mut self) -> bool {
|
||||
self.align_to::<()>();
|
||||
if ! self.inner().visit_bot() { return false; }
|
||||
self.bump_past::<()>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_nil(&mut self) -> bool {
|
||||
self.align_to::<()>();
|
||||
if ! self.inner().visit_nil() { return false; }
|
||||
self.bump_past::<()>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_bool(&mut self) -> bool {
|
||||
self.align_to::<bool>();
|
||||
if ! self.inner().visit_bool() { return false; }
|
||||
self.bump_past::<bool>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_int(&mut self) -> bool {
|
||||
self.align_to::<int>();
|
||||
if ! self.inner().visit_int() { return false; }
|
||||
self.bump_past::<int>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_i8(&mut self) -> bool {
|
||||
self.align_to::<i8>();
|
||||
if ! self.inner().visit_i8() { return false; }
|
||||
self.bump_past::<i8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_i16(&mut self) -> bool {
|
||||
self.align_to::<i16>();
|
||||
if ! self.inner().visit_i16() { return false; }
|
||||
self.bump_past::<i16>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_i32(&mut self) -> bool {
|
||||
self.align_to::<i32>();
|
||||
if ! self.inner().visit_i32() { return false; }
|
||||
self.bump_past::<i32>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_i64(&mut self) -> bool {
|
||||
self.align_to::<i64>();
|
||||
if ! self.inner().visit_i64() { return false; }
|
||||
self.bump_past::<i64>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_uint(&mut self) -> bool {
|
||||
self.align_to::<uint>();
|
||||
if ! self.inner().visit_uint() { return false; }
|
||||
self.bump_past::<uint>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_u8(&mut self) -> bool {
|
||||
self.align_to::<u8>();
|
||||
if ! self.inner().visit_u8() { return false; }
|
||||
self.bump_past::<u8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_u16(&mut self) -> bool {
|
||||
self.align_to::<u16>();
|
||||
if ! self.inner().visit_u16() { return false; }
|
||||
self.bump_past::<u16>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_u32(&mut self) -> bool {
|
||||
self.align_to::<u32>();
|
||||
if ! self.inner().visit_u32() { return false; }
|
||||
self.bump_past::<u32>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_u64(&mut self) -> bool {
|
||||
self.align_to::<u64>();
|
||||
if ! self.inner().visit_u64() { return false; }
|
||||
self.bump_past::<u64>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_f32(&mut self) -> bool {
|
||||
self.align_to::<f32>();
|
||||
if ! self.inner().visit_f32() { return false; }
|
||||
self.bump_past::<f32>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_f64(&mut self) -> bool {
|
||||
self.align_to::<f64>();
|
||||
if ! self.inner().visit_f64() { return false; }
|
||||
self.bump_past::<f64>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_char(&mut self) -> bool {
|
||||
self.align_to::<char>();
|
||||
if ! self.inner().visit_char() { return false; }
|
||||
self.bump_past::<char>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_estr_box(&mut self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_estr_uniq(&mut self) -> bool {
|
||||
self.align_to::<~str>();
|
||||
if ! self.inner().visit_estr_uniq() { return false; }
|
||||
self.bump_past::<~str>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_estr_slice(&mut self) -> bool {
|
||||
self.align_to::<&'static str>();
|
||||
if ! self.inner().visit_estr_slice() { return false; }
|
||||
self.bump_past::<&'static str>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_estr_fixed(&mut self, n: uint,
|
||||
sz: uint,
|
||||
align: uint) -> bool {
|
||||
self.align(align);
|
||||
if ! self.inner().visit_estr_fixed(n, sz, align) { return false; }
|
||||
self.bump(sz);
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<@u8>();
|
||||
if ! self.inner().visit_box(mtbl, inner) { return false; }
|
||||
self.bump_past::<@u8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<~u8>();
|
||||
if ! self.inner().visit_uniq(mtbl, inner) { return false; }
|
||||
self.bump_past::<~u8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_ptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<*u8>();
|
||||
if ! self.inner().visit_ptr(mtbl, inner) { return false; }
|
||||
self.bump_past::<*u8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<&'static u8>();
|
||||
if ! self.inner().visit_rptr(mtbl, inner) { return false; }
|
||||
self.bump_past::<&'static u8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<Vec<()>>();
|
||||
// FIXME (#3732): Inner really has to move its own pointers on this one.
|
||||
// or else possibly we could have some weird interface wherein we
|
||||
// read-off a word from inner's pointers, but the read-word has to
|
||||
// always be the same in all sub-pointers? Dubious.
|
||||
if ! self.inner().visit_vec(mtbl, inner) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<~[u8]>();
|
||||
if ! self.inner().visit_vec(mtbl, inner) { return false; }
|
||||
self.bump_past::<~[u8]>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<~[u8]>();
|
||||
if ! self.inner().visit_evec_uniq(mtbl, inner) { return false; }
|
||||
self.bump_past::<~[u8]>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align_to::<&'static [u8]>();
|
||||
if ! self.inner().visit_evec_slice(mtbl, inner) { return false; }
|
||||
self.bump_past::<&'static [u8]>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
|
||||
mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.align(align);
|
||||
if ! self.inner().visit_evec_fixed(n, sz, align, mtbl, inner) {
|
||||
return false;
|
||||
}
|
||||
self.bump(sz);
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool {
|
||||
self.align(align);
|
||||
if ! self.inner().visit_enter_rec(n_fields, sz, align) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_rec_field(&mut self, i: uint, name: &str,
|
||||
mtbl: uint, inner: *TyDesc) -> bool {
|
||||
if ! self.inner().visit_rec_field(i, name, mtbl, inner) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_leave_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool {
|
||||
if ! self.inner().visit_leave_rec(n_fields, sz, align) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_class(&mut self, name: &str, named_fields: bool, n_fields: uint, sz: uint,
|
||||
align: uint) -> bool {
|
||||
self.align(align);
|
||||
if ! self.inner().visit_enter_class(name, named_fields, n_fields, sz, align) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_class_field(&mut self, i: uint, name: &str, named: bool,
|
||||
mtbl: uint, inner: *TyDesc) -> bool {
|
||||
if ! self.inner().visit_class_field(i, name, named, mtbl, inner) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_leave_class(&mut self, name: &str, named_fields: bool, n_fields: uint, sz: uint,
|
||||
align: uint) -> bool {
|
||||
if ! self.inner().visit_leave_class(name, named_fields, n_fields, sz, align) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_tup(&mut self, n_fields: uint, sz: uint, align: uint) -> bool {
|
||||
self.align(align);
|
||||
if ! self.inner().visit_enter_tup(n_fields, sz, align) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
|
||||
if ! self.inner().visit_tup_field(i, inner) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_leave_tup(&mut self, n_fields: uint, sz: uint, align: uint) -> bool {
|
||||
if ! self.inner().visit_leave_tup(n_fields, sz, align) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_fn(&mut self, purity: uint, proto: uint,
|
||||
n_inputs: uint, retstyle: uint) -> bool {
|
||||
if ! self.inner().visit_enter_fn(purity, proto, n_inputs, retstyle) {
|
||||
return false
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_fn_input(&mut self, i: uint, mode: uint, inner: *TyDesc) -> bool {
|
||||
if ! self.inner().visit_fn_input(i, mode, inner) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_fn_output(&mut self, retstyle: uint, variadic: bool, inner: *TyDesc) -> bool {
|
||||
if ! self.inner().visit_fn_output(retstyle, variadic, inner) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_leave_fn(&mut self, purity: uint, proto: uint,
|
||||
n_inputs: uint, retstyle: uint) -> bool {
|
||||
if ! self.inner().visit_leave_fn(purity, proto, n_inputs, retstyle) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_enum(&mut self, n_variants: uint,
|
||||
get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
|
||||
sz: uint, align: uint)
|
||||
-> bool {
|
||||
self.align(align);
|
||||
if ! self.inner().visit_enter_enum(n_variants, get_disr, sz, align) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_enum_variant(&mut self, variant: uint,
|
||||
disr_val: Disr,
|
||||
n_fields: uint,
|
||||
name: &str) -> bool {
|
||||
if ! self.inner().visit_enter_enum_variant(variant, disr_val,
|
||||
n_fields, name) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool {
|
||||
if ! self.inner().visit_enum_variant_field(i, offset, inner) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_leave_enum_variant(&mut self, variant: uint,
|
||||
disr_val: Disr,
|
||||
n_fields: uint,
|
||||
name: &str) -> bool {
|
||||
if ! self.inner().visit_leave_enum_variant(variant, disr_val,
|
||||
n_fields, name) {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_leave_enum(&mut self, n_variants: uint,
|
||||
get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
|
||||
sz: uint, align: uint)
|
||||
-> bool {
|
||||
if ! self.inner().visit_leave_enum(n_variants, get_disr, sz, align) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_trait(&mut self, name: &str) -> bool {
|
||||
self.align_to::<~TyVisitor>();
|
||||
if ! self.inner().visit_trait(name) { return false; }
|
||||
self.bump_past::<~TyVisitor>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, i: uint) -> bool {
|
||||
if ! self.inner().visit_param(i) { return false; }
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_self(&mut self) -> bool {
|
||||
self.align_to::<&'static u8>();
|
||||
if ! self.inner().visit_self() { return false; }
|
||||
self.align_to::<&'static u8>();
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_type(&mut self) -> bool {
|
||||
if ! self.inner().visit_type() { return false; }
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct my_visitor(@RefCell<Stuff>);
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct Stuff {
|
||||
ptr1: *c_void,
|
||||
ptr2: *c_void,
|
||||
vals: ~[~str]
|
||||
}
|
||||
|
||||
impl my_visitor {
|
||||
pub fn get<T:Clone>(&mut self, f: |T|) {
|
||||
unsafe {
|
||||
let my_visitor(s) = *self;
|
||||
f((*((*s).get().ptr1 as *T)).clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_inner(&mut self, inner: *TyDesc) -> bool {
|
||||
unsafe {
|
||||
let my_visitor(s) = *self;
|
||||
let u = my_visitor(s);
|
||||
let mut v = ptr_visit_adaptor::<my_visitor>(Inner {inner: u});
|
||||
visit_tydesc(inner, &mut v as &mut TyVisitor);
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner<V> { inner: V }
|
||||
|
||||
impl movable_ptr for my_visitor {
|
||||
fn move_ptr(&mut self, adjustment: |*c_void| -> *c_void) {
|
||||
let my_visitor(s) = *self;
|
||||
let mut this = s.borrow_mut();
|
||||
this.get().ptr1 = adjustment(this.get().ptr1);
|
||||
this.get().ptr2 = adjustment(this.get().ptr2);
|
||||
}
|
||||
}
|
||||
|
||||
impl TyVisitor for my_visitor {
|
||||
|
||||
fn visit_bot(&mut self) -> bool { true }
|
||||
fn visit_nil(&mut self) -> bool { true }
|
||||
fn visit_bool(&mut self) -> bool {
|
||||
self.get::<bool>(|b| {
|
||||
let my_visitor(s) = *self;
|
||||
let mut this = s.borrow_mut();
|
||||
this.get().vals.push(b.to_str());
|
||||
});
|
||||
true
|
||||
}
|
||||
fn visit_int(&mut self) -> bool {
|
||||
self.get::<int>(|i| {
|
||||
let my_visitor(s) = *self;
|
||||
let mut this = s.borrow_mut();
|
||||
this.get().vals.push(i.to_str());
|
||||
});
|
||||
true
|
||||
}
|
||||
fn visit_i8(&mut self) -> bool { true }
|
||||
fn visit_i16(&mut self) -> bool { true }
|
||||
fn visit_i32(&mut self) -> bool { true }
|
||||
fn visit_i64(&mut self) -> bool { true }
|
||||
|
||||
fn visit_uint(&mut self) -> bool { true }
|
||||
fn visit_u8(&mut self) -> bool { true }
|
||||
fn visit_u16(&mut self) -> bool { true }
|
||||
fn visit_u32(&mut self) -> bool { true }
|
||||
fn visit_u64(&mut self) -> bool { true }
|
||||
|
||||
fn visit_f32(&mut self) -> bool { true }
|
||||
fn visit_f64(&mut self) -> bool { true }
|
||||
|
||||
fn visit_char(&mut self) -> bool { true }
|
||||
|
||||
fn visit_estr_box(&mut self) -> bool { true }
|
||||
fn visit_estr_uniq(&mut self) -> bool { true }
|
||||
fn visit_estr_slice(&mut self) -> bool { true }
|
||||
fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
|
||||
_align: uint) -> bool { true }
|
||||
|
||||
fn visit_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_ptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_rptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
|
||||
fn visit_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_unboxed_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_evec_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint,
|
||||
_mtbl: uint, _inner: *TyDesc) -> bool { true }
|
||||
|
||||
fn visit_enter_rec(&mut self, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
fn visit_rec_field(&mut self, _i: uint, _name: &str,
|
||||
_mtbl: uint, inner: *TyDesc) -> bool {
|
||||
error!("rec field!");
|
||||
self.visit_inner(inner)
|
||||
}
|
||||
fn visit_leave_rec(&mut self, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
|
||||
fn visit_enter_class(&mut self, _name: &str, _named_fields: bool, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
fn visit_class_field(&mut self, _i: uint, _name: &str, _named: bool,
|
||||
_mtbl: uint, inner: *TyDesc) -> bool {
|
||||
self.visit_inner(inner)
|
||||
}
|
||||
fn visit_leave_class(&mut self, _name: &str, _named_fields: bool, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
|
||||
fn visit_enter_tup(&mut self, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
fn visit_tup_field(&mut self, _i: uint, inner: *TyDesc) -> bool {
|
||||
error!("tup field!");
|
||||
self.visit_inner(inner)
|
||||
}
|
||||
fn visit_leave_tup(&mut self, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
|
||||
fn visit_enter_enum(&mut self, _n_variants: uint,
|
||||
_get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
|
||||
_sz: uint, _align: uint) -> bool {
|
||||
// FIXME (#3732): this needs to rewind between enum variants, or something.
|
||||
true
|
||||
}
|
||||
fn visit_enter_enum_variant(&mut self, _variant: uint,
|
||||
_disr_val: Disr,
|
||||
_n_fields: uint,
|
||||
_name: &str) -> bool { true }
|
||||
fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
|
||||
self.visit_inner(inner)
|
||||
}
|
||||
fn visit_leave_enum_variant(&mut self, _variant: uint,
|
||||
_disr_val: Disr,
|
||||
_n_fields: uint,
|
||||
_name: &str) -> bool { true }
|
||||
fn visit_leave_enum(&mut self, _n_variants: uint,
|
||||
_get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
|
||||
_sz: uint, _align: uint) -> bool { true }
|
||||
|
||||
fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
|
||||
_n_inputs: uint, _retstyle: uint) -> bool { true }
|
||||
fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
|
||||
true
|
||||
}
|
||||
fn visit_fn_output(&mut self, _retstyle: uint, _variadic: bool, _inner: *TyDesc) -> bool {
|
||||
true
|
||||
}
|
||||
fn visit_leave_fn(&mut self, _purity: uint, _proto: uint,
|
||||
_n_inputs: uint, _retstyle: uint) -> bool { true }
|
||||
|
||||
|
||||
fn visit_trait(&mut self, _name: &str) -> bool { true }
|
||||
fn visit_param(&mut self, _i: uint) -> bool { true }
|
||||
fn visit_self(&mut self) -> bool { true }
|
||||
fn visit_type(&mut self) -> bool { true }
|
||||
}
|
||||
|
||||
fn get_tydesc_for<T>(_t: T) -> *TyDesc {
|
||||
unsafe {
|
||||
get_tydesc::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
struct Triple { x: int, y: int, z: int }
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let r = (1,2,3,true,false, Triple {x:5,y:4,z:3}, (12,));
|
||||
let p = ptr::to_unsafe_ptr(&r) as *c_void;
|
||||
let u = my_visitor(@RefCell::new(Stuff {ptr1: p,
|
||||
ptr2: p,
|
||||
vals: ~[]}));
|
||||
let mut v = ptr_visit_adaptor(Inner {inner: u});
|
||||
let td = get_tydesc_for(r);
|
||||
error!("tydesc sz: {}, align: {}",
|
||||
(*td).size, (*td).align);
|
||||
visit_tydesc(td, &mut v as &mut TyVisitor);
|
||||
|
||||
let my_visitor(m) = u;
|
||||
let mut ub = m.borrow_mut();
|
||||
let r = ub.get().vals.clone();
|
||||
for s in r.iter() {
|
||||
println!("val: {}", *s);
|
||||
}
|
||||
error!("{:?}", ub.get().vals.clone());
|
||||
assert_eq!(ub.get().vals.clone(),
|
||||
~[ ~"1", ~"2", ~"3", ~"true", ~"false", ~"5", ~"4", ~"3", ~"12"]);
|
||||
}
|
||||
}
|
@ -18,8 +18,11 @@ fn box_it<'r>(x: 'r ||) -> closure_box<'r> {
|
||||
|
||||
pub fn main() {
|
||||
let mut i = 3;
|
||||
let cl_box = box_it(|| i += 1);
|
||||
assert_eq!(i, 3);
|
||||
(cl_box.cl)();
|
||||
{
|
||||
let cl = || i += 1;
|
||||
let cl_box = box_it(cl);
|
||||
(cl_box.cl)();
|
||||
}
|
||||
assert_eq!(i, 4);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user