diff options
| author | Ben Blum <bblum@andrew.cmu.edu> | 2012-08-22 19:00:28 -0400 |
|---|---|---|
| committer | Ben Blum <bblum@andrew.cmu.edu> | 2012-08-22 20:40:25 -0400 |
| commit | 5b25fc918a8b91322c28242d3956109001b0f7c4 (patch) | |
| tree | c02331c20638ff3602959b9c80aaea60e845ea12 /src/rustc | |
| parent | 1b804ce343a79fec2b08b88740782c1e8c081417 (diff) | |
Parse and typecheck moving out of enums (#2329)
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/middle/borrowck/gather_loans.rs | 3 | ||||
| -rw-r--r-- | src/rustc/middle/lint.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/mem_categorization.rs | 1 | ||||
| -rw-r--r-- | src/rustc/middle/trans/alt.rs | 5 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check.rs | 5 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check/alt.rs | 46 |
6 files changed, 55 insertions, 7 deletions
diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index c0d7521e9f2..31ef79aa616 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -412,9 +412,10 @@ impl gather_loan_ctxt { match pat.node { ast::pat_ident(bm, id, o_pat) if !self.pat_is_variant(pat) => { match bm { - ast::bind_by_value => { + ast::bind_by_value | ast::bind_by_move => { // copying does not borrow anything, so no check // is required + // as for move, check::alt ensures it's from an rvalue. } ast::bind_by_ref(mutbl) => { // ref x or ref x @ p --- creates a ptr which must diff --git a/src/rustc/middle/lint.rs b/src/rustc/middle/lint.rs index ff97f759268..d2d103952f0 100644 --- a/src/rustc/middle/lint.rs +++ b/src/rustc/middle/lint.rs @@ -490,7 +490,7 @@ fn check_pat(tcx: ty::ctxt, pat: @ast::pat) { do pat_bindings(tcx.def_map, pat) |binding_mode, id, span, path| { match binding_mode { - ast::bind_by_ref(_) | ast::bind_by_value => {} + ast::bind_by_ref(_) | ast::bind_by_value | ast::bind_by_move => {} ast::bind_by_implicit_ref => { let pat_ty = ty::node_id_to_type(tcx, id); let kind = ty::type_kind(tcx, pat_ty); diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs index 8d5be4aa063..7a14e9afe07 100644 --- a/src/rustc/middle/mem_categorization.rs +++ b/src/rustc/middle/mem_categorization.rs @@ -409,6 +409,7 @@ impl &mem_categorization_ctxt { } ast::def_binding(vid, ast::bind_by_value) | + ast::def_binding(vid, ast::bind_by_move) | ast::def_binding(vid, ast::bind_by_ref(_)) => { // by-value/by-ref bindings are local variables @{id:id, span:span, diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index 40623e9af93..13bbfabd0ca 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -474,6 +474,8 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef], load_if_immediate(bcx, llval, ty), ty); bcx.fcx.lllocals.insert(val, local_mem(alloc)); add_clean(bcx, alloc, ty); + } else if mode == ast::bind_by_move { + fail ~"can't translate bind_by_move into a pattern guard"; } else { bcx.fcx.lllocals.insert(val, local_mem(llval)); } @@ -803,6 +805,9 @@ fn make_pattern_bindings(bcx: block, phi_bindings: phi_bindings_list) local_mem(allocation)); add_clean(bcx, allocation, ty); } + ast::bind_by_move => { + fail ~"unimplemented -- bblum"; + } } } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 9dd5af2cf10..87817bd2e07 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -2035,7 +2035,10 @@ fn check_decl_local(fcx: @fn_ctxt, local: @ast::local) -> bool { map: pat_id_map(fcx.ccx.tcx.def_map, local.node.pat), alt_region: region, block_region: region, - pat_region: region + pat_region: region, + matching_lvalue: true, // FIXME(#3235) Make this more flexible + has_guard: false, + mut ever_bound_by_ref: false, }; alt::check_pat(pcx, local.node.pat, t); return bot; diff --git a/src/rustc/middle/typeck/check/alt.rs b/src/rustc/middle/typeck/check/alt.rs index 83f62b7a6f1..a38e42ff076 100644 --- a/src/rustc/middle/typeck/check/alt.rs +++ b/src/rustc/middle/typeck/check/alt.rs @@ -9,6 +9,7 @@ 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(fcx.ccx.method_map, discrim); // Typecheck the patterns first, so that we get types for all the // bindings. @@ -18,7 +19,12 @@ fn check_alt(fcx: @fn_ctxt, map: pat_id_map(tcx.def_map, arm.pats[0]), alt_region: ty::re_scope(expr.id), block_region: ty::re_scope(arm.body.node.id), - pat_region: ty::re_scope(expr.id) + pat_region: ty::re_scope(expr.id), + // The following three fields determine whether 'move' is allowed. + matching_lvalue: is_lvalue, + has_guard: arm.guard.is_some(), + // Each arm is freshly allowed to decide whether it can 'move'. + mut ever_bound_by_ref: false, }; for arm.pats.each |p| { check_pat(pcx, p, pattern_ty);} @@ -47,7 +53,14 @@ type pat_ctxt = { alt_region: ty::region, block_region: ty::region, /* Equal to either alt_region or block_region. */ - pat_region: ty::region + pat_region: ty::region, + /* Moving out is only permitted when matching rvalues. */ + matching_lvalue: bool, + /* Moving out is not permitted with guards. */ + has_guard: bool, + /* If a pattern binding binds by-reference ever, then binding by-move in + * the same arm is disallowed (no "ref x @ some(move y)", etc etc). */ + mut ever_bound_by_ref: bool, }; fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, @@ -161,6 +174,7 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { match bm { ast::bind_by_ref(mutbl) => { + pcx.ever_bound_by_ref = true; // if the binding is like // ref x | ref const x | ref mut x // then the type of x is &M T where M is the mutability @@ -172,8 +186,32 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { let region_ty = ty::mk_rptr(tcx, region_var, mt); demand::eqtype(fcx, pat.span, region_ty, typ); } - ast::bind_by_value | ast::bind_by_implicit_ref => { - // otherwise the type of x is the expected type T + // otherwise the type of x is the expected type T + ast::bind_by_value => { + demand::eqtype(fcx, pat.span, expected, typ); + } + ast::bind_by_move => { + demand::eqtype(fcx, pat.span, expected, typ); + // check legality of moving out of the enum + if sub.is_some() { + tcx.sess.span_err(pat.span, + ~"cannot bind by-move with sub-bindings"); + } + if pcx.has_guard { + tcx.sess.span_err(pat.span, + ~"cannot bind by-move into a pattern guard"); + } + if pcx.ever_bound_by_ref { + tcx.sess.span_err(pat.span, + ~"cannot bind by-move and by-ref in the same pattern"); + } + if pcx.matching_lvalue { + tcx.sess.span_err(pat.span, + ~"cannot bind by-move when matching an lvalue"); + } + } + ast::bind_by_implicit_ref => { + pcx.ever_bound_by_ref = true; demand::eqtype(fcx, pat.span, expected, typ); } } |
