From 9d67df61d2dd2bc359767b1ba7892b0c4b17464b Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 14 Aug 2013 19:04:41 +1000 Subject: [PATCH] rustc: allow @ as-patterns to move when the sub-pattern contains no bindings. A pattern like `foo @ Foo(Bar(*), _)` should be legal, even if `foo` moves, since the subpatterns are purely structural. Fixes #3761. --- src/librustc/middle/check_match.rs | 4 ++- src/librustc/middle/pat_util.rs | 15 ++++++++++ .../bind-by-move-nonident-subpattern.rs | 30 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/bind-by-move-nonident-subpattern.rs diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 37f45142a1107..9719460bbd33e 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 9bf14697d9ad7..a67a488ef30fc 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 +} diff --git a/src/test/run-pass/bind-by-move-nonident-subpattern.rs b/src/test/run-pass/bind-by-move-nonident-subpattern.rs new file mode 100644 index 0000000000000..7cbaf28faa192 --- /dev/null +++ b/src/test/run-pass/bind-by-move-nonident-subpattern.rs @@ -0,0 +1,30 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #3761 + +struct Foo(~str); + +enum Tree { + Leaf(uint), + Node(~Tree, ~Tree) +} + +fn main() { + match Foo(~"hi") { + _msg @ Foo(_) => {} + } + + match Node(~Node(~Leaf(1), ~Leaf(2)), ~Leaf(3)) { + leaf @ Leaf(*) => { fail!() } + two_subnodes @ Node(~Node(*), ~Node(*)) => { fail!() } + other @ Node(_, _) => { /* ok */ } + } +}