about summary refs log tree commit diff
path: root/src/rustc
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2012-08-22 19:00:28 -0400
committerBen Blum <bblum@andrew.cmu.edu>2012-08-22 20:40:25 -0400
commit5b25fc918a8b91322c28242d3956109001b0f7c4 (patch)
treec02331c20638ff3602959b9c80aaea60e845ea12 /src/rustc
parent1b804ce343a79fec2b08b88740782c1e8c081417 (diff)
Parse and typecheck moving out of enums (#2329)
Diffstat (limited to 'src/rustc')
-rw-r--r--src/rustc/middle/borrowck/gather_loans.rs3
-rw-r--r--src/rustc/middle/lint.rs2
-rw-r--r--src/rustc/middle/mem_categorization.rs1
-rw-r--r--src/rustc/middle/trans/alt.rs5
-rw-r--r--src/rustc/middle/typeck/check.rs5
-rw-r--r--src/rustc/middle/typeck/check/alt.rs46
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);
           }
         }