Skip to content

Commit b9e9a03

Browse files
committed
Auto merge of #41564 - gaurikholkar:master, r=nikomatsakis
Disable ref hint for pattern in let and adding ui tests #40402 A fix to #40402 The `to prevent move, use ref e or ref mut e ` has been disabled. ``` fn main() { let v = vec![String::from("oh no")]; let e = v[0]; } ``` now gives ``` error[E0507]: cannot move out of indexed content --> example.rs:4:13 | 4 | let e = v[0]; | ^^^^ cannot move out of indexed content error: aborting due to previous error ``` I have added ui tests for the same and also modified a compile-fail test.
2 parents 95467d3 + ab5d16a commit b9e9a03

File tree

7 files changed

+146
-19
lines changed

7 files changed

+146
-19
lines changed

src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs

+69-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! Computes moves.
1212
1313
use borrowck::*;
14-
use borrowck::gather_loans::move_error::MoveSpanAndPath;
14+
use borrowck::gather_loans::move_error::MovePlace;
1515
use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
1616
use borrowck::move_data::*;
1717
use rustc::middle::expr_use_visitor as euv;
@@ -23,13 +23,67 @@ use rustc::ty::{self, Ty};
2323
use std::rc::Rc;
2424
use syntax::ast;
2525
use syntax_pos::Span;
26-
use rustc::hir::{self, PatKind};
26+
use rustc::hir::*;
27+
use rustc::hir::map::Node::*;
2728

2829
struct GatherMoveInfo<'tcx> {
2930
id: ast::NodeId,
3031
kind: MoveKind,
3132
cmt: mc::cmt<'tcx>,
32-
span_path_opt: Option<MoveSpanAndPath>
33+
span_path_opt: Option<MovePlace<'tcx>>
34+
}
35+
36+
/// Represents the kind of pattern
37+
#[derive(Debug, Clone, Copy)]
38+
pub enum PatternSource<'tcx> {
39+
MatchExpr(&'tcx Expr),
40+
LetDecl(&'tcx Local),
41+
Other,
42+
}
43+
44+
/// Analyzes the context where the pattern appears to determine the
45+
/// kind of hint we want to give. In particular, if the pattern is in a `match`
46+
/// or nested within other patterns, we want to suggest a `ref` binding:
47+
///
48+
/// let (a, b) = v[0]; // like the `a` and `b` patterns here
49+
/// match v[0] { a => ... } // or the `a` pattern here
50+
///
51+
/// But if the pattern is the outermost pattern in a `let`, we would rather
52+
/// suggest that the author add a `&` to the initializer:
53+
///
54+
/// let x = v[0]; // suggest `&v[0]` here
55+
///
56+
/// In this latter case, this function will return `PatternSource::LetDecl`
57+
/// with a reference to the let
58+
fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> PatternSource<'tcx> {
59+
60+
let parent = tcx.hir.get_parent_node(pat.id);
61+
62+
match tcx.hir.get(parent) {
63+
NodeExpr(ref e) => {
64+
// the enclosing expression must be a `match` or something else
65+
assert!(match e.node {
66+
ExprMatch(..) => true,
67+
_ => return PatternSource::Other,
68+
});
69+
PatternSource::MatchExpr(e)
70+
}
71+
NodeStmt(ref s) => {
72+
// the enclosing statement must be a `let` or something else
73+
match s.node {
74+
StmtDecl(ref decl, _) => {
75+
match decl.node {
76+
DeclLocal(ref local) => PatternSource::LetDecl(local),
77+
_ => return PatternSource::Other,
78+
}
79+
}
80+
_ => return PatternSource::Other,
81+
}
82+
}
83+
84+
_ => return PatternSource::Other,
85+
86+
}
3387
}
3488

3589
pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
@@ -95,11 +149,15 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
95149
move_error_collector: &mut MoveErrorCollector<'tcx>,
96150
move_pat: &hir::Pat,
97151
cmt: mc::cmt<'tcx>) {
152+
let source = get_pattern_source(bccx.tcx,move_pat);
98153
let pat_span_path_opt = match move_pat.node {
99154
PatKind::Binding(_, _, ref path1, _) => {
100-
Some(MoveSpanAndPath{span: move_pat.span,
101-
name: path1.node})
102-
},
155+
Some(MovePlace {
156+
span: move_pat.span,
157+
name: path1.node,
158+
pat_source: source,
159+
})
160+
}
103161
_ => None,
104162
};
105163
let move_info = GatherMoveInfo {
@@ -108,6 +166,11 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
108166
cmt: cmt,
109167
span_path_opt: pat_span_path_opt,
110168
};
169+
170+
debug!("gather_move_from_pat: move_pat={:?} source={:?}",
171+
move_pat,
172+
source);
173+
111174
gather_move(bccx, move_data, move_error_collector, move_info);
112175
}
113176

src/librustc_borrowck/borrowck/gather_loans/move_error.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc::ty;
1717
use syntax::ast;
1818
use syntax_pos;
1919
use errors::DiagnosticBuilder;
20+
use borrowck::gather_loans::gather_moves::PatternSource;
2021

2122
pub struct MoveErrorCollector<'tcx> {
2223
errors: Vec<MoveError<'tcx>>
@@ -40,12 +41,12 @@ impl<'tcx> MoveErrorCollector<'tcx> {
4041

4142
pub struct MoveError<'tcx> {
4243
move_from: mc::cmt<'tcx>,
43-
move_to: Option<MoveSpanAndPath>
44+
move_to: Option<MovePlace<'tcx>>
4445
}
4546

4647
impl<'tcx> MoveError<'tcx> {
4748
pub fn with_move_info(move_from: mc::cmt<'tcx>,
48-
move_to: Option<MoveSpanAndPath>)
49+
move_to: Option<MovePlace<'tcx>>)
4950
-> MoveError<'tcx> {
5051
MoveError {
5152
move_from: move_from,
@@ -55,30 +56,41 @@ impl<'tcx> MoveError<'tcx> {
5556
}
5657

5758
#[derive(Clone)]
58-
pub struct MoveSpanAndPath {
59+
pub struct MovePlace<'tcx> {
5960
pub span: syntax_pos::Span,
6061
pub name: ast::Name,
62+
pub pat_source: PatternSource<'tcx>,
6163
}
6264

6365
pub struct GroupedMoveErrors<'tcx> {
6466
move_from: mc::cmt<'tcx>,
65-
move_to_places: Vec<MoveSpanAndPath>
67+
move_to_places: Vec<MovePlace<'tcx>>
6668
}
6769

68-
fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
69-
errors: &Vec<MoveError<'tcx>>) {
70+
fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec<MoveError<'tcx>>) {
7071
let grouped_errors = group_errors_with_same_origin(errors);
7172
for error in &grouped_errors {
7273
let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
7374
let mut is_first_note = true;
74-
for move_to in &error.move_to_places {
75-
err = note_move_destination(err, move_to.span, move_to.name, is_first_note);
76-
is_first_note = false;
75+
match error.move_to_places.get(0) {
76+
Some(&MovePlace { pat_source: PatternSource::LetDecl(_), .. }) => {
77+
// ignore patterns that are found at the top-level of a `let`;
78+
// see `get_pattern_source()` for details
79+
}
80+
_ => {
81+
for move_to in &error.move_to_places {
82+
83+
err = note_move_destination(err, move_to.span, move_to.name, is_first_note);
84+
is_first_note = false;
85+
}
86+
}
7787
}
7888
if let NoteClosureEnv(upvar_id) = error.move_from.note {
79-
err.span_label(bccx.tcx.hir.span(upvar_id.var_id), &"captured outer variable");
89+
err.span_label(bccx.tcx.hir.span(upvar_id.var_id),
90+
&"captured outer variable");
8091
}
8192
err.emit();
93+
8294
}
8395
}
8496

src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs

-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ fn c() {
5454
_ => {}
5555
}
5656
let a = vec[0]; //~ ERROR cannot move out
57-
//~^ NOTE to prevent move
5857
//~| cannot move out of here
5958
}
6059

@@ -68,7 +67,6 @@ fn d() {
6867
_ => {}
6968
}
7069
let a = vec[0]; //~ ERROR cannot move out
71-
//~^ NOTE to prevent move
7270
//~| cannot move out of here
7371
}
7472

@@ -84,7 +82,6 @@ fn e() {
8482
_ => {}
8583
}
8684
let a = vec[0]; //~ ERROR cannot move out
87-
//~^ NOTE to prevent move
8885
//~| cannot move out of here
8986
}
9087

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that we do not suggest `ref f` here in the `main()` function.
12+
struct Foo {
13+
pub v: Vec<String>,
14+
}
15+
16+
fn main() {
17+
let mut f = Foo { v: Vec::new() };
18+
f.v.push("hello".to_string());
19+
let e = f.v[0];
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error[E0507]: cannot move out of indexed content
2+
--> $DIR/issue-40402-1.rs:19:13
3+
|
4+
19 | let e = f.v[0];
5+
| ^^^^^^ cannot move out of indexed content
6+
7+
error: aborting due to previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that we do suggest `(ref a, ref b)` here, since `a` and `b`
12+
// are nested within a pattern
13+
fn main() {
14+
let x = vec![(String::new(), String::new())];
15+
let (a, b) = x[0];
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0507]: cannot move out of indexed content
2+
--> $DIR/issue-40402-2.rs:15:18
3+
|
4+
15 | let (a, b) = x[0];
5+
| - - ^^^^ cannot move out of indexed content
6+
| | |
7+
| | ...and here (use `ref b` or `ref mut b`)
8+
| hint: to prevent move, use `ref a` or `ref mut a`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)