diff --git a/src/librustc/middle/check_alt.rs b/src/librustc/middle/check_alt.rs index 840107227f0d..f5a57c520d5f 100644 --- a/src/librustc/middle/check_alt.rs +++ b/src/librustc/middle/check_alt.rs @@ -9,7 +9,7 @@ // except according to those terms. use syntax::ast::*; -use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat}; +use syntax::ast_util::{variant_def_ids, dummy_sp, unguarded_pat, walk_pat}; use const_eval::{eval_const_expr, const_val, const_int, const_bool, compare_const_vals, lookup_const_by_id}; use syntax::codemap::span; @@ -43,6 +43,15 @@ fn check_expr(cx: @AltCheckCtxt, 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_lvalue = ty::expr_is_lval(cx.tcx, cx.method_map, scrut); + for arms.each |arm| { + check_legality_of_move_bindings(cx, + is_lvalue, + arm.guard.is_some(), + arm.pats); + } + check_arms(cx, (*arms)); /* Check for exhaustiveness */ // Check for empty enum, because is_useful only works on inhabited @@ -511,6 +520,13 @@ fn check_local(cx: @AltCheckCtxt, loc: @local, &&s: (), v: visit::vt<()>) { cx.tcx.sess.span_err(loc.node.pat.span, ~"refutable pattern in local binding"); } + + // Check legality of move bindings. + let is_lvalue = match loc.node.init { + Some(init) => ty::expr_is_lval(cx.tcx, cx.method_map, init), + None => true + }; + check_legality_of_move_bindings(cx, is_lvalue, false, [ loc.node.pat ]); } fn check_fn(cx: @AltCheckCtxt, @@ -565,6 +581,67 @@ fn is_refutable(cx: @AltCheckCtxt, pat: &pat) -> bool { } } +// Legality of move bindings checking + +fn check_legality_of_move_bindings(cx: @AltCheckCtxt, + is_lvalue: bool, + has_guard: bool, + pats: &[@pat]) { + let tcx = cx.tcx; + let def_map = tcx.def_map; + let mut by_ref_span = None; + let mut any_by_move = false; + for pats.each |pat| { + do pat_bindings(def_map, *pat) |bm, _id, span, _path| { + match bm { + bind_by_ref(_) | bind_by_implicit_ref => { + by_ref_span = Some(span); + } + bind_by_move => { + any_by_move = true; + } + _ => { } + } + } + } + + if !any_by_move { return; } // pointless micro-optimization + for pats.each |pat| { + do walk_pat(*pat) |p| { + if pat_is_binding(def_map, p) { + match p.node { + pat_ident(bind_by_move, _, sub) => { + // check legality of moving out of the enum + if sub.is_some() { + tcx.sess.span_err( + p.span, + ~"cannot bind by-move with sub-bindings"); + } else if has_guard { + tcx.sess.span_err( + p.span, + ~"cannot bind by-move into a pattern guard"); + } else if by_ref_span.is_some() { + tcx.sess.span_err( + p.span, + ~"cannot bind by-move and by-ref \ + in the same pattern"); + 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"); + } + } + _ => {} + } + } + } + } +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/librustc/middle/typeck/check/alt.rs b/src/librustc/middle/typeck/check/alt.rs index cc47049d675a..46d618aeb505 100644 --- a/src/librustc/middle/typeck/check/alt.rs +++ b/src/librustc/middle/typeck/check/alt.rs @@ -21,7 +21,6 @@ fn check_alt(fcx: @fn_ctxt, let pattern_ty = fcx.infcx().next_ty_var(); bot = check_expr_with(fcx, discrim, pattern_ty); - let is_lvalue = ty::expr_is_lval(tcx, fcx.ccx.method_map, discrim); // Typecheck the patterns first, so that we get types for all the // bindings. @@ -34,10 +33,6 @@ fn check_alt(fcx: @fn_ctxt, }; for arm.pats.each |p| { check_pat(pcx, *p, pattern_ty);} - check_legality_of_move_bindings(fcx, - is_lvalue, - arm.guard.is_some(), - arm.pats); } // Now typecheck the blocks. @@ -58,67 +53,6 @@ fn check_alt(fcx: @fn_ctxt, return bot; } -fn check_legality_of_move_bindings(fcx: @fn_ctxt, - is_lvalue: bool, - has_guard: bool, - pats: &[@ast::pat]) -{ - let tcx = fcx.tcx(); - let def_map = tcx.def_map; - let mut by_ref = None; - let mut any_by_move = false; - for pats.each |pat| { - do pat_util::pat_bindings(def_map, *pat) |bm, _id, span, _path| { - match bm { - ast::bind_by_ref(_) | ast::bind_by_implicit_ref => { - by_ref = Some(span); - } - ast::bind_by_move => { - any_by_move = true; - } - _ => { } - } - } - } - - if !any_by_move { return; } // pointless micro-optimization - for pats.each |pat| { - do walk_pat(*pat) |p| { - if pat_is_binding(def_map, p) { - match p.node { - ast::pat_ident(ast::bind_by_move, _, sub) => { - // check legality of moving out of the enum - if sub.is_some() { - tcx.sess.span_err( - p.span, - ~"cannot bind by-move with sub-bindings"); - } else if has_guard { - tcx.sess.span_err( - p.span, - ~"cannot bind by-move into a pattern guard"); - } else if by_ref.is_some() { - tcx.sess.span_err( - p.span, - ~"cannot bind by-move and by-ref \ - in the same pattern"); - tcx.sess.span_note( - by_ref.get(), - ~"by-ref binding occurs here"); - } else if is_lvalue { - tcx.sess.span_err( - p.span, - ~"cannot bind by-move when \ - matching an lvalue"); - } - } - _ => {} - } - } - } - } -} - - type pat_ctxt = { fcx: @fn_ctxt, map: PatIdMap, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index f62e2e638e44..3b9ad6e7184d 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2399,15 +2399,11 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { let t = ty::mk_var(tcx, fcx.inh.locals.get(local.node.id)); fcx.write_ty(local.node.id, t); - let is_lvalue; match local.node.init { Some(init) => { bot = check_decl_initializer(fcx, local.node.id, init); - is_lvalue = ty::expr_is_lval(tcx, fcx.ccx.method_map, init); - } - _ => { - is_lvalue = true; } + _ => {} } let region = @@ -2419,11 +2415,6 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { block_region: region, }; alt::check_pat(pcx, local.node.pat, t); - let has_guard = false; - alt::check_legality_of_move_bindings(fcx, - is_lvalue, - has_guard, - [local.node.pat]); return bot; }