Collect move errors before reporting

This commit changes the way move errors are reported when some value is
captured by a PatIdent. First, we collect all of the "cannot move out
of" errors before reporting them, and those errors with the same "move
source" are reported together. If the move is caused by a PatIdent (that
binds by value), we add a note indicating where it is and suggest the
user to put `ref` if they don't want the value to move. This makes the
"cannot move out of" error in match expression nicer (though the extra
note may not feel that helpful in other places :P). For example, with
the following code snippet,

```rust
enum Foo {
    Foo1(~u32, ~u32),
    Foo2(~u32),
    Foo3,
}

fn main() {
    let f = &Foo1(~1u32, ~2u32);
    match *f {
        Foo1(num1, num2) => (),
        Foo2(num) => (),
        Foo3 => ()
    }
}
```

Errors before the change:

```rust
test.rs:10:9: 10:25 error: cannot move out of dereference of `&`-pointer
test.rs:10         Foo1(num1, num2) => (),
                   ^~~~~~~~~~~~~~~~
test.rs:10:9: 10:25 error: cannot move out of dereference of `&`-pointer
test.rs:10         Foo1(num1, num2) => (),
                   ^~~~~~~~~~~~~~~~
test.rs:11:9: 11:18 error: cannot move out of dereference of `&`-pointer
test.rs:11         Foo2(num) => (),
                   ^~~~~~~~~
```

After:

```rust
test.rs:9:11: 9:13 error: cannot move out of dereference of `&`-pointer
test.rs:9     match *f {
                    ^~
test.rs:10:14: 10:18 note: attempting to move value to here (to prevent the move, you can use `ref num1` to capture value by reference)
test.rs:10         Foo1(num1, num2) => (),
                        ^~~~
test.rs:10:20: 10:24 note: and here (use `ref num2`)
test.rs:10         Foo1(num1, num2) => (),
                              ^~~~
test.rs:11:14: 11:17 note: and here (use `ref num`)
test.rs:11         Foo2(num) => (),
                        ^~~
```

Close #8064
This commit is contained in:
Kiet Tran 2014-04-08 21:14:14 -04:00
parent 8801d891c4
commit 13d6c35c56
7 changed files with 322 additions and 48 deletions

View file

@ -0,0 +1,58 @@
// Copyright 2014 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.
enum Foo {
Foo1(~u32, ~u32),
Foo2(~u32),
Foo3,
}
fn blah() {
let f = &Foo1(~1u32, ~2u32);
match *f { //~ ERROR cannot move out of
Foo1(num1, //~ NOTE attempting to move value to here
num2) => (), //~ NOTE and here
Foo2(num) => (), //~ NOTE and here
Foo3 => ()
}
}
struct S {f:~str, g:~str}
impl Drop for S {
fn drop(&mut self) { println!("{}", self.f); }
}
fn move_in_match() {
match S {f:~"foo", g:~"bar"} {
S { //~ ERROR cannot move out of type `S`, which defines the `Drop` trait
f: _s, //~ NOTE attempting to move value to here
g: _t //~ NOTE and here
} => {}
}
}
// from issue-8064
struct A {
a: ~int
}
fn free<T>(_: T) {}
fn blah2() {
let a = &A { a: ~1 };
match a.a { //~ ERROR cannot move out of
n => { //~ NOTE attempting to move value to here
free(n)
}
}
free(a)
}
fn main() {}

View file

@ -25,9 +25,10 @@ pub fn main() {
match x {
[_, ..tail] => {
match tail {
[Foo { string: a }, Foo { string: b }] => {
//~^ ERROR cannot move out of dereference of `&`-pointer
//~^^ ERROR cannot move out of dereference of `&`-pointer
[Foo { string: a }, //~ ERROR cannot move out of dereference of `&`-pointer
Foo { string: b }] => {
//~^^ NOTE attempting to move value to here
//~^^ NOTE and here
}
_ => {
unreachable!();

View file

@ -31,8 +31,8 @@ fn c() {
let mut vec = vec!(~1, ~2, ~3);
let vec: &mut [~int] = vec.as_mut_slice();
match vec {
[_a, .._b] => {
//~^ ERROR cannot move out
[_a, //~ ERROR cannot move out
.._b] => { //~^ NOTE attempting to move value to here
// Note: `_a` is *moved* here, but `b` is borrowing,
// hence illegal.
@ -49,9 +49,8 @@ fn d() {
let mut vec = vec!(~1, ~2, ~3);
let vec: &mut [~int] = vec.as_mut_slice();
match vec {
[.._a, _b] => {
//~^ ERROR cannot move out
}
[.._a, //~ ERROR cannot move out
_b] => {} //~ NOTE attempting to move value to here
_ => {}
}
let a = vec[0]; //~ ERROR cannot move out
@ -62,11 +61,13 @@ fn e() {
let vec: &mut [~int] = vec.as_mut_slice();
match vec {
[_a, _b, _c] => {} //~ ERROR cannot move out
//~^ ERROR cannot move out
//~^^ ERROR cannot move out
//~^ NOTE attempting to move value to here
//~^^ NOTE and here
//~^^^ NOTE and here
_ => {}
}
let a = vec[0]; //~ ERROR cannot move out
//~^ NOTE attempting to move value to here
}
fn main() {}

View file

@ -26,9 +26,9 @@ fn main() {
let s = S { x: ~Bar(~42) };
loop {
f(&s, |hellothere| {
match hellothere.x {
match hellothere.x { //~ ERROR cannot move out
~Foo(_) => {}
~Bar(x) => println!("{}", x.to_str()), //~ ERROR cannot move out
~Bar(x) => println!("{}", x.to_str()), //~ NOTE attempting to move value to here
~Baz => {}
}
})