about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/check_match.rs4
-rw-r--r--src/librustc/middle/pat_util.rs15
2 files changed, 18 insertions, 1 deletions
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 37f45142a11..9719460bbd3 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -879,7 +879,9 @@ pub fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
 
     let check_move: &fn(@pat, Option<@pat>) = |p, sub| {
         // check legality of moving out of the enum
-        if sub.is_some() {
+
+        // x @ Foo(*) is legal, but x @ Foo(y) isn't.
+        if sub.map_move_default(false, |p| pat_contains_bindings(def_map, p)) {
             tcx.sess.span_err(
                 p.span,
                 "cannot bind by-move with sub-bindings");
diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs
index 9bf14697d9a..a67a488ef30 100644
--- a/src/librustc/middle/pat_util.rs
+++ b/src/librustc/middle/pat_util.rs
@@ -88,3 +88,18 @@ pub fn pat_binding_ids(dm: resolve::DefMap, pat: @pat) -> ~[NodeId] {
     pat_bindings(dm, pat, |_bm, b_id, _sp, _pt| found.push(b_id) );
     return found;
 }
+
+/// Checks if the pattern contains any patterns that bind something to
+/// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(*)`.
+pub fn pat_contains_bindings(dm: resolve::DefMap, pat: @pat) -> bool {
+    let mut contains_bindings = false;
+    do walk_pat(pat) |p| {
+        if pat_is_binding(dm, p) {
+            contains_bindings = true;
+            false // there's at least one binding, can short circuit now.
+        } else {
+            true
+        }
+    };
+    contains_bindings
+}