Skip to content

Commit

Permalink
rustc: allow @ as-patterns to move when the sub-pattern contains no b…
Browse files Browse the repository at this point in the history
…indings.

A pattern like `foo @ Foo(Bar(*), _)` should be legal, even if `foo` moves,
since the subpatterns are purely structural.

Fixes rust-lang#3761.
  • Loading branch information
huonw committed Aug 14, 2013
1 parent e86d414 commit 9d67df6
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
15 changes: 15 additions & 0 deletions src/librustc/middle/pat_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
30 changes: 30 additions & 0 deletions src/test/run-pass/bind-by-move-nonident-subpattern.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 */ }
}
}

4 comments on commit 9d67df6

@pnkfelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huonw mind adding a compile-fail case for the sub-pattern contains a binding?

@huonw
Copy link
Owner Author

@huonw huonw commented on 9d67df6 Aug 14, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pnkfelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huonw ah sorry, I should have looked.

@pnkfelix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+

Please sign in to comment.