diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index b2e303d40ee..a455bdc436c 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -65,7 +65,7 @@ pub fn check_loans(bccx: @BorrowckCtxt, enum MoveError { MoveOk, - MoveWhileBorrowed(/*move*/@LoanPath, /*loan*/@LoanPath, /*loan*/span) + MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span) } impl<'self> CheckLoanCtxt<'self> { @@ -348,7 +348,7 @@ impl<'self> CheckLoanCtxt<'self> { cmt = b; } - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_implicit_self | mc::cat_copied_upvar(*) | @@ -547,45 +547,50 @@ impl<'self> CheckLoanCtxt<'self> { self.bccx.loan_path_to_str(loan_path))); } - pub fn check_move_out_from_expr(&self, ex: @ast::expr) { - match ex.node { - ast::expr_paren(*) => { - /* In the case of an expr_paren(), the expression inside - * the parens will also be marked as being moved. Ignore - * the parents then so as not to report duplicate errors. */ + fn check_move_out_from_expr(&self, expr: @ast::expr) { + match expr.node { + ast::expr_fn_block(*) => { + // moves due to capture clauses are checked + // in `check_loans_in_fn`, so that we can + // give a better error message } _ => { - let cmt = self.bccx.cat_expr(ex); - match self.analyze_move_out_from_cmt(cmt) { - MoveOk => {} - MoveWhileBorrowed(move_path, loan_path, loan_span) => { - self.bccx.span_err( - cmt.span, - fmt!("cannot move out of `%s` \ - because it is borrowed", - self.bccx.loan_path_to_str(move_path))); - self.bccx.span_note( - loan_span, - fmt!("borrow of `%s` occurs here", - self.bccx.loan_path_to_str(loan_path))); - } + self.check_move_out_from_id(expr.id, expr.span) + } + } + } + + fn check_move_out_from_id(&self, id: ast::node_id, span: span) { + for self.move_data.each_path_moved_by(id) |_, move_path| { + match self.analyze_move_out_from(id, move_path) { + MoveOk => {} + MoveWhileBorrowed(loan_path, loan_span) => { + self.bccx.span_err( + span, + fmt!("cannot move out of `%s` \ + because it is borrowed", + self.bccx.loan_path_to_str(move_path))); + self.bccx.span_note( + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); } } } } - pub fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError { - debug!("analyze_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx())); + pub fn analyze_move_out_from(&self, + expr_id: ast::node_id, + move_path: @LoanPath) -> MoveError { + debug!("analyze_move_out_from(expr_id=%?, move_path=%s)", + expr_id, move_path.repr(self.tcx())); // FIXME(#4384) inadequare if/when we permit `move a.b` // check for a conflicting loan: - let r = opt_loan_path(cmt); - for r.iter().advance |&lp| { - for self.each_in_scope_restriction(cmt.id, lp) |loan, _| { - // Any restriction prevents moves. - return MoveWhileBorrowed(lp, loan.loan_path, loan.span); - } + for self.each_in_scope_restriction(expr_id, move_path) |loan, _| { + // Any restriction prevents moves. + return MoveWhileBorrowed(loan.loan_path, loan.span); } MoveOk @@ -652,13 +657,11 @@ fn check_loans_in_fn<'a>(fk: &visit::fn_kind, closure_id: ast::node_id, cap_var: &moves::CaptureVar) { let var_id = ast_util::def_id_of_def(cap_var.def).node; - let ty = ty::node_id_to_type(this.tcx(), var_id); - let cmt = this.bccx.cat_def(closure_id, cap_var.span, - ty, cap_var.def); - let move_err = this.analyze_move_out_from_cmt(cmt); + let move_path = @LpVar(var_id); + let move_err = this.analyze_move_out_from(closure_id, move_path); match move_err { MoveOk => {} - MoveWhileBorrowed(move_path, loan_path, loan_span) => { + MoveWhileBorrowed(loan_path, loan_span) => { this.bccx.span_err( cap_var.span, fmt!("cannot move `%s` into closure \ @@ -689,10 +692,7 @@ fn check_loans_in_expr<'a>(expr: @ast::expr, expr.repr(this.tcx())); this.check_for_conflicting_loans(expr.id); - - if this.bccx.moves_map.contains(&expr.id) { - this.check_move_out_from_expr(expr); - } + this.check_move_out_from_expr(expr); match expr.node { ast::expr_self | @@ -742,18 +742,7 @@ fn check_loans_in_pat<'a>(pat: @ast::pat, visit::vt<@mut CheckLoanCtxt<'a>>)) { this.check_for_conflicting_loans(pat.id); - - // Note: moves out of pattern bindings are not checked by - // the borrow checker, at least not directly. What happens - // is that if there are any moved bindings, the discriminant - // will be considered a move, and this will be checked as - // normal. Then, in `middle::check_match`, we will check - // that no move occurs in a binding that is underneath an - // `@` or `&`. Together these give the same guarantees as - // `check_move_out_from_expr()` without requiring us to - // rewalk the patterns and rebuild the pattern - // categorizations. - + this.check_move_out_from_id(pat.id, pat.span); visit::visit_pat(pat, (this, vt)); } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 05fc139305c..5d91916d004 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -67,7 +67,7 @@ impl GuaranteeLifetimeContext { //! Main routine. Walks down `cmt` until we find the "guarantor". match cmt.cat { - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_implicit_self | mc::cat_copied_upvar(*) | // L-Local mc::cat_local(*) | // L-Local @@ -179,7 +179,7 @@ impl GuaranteeLifetimeContext { //! lvalue. cmt.mutbl.is_immutable() || match cmt.guarantor().cat { - mc::cat_rvalue => true, + mc::cat_rvalue(*) => true, _ => false } } @@ -299,7 +299,7 @@ impl GuaranteeLifetimeContext { mc::cat_arg(id) => { self.bccx.moved_variables_set.contains(&id) } - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_implicit_self | mc::cat_copied_upvar(*) | @@ -325,8 +325,8 @@ impl GuaranteeLifetimeContext { // See the SCOPE(LV) function in doc.rs match cmt.cat { - mc::cat_rvalue => { - ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id)) + mc::cat_rvalue(cleanup_scope_id) => { + ty::re_scope(cleanup_scope_id) } mc::cat_implicit_self | mc::cat_copied_upvar(_) => { diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 26fa4924ccb..86baf535284 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -73,6 +73,7 @@ struct GatherLoanCtxt { } pub fn gather_loans(bccx: @BorrowckCtxt, + decl: &ast::fn_decl, body: &ast::blk) -> (id_range, @mut ~[Loan], @mut move_data::MoveData) { let glcx = @mut GatherLoanCtxt { @@ -83,6 +84,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt, repeating_ids: ~[body.node.id], move_data: @mut MoveData::new() }; + glcx.gather_fn_arg_patterns(decl, body); let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, visit_block: gather_loans_in_block, visit_fn: gather_loans_in_fn, @@ -124,6 +126,7 @@ fn gather_loans_in_fn(fk: &visit::fn_kind, this.push_repeating_id(body.node.id); visit::visit_fn(fk, decl, body, sp, id, (this, v)); this.pop_repeating_id(body.node.id); + this.gather_fn_arg_patterns(decl, body); } } } @@ -138,26 +141,33 @@ fn gather_loans_in_block(blk: &ast::blk, fn gather_loans_in_local(local: @ast::local, (this, vt): (@mut GatherLoanCtxt, visit::vt<@mut GatherLoanCtxt>)) { - if local.node.init.is_none() { - // Variable declarations without initializers are considered "moves": - let tcx = this.bccx.tcx; - do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| { - gather_moves::gather_decl(this.bccx, - this.move_data, - id, - span, - id); + match local.node.init { + None => { + // Variable declarations without initializers are considered "moves": + let tcx = this.bccx.tcx; + do pat_util::pat_bindings(tcx.def_map, local.node.pat) + |_, id, span, _| { + gather_moves::gather_decl(this.bccx, + this.move_data, + id, + span, + id); + } } - } else { - // Variable declarations with initializers are considered "assigns": - let tcx = this.bccx.tcx; - do pat_util::pat_bindings(tcx.def_map, local.node.pat) |_, id, span, _| { - gather_moves::gather_assignment(this.bccx, - this.move_data, - id, - span, - @LpVar(id), - id); + Some(init) => { + // Variable declarations with initializers are considered "assigns": + let tcx = this.bccx.tcx; + do pat_util::pat_bindings(tcx.def_map, local.node.pat) + |_, id, span, _| { + gather_moves::gather_assignment(this.bccx, + this.move_data, + id, + span, + @LpVar(id), + id); + } + let init_cmt = this.bccx.cat_expr(init); + this.gather_pat(init_cmt, local.node.pat, None); } } @@ -230,7 +240,7 @@ fn gather_loans_in_expr(ex: @ast::expr, let cmt = this.bccx.cat_expr(ex_v); for arms.iter().advance |arm| { for arm.pats.iter().advance |pat| { - this.gather_pat(cmt, *pat, arm.body.node.id, ex.id); + this.gather_pat(cmt, *pat, Some((arm.body.node.id, ex.id))); } } visit::visit_expr(ex, (this, vt)); @@ -596,11 +606,40 @@ impl GatherLoanCtxt { } } - pub fn gather_pat(&mut self, - discr_cmt: mc::cmt, - root_pat: @ast::pat, - arm_body_id: ast::node_id, - match_id: ast::node_id) { + fn gather_fn_arg_patterns(&mut self, + decl: &ast::fn_decl, + body: &ast::blk) { + /*! + * Walks the patterns for fn arguments, checking that they + * do not attempt illegal moves or create refs that outlive + * the arguments themselves. Just a shallow wrapper around + * `gather_pat()`. + */ + + let mc_ctxt = self.bccx.mc_ctxt(); + for decl.inputs.each |arg| { + let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id); + + let arg_cmt = mc_ctxt.cat_rvalue( + arg.id, + arg.pat.span, + body.node.id, // Arguments live only as long as the fn body. + arg_ty); + + self.gather_pat(arg_cmt, arg.pat, None); + } + } + + fn gather_pat(&mut self, + discr_cmt: mc::cmt, + root_pat: @ast::pat, + arm_match_ids: Option<(ast::node_id, ast::node_id)>) { + /*! + * Walks patterns, examining the bindings to determine if they + * cause borrows (`ref` bindings, vector patterns) or + * moves (non-`ref` bindings with linear type). + */ + do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { match pat.node { ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { @@ -621,15 +660,19 @@ impl GatherLoanCtxt { // with a cat_discr() node. There is a detailed // discussion of the function of this node in // `lifetime.rs`: - let arm_scope = ty::re_scope(arm_body_id); - if self.bccx.is_subregion_of(scope_r, arm_scope) { - let cmt_discr = self.bccx.cat_discr(cmt, match_id); - self.guarantee_valid(pat.id, pat.span, - cmt_discr, mutbl, scope_r); - } else { - self.guarantee_valid(pat.id, pat.span, - cmt, mutbl, scope_r); - } + let cmt_discr = match arm_match_ids { + None => cmt, + Some((arm_id, match_id)) => { + let arm_scope = ty::re_scope(arm_id); + if self.bccx.is_subregion_of(scope_r, arm_scope) { + self.bccx.cat_discr(cmt, match_id) + } else { + cmt + } + } + }; + self.guarantee_valid(pat.id, pat.span, + cmt_discr, mutbl, scope_r); } ast::bind_infer => { // No borrows here, but there may be moves @@ -652,6 +695,24 @@ impl GatherLoanCtxt { self.vec_slice_info(slice_pat, slice_ty); let mcx = self.bccx.mc_ctxt(); let cmt_index = mcx.cat_index(slice_pat, cmt, 0); + + // Note: We declare here that the borrow occurs upon + // entering the `[...]` pattern. This implies that + // something like `[a, ..b]` where `a` is a move is + // illegal, because the borrow is already in effect. + // In fact such a move would be safe-ish, but it + // effectively *requires* that we use the nulling + // out semantics to indicate when a value has been + // moved, which we are trying to move away from. + // Otherwise, how can we indicate that the first + // element in the vector has been moved? + // Eventually, we could perhaps modify this rule to + // permit `[..a, b]` where `b` is a move, because in + // that case we can adjust the length of the + // original vec accordingly, but we'd have to make + // 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_mutbl, slice_r); } diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index d5377aeb618..e568da5eedf 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -64,7 +64,7 @@ impl RestrictionsContext { } match cmt.cat { - mc::cat_rvalue => { + mc::cat_rvalue(*) => { // Effectively, rvalues are stored into a // non-aliasable temporary on the stack. Since they // are inherently non-aliasable, they can only be diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 2e3813f57e0..47d35d73df0 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -124,7 +124,7 @@ fn borrowck_fn(fk: &visit::fn_kind, // Check the body of fn items. let (id_range, all_loans, move_data) = - gather_loans::gather_loans(this, body); + gather_loans::gather_loans(this, decl, body); let mut loan_dfcx = DataFlowContext::new(this.tcx, this.method_map, @@ -264,7 +264,7 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { //! traverses the CMT. match cmt.cat { - mc::cat_rvalue | + mc::cat_rvalue(*) | mc::cat_static_item | mc::cat_copied_upvar(_) | mc::cat_implicit_self => { @@ -485,7 +485,7 @@ impl BorrowckCtxt { pub fn mc_ctxt(&self) -> mc::mem_categorization_ctxt { mc::mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map} + method_map: self.method_map} } pub fn cat_pattern(&self, diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index 73adade7a5d..7ec1ff3c628 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -474,6 +474,24 @@ impl FlowedMoveData { } } + pub fn each_path_moved_by(&self, + id: ast::node_id, + f: &fn(&Move, @LoanPath) -> bool) + -> bool { + /*! + * Iterates through each path moved by `id` + */ + + for self.dfcx_moves.each_gen_bit_frozen(id) |index| { + let move = &self.move_data.moves[index]; + let moved_path = move.path; + if !f(move, self.move_data.path(moved_path).loan_path) { + return false; + } + } + return true; + } + pub fn each_move_of(&self, id: ast::node_id, loan_path: @LoanPath, diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 0baeb8ce57c..02f7294ffcd 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -49,23 +49,13 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); } -pub fn expr_is_non_moving_lvalue(cx: &MatchCheckCtxt, expr: &expr) -> bool { - if !ty::expr_is_lval(cx.tcx, cx.method_map, expr) { - return false; - } - - !cx.moves_map.contains(&expr.id) -} - pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, (s, v): ((), visit::vt<()>)) { visit::visit_expr(ex, (s, v)); match ex.node { expr_match(scrut, ref arms) => { // First, check legality of move bindings. - let is_non_moving_lvalue = expr_is_non_moving_lvalue(cx, ex); for arms.iter().advance |arm| { check_legality_of_move_bindings(cx, - is_non_moving_lvalue, arm.guard.is_some(), arm.pats); } @@ -758,11 +748,7 @@ pub fn check_local(cx: &MatchCheckCtxt, } // Check legality of move bindings. - let is_lvalue = match loc.node.init { - Some(init) => expr_is_non_moving_lvalue(cx, init), - None => true - }; - check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]); + check_legality_of_move_bindings(cx, false, [ loc.node.pat ]); } pub fn check_fn(cx: &MatchCheckCtxt, @@ -821,7 +807,6 @@ pub fn is_refutable(cx: &MatchCheckCtxt, pat: &pat) -> bool { // Legality of move bindings checking pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, - is_lvalue: bool, has_guard: bool, pats: &[@pat]) { let tcx = cx.tcx; @@ -861,11 +846,6 @@ pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, tcx.sess.span_note( by_ref_span.get(), "by-ref binding occurs here"); - } else if is_lvalue { - tcx.sess.span_err( - p.span, - "cannot bind by-move when \ - matching an lvalue"); } }; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index e054b84984d..ec375eaba0e 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -422,8 +422,8 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { loop_scopes: &mut ~[LoopScope]) { match decl.node { ast::decl_local(local) => { - self.walk_pat(local.node.pat, in_out, loop_scopes); self.walk_opt_expr(local.node.init, in_out, loop_scopes); + self.walk_pat(local.node.pat, in_out, loop_scopes); } ast::decl_item(_) => {} diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index fd36858ba68..ac7805146e4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -60,7 +60,7 @@ use syntax::print::pprust; #[deriving(Eq)] pub enum categorization { - cat_rvalue, // result of eval'ing some misc expr + cat_rvalue(ast::node_id), // temporary val, argument is its scope cat_static_item, cat_implicit_self, cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env @@ -350,7 +350,7 @@ impl mem_categorization_ctxt { // Convert a bare fn to a closure by adding NULL env. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) + self.cat_rvalue_node(expr, expr_ty) } Some( @@ -360,7 +360,7 @@ impl mem_categorization_ctxt { // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) + self.cat_rvalue_node(expr, expr_ty) } Some( @@ -390,7 +390,7 @@ impl mem_categorization_ctxt { match expr.node { ast::expr_unary(_, ast::deref, e_base) => { if self.method_map.contains_key(&expr.id) { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } let base_cmt = self.cat_expr(e_base); @@ -408,7 +408,7 @@ impl mem_categorization_ctxt { ast::expr_index(_, base, _) => { if self.method_map.contains_key(&expr.id) { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } let base_cmt = self.cat_expr(base); @@ -433,7 +433,7 @@ impl mem_categorization_ctxt { ast::expr_match(*) | ast::expr_lit(*) | ast::expr_break(*) | ast::expr_mac(*) | ast::expr_again(*) | ast::expr_struct(*) | ast::expr_repeat(*) | ast::expr_inline_asm(*) => { - return self.cat_rvalue(expr, expr_ty); + return self.cat_rvalue_node(expr, expr_ty); } } } @@ -577,11 +577,24 @@ impl mem_categorization_ctxt { } } - pub fn cat_rvalue(&self, elt: N, expr_ty: ty::t) -> cmt { + pub fn cat_rvalue_node(&self, + node: N, + expr_ty: ty::t) -> cmt { + self.cat_rvalue(node.id(), + node.span(), + self.tcx.region_maps.cleanup_scope(node.id()), + expr_ty) + } + + pub fn cat_rvalue(&self, + cmt_id: ast::node_id, + span: span, + cleanup_scope_id: ast::node_id, + expr_ty: ty::t) -> cmt { @cmt_ { - id:elt.id(), - span:elt.span(), - cat:cat_rvalue, + id:cmt_id, + span:span, + cat:cat_rvalue(cleanup_scope_id), mutbl:McDeclared, ty:expr_ty } @@ -970,7 +983,7 @@ impl mem_categorization_ctxt { } for slice.iter().advance |&slice_pat| { let slice_ty = self.pat_ty(slice_pat); - let slice_cmt = self.cat_rvalue(pat, slice_ty); + let slice_cmt = self.cat_rvalue_node(pat, slice_ty); self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y)); } for after.iter().advance |&after_pat| { @@ -1003,7 +1016,7 @@ impl mem_categorization_ctxt { cat_copied_upvar(_) => { ~"captured outer variable in a heap closure" } - cat_rvalue => { + cat_rvalue(*) => { ~"non-lvalue" } cat_local(_) => { @@ -1100,7 +1113,7 @@ impl cmt_ { //! determines how long the value in `self` remains live. match self.cat { - cat_rvalue | + cat_rvalue(*) | cat_static_item | cat_implicit_self | cat_copied_upvar(*) | @@ -1187,11 +1200,13 @@ impl Repr for categorization { match *self { cat_static_item | cat_implicit_self | - cat_rvalue | + cat_rvalue(*) | cat_copied_upvar(*) | cat_local(*) | cat_self(*) | - cat_arg(*) => fmt!("%?", *self), + cat_arg(*) => { + fmt!("%?", *self) + } cat_deref(cmt, derefs, ptr) => { fmt!("%s->(%s, %u)", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs) @@ -1205,7 +1220,9 @@ impl Repr for categorization { fmt!("%s->(enum)", cmt.cat.repr(tcx)) } cat_stack_upvar(cmt) | - cat_discr(cmt, _) => cmt.cat.repr(tcx) + cat_discr(cmt, _) => { + cmt.cat.repr(tcx) + } } } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index f3d4abcdf31..e9a73a513c8 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -190,10 +190,19 @@ enum UseMode { pub fn compute_moves(tcx: ty::ctxt, method_map: method_map, +<<<<<<< HEAD crate: &crate) -> MoveMaps { +||||||| merged common ancestors + crate: @crate) -> MoveMaps +{ +======= + crate: @crate) -> MoveMaps { +>>>>>>> Modify borrow checker to visit irrefutable patterns that appear in let visitor = visit::mk_vt(@visit::Visitor { + visit_fn: compute_modes_for_fn, visit_expr: compute_modes_for_expr, + visit_local: compute_modes_for_local, .. *visit::default_visitor() }); let visit_cx = VisitContext { @@ -220,9 +229,31 @@ pub fn moved_variable_node_id_from_def(def: def) -> Option { } } -// ______________________________________________________________________ +/////////////////////////////////////////////////////////////////////////// // Expressions +fn compute_modes_for_local<'a>(local: @local, + (cx, v): (VisitContext, + vt)) { + cx.use_pat(local.node.pat); + for local.node.init.iter().advance |&init| { + cx.use_expr(init, Read, v); + } +} + +fn compute_modes_for_fn(fk: &visit::fn_kind, + decl: &fn_decl, + body: &blk, + span: span, + id: node_id, + (cx, v): (VisitContext, + vt)) { + for decl.inputs.each |a| { + cx.use_pat(a.pat); + } + visit::visit_fn(fk, decl, body, span, id, (cx, v)); +} + fn compute_modes_for_expr(expr: @expr, (cx, v): (VisitContext, vt)) @@ -522,7 +553,10 @@ impl VisitContext { self.use_expr(base, comp_mode, visitor); } - expr_fn_block(_, ref body) => { + expr_fn_block(ref decl, ref body) => { + for decl.inputs.each |a| { + self.use_pat(a.pat); + } let cap_vars = self.compute_captures(expr.id); self.move_maps.capture_map.insert(expr.id, cap_vars); self.consume_block(body, visitor); @@ -580,13 +614,15 @@ impl VisitContext { * into itself or not based on its type and annotation. */ - do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, _path| { + do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| { let binding_moves = match bm { bind_by_ref(_) => false, bind_infer => { let pat_ty = ty::node_id_to_type(self.tcx, id); - debug!("pattern %? type is %s", - id, pat_ty.repr(self.tcx)); + debug!("pattern %? %s type is %s", + id, + ast_util::path_to_ident(path).repr(self.tcx), + pat_ty.repr(self.tcx)); ty::type_moves_by_default(self.tcx, pat_ty) } }; diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 1f7946576db..ac7a9db99e9 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -158,9 +158,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, None => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"a structure pattern", None); fcx.write_error(pat.id); @@ -200,9 +200,9 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path, _ => { fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"an enum or structure pattern", None); fcx.write_error(pat.id); @@ -534,9 +534,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { _ => ty::terr_mismatch }; fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); + *e, actual)})}, Some(expected), ~"tuple", Some(&type_error)); fcx.write_error(pat.id); } } @@ -583,9 +583,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { fcx.infcx().type_error_message_str_with_expected( pat.span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), ~"a vector pattern", None); @@ -641,9 +641,9 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.infcx().type_error_message_str_with_expected( span, |expected, actual| { - expected.map_default(~"", |&e| { + expected.map_default(~"", |e| { fmt!("mismatched types: expected `%s` but found %s", - e, actual)})}, + *e, actual)})}, Some(expected), fmt!("%s pattern", match pointer_kind { Managed => "an @-box", diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index e5248e01ed7..d59c8e5e894 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -350,10 +350,7 @@ pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt, self_info.self_id); } for decl.inputs.iter().advance |arg| { - do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat) - |_bm, pat_id, span, _path| { - resolve_type_vars_for_node(wbcx, span, pat_id); - } + (visit.visit_pat)(arg.pat, (wbcx, visit)); // Privacy needs the type for the whole pattern, not just each binding if !pat_util::pat_is_binding(fcx.tcx().def_map, arg.pat) { resolve_type_vars_for_node(wbcx, arg.pat.span, arg.pat.id);