11
11
use rustc:: hir;
12
12
use rustc:: mir:: * ;
13
13
use rustc:: ty;
14
- use rustc_data_structures:: indexed_vec:: Idx ;
15
14
use rustc_errors:: DiagnosticBuilder ;
15
+ use rustc_data_structures:: indexed_vec:: Idx ;
16
16
use syntax_pos:: Span ;
17
17
18
18
use borrow_check:: MirBorrowckCtxt ;
19
+ use borrow_check:: prefixes:: PrefixSet ;
19
20
use dataflow:: move_paths:: { IllegalMoveOrigin , IllegalMoveOriginKind } ;
20
21
use dataflow:: move_paths:: { LookupResult , MoveError , MovePathIndex } ;
21
22
use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
@@ -38,6 +39,7 @@ enum GroupedMoveError<'tcx> {
38
39
// Match place can't be moved from
39
40
// e.g. match x[0] { s => (), } where x: &[String]
40
41
MovesFromMatchPlace {
42
+ original_path : Place < ' tcx > ,
41
43
span : Span ,
42
44
move_from : Place < ' tcx > ,
43
45
kind : IllegalMoveOriginKind < ' tcx > ,
@@ -46,37 +48,43 @@ enum GroupedMoveError<'tcx> {
46
48
// Part of a pattern can't be moved from,
47
49
// e.g. match &String::new() { &x => (), }
48
50
MovesFromPattern {
51
+ original_path : Place < ' tcx > ,
49
52
span : Span ,
50
53
move_from : MovePathIndex ,
51
54
kind : IllegalMoveOriginKind < ' tcx > ,
52
55
binds_to : Vec < Local > ,
53
56
} ,
54
57
// Everything that isn't from pattern matching.
55
58
OtherIllegalMove {
59
+ original_path : Place < ' tcx > ,
56
60
span : Span ,
57
61
kind : IllegalMoveOriginKind < ' tcx > ,
58
62
} ,
59
63
}
60
64
61
65
impl < ' a , ' gcx , ' tcx > MirBorrowckCtxt < ' a , ' gcx , ' tcx > {
62
- pub ( crate ) fn report_move_errors ( & mut self , move_errors : Vec < MoveError < ' tcx > > ) {
66
+ pub ( crate ) fn report_move_errors ( & mut self , move_errors : Vec < ( Place < ' tcx > , MoveError < ' tcx > ) > ) {
63
67
let grouped_errors = self . group_move_errors ( move_errors) ;
64
68
for error in grouped_errors {
65
69
self . report ( error) ;
66
70
}
67
71
}
68
72
69
- fn group_move_errors ( & self , errors : Vec < MoveError < ' tcx > > ) -> Vec < GroupedMoveError < ' tcx > > {
73
+ fn group_move_errors (
74
+ & self ,
75
+ errors : Vec < ( Place < ' tcx > , MoveError < ' tcx > ) >
76
+ ) -> Vec < GroupedMoveError < ' tcx > > {
70
77
let mut grouped_errors = Vec :: new ( ) ;
71
- for error in errors {
72
- self . append_to_grouped_errors ( & mut grouped_errors, error) ;
78
+ for ( original_path , error) in errors {
79
+ self . append_to_grouped_errors ( & mut grouped_errors, original_path , error) ;
73
80
}
74
81
grouped_errors
75
82
}
76
83
77
84
fn append_to_grouped_errors (
78
85
& self ,
79
86
grouped_errors : & mut Vec < GroupedMoveError < ' tcx > > ,
87
+ original_path : Place < ' tcx > ,
80
88
error : MoveError < ' tcx > ,
81
89
) {
82
90
match error {
@@ -116,6 +124,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
116
124
self . append_binding_error (
117
125
grouped_errors,
118
126
kind,
127
+ original_path,
119
128
move_from,
120
129
* local,
121
130
opt_match_place,
@@ -127,6 +136,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
127
136
}
128
137
grouped_errors. push ( GroupedMoveError :: OtherIllegalMove {
129
138
span : stmt_source_info. span ,
139
+ original_path,
130
140
kind,
131
141
} ) ;
132
142
}
@@ -137,6 +147,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
137
147
& self ,
138
148
grouped_errors : & mut Vec < GroupedMoveError < ' tcx > > ,
139
149
kind : IllegalMoveOriginKind < ' tcx > ,
150
+ original_path : Place < ' tcx > ,
140
151
move_from : & Place < ' tcx > ,
141
152
bind_to : Local ,
142
153
match_place : & Option < Place < ' tcx > > ,
@@ -176,6 +187,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
176
187
grouped_errors. push ( GroupedMoveError :: MovesFromMatchPlace {
177
188
span,
178
189
move_from : match_place. clone ( ) ,
190
+ original_path,
179
191
kind,
180
192
binds_to,
181
193
} ) ;
@@ -206,6 +218,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
206
218
grouped_errors. push ( GroupedMoveError :: MovesFromPattern {
207
219
span : match_span,
208
220
move_from : mpi,
221
+ original_path,
209
222
kind,
210
223
binds_to : vec ! [ bind_to] ,
211
224
} ) ;
@@ -215,12 +228,23 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
215
228
216
229
fn report ( & mut self , error : GroupedMoveError < ' tcx > ) {
217
230
let ( mut err, err_span) = {
218
- let ( span, kind) : ( Span , & IllegalMoveOriginKind ) = match error {
219
- GroupedMoveError :: MovesFromMatchPlace { span, ref kind, .. }
220
- | GroupedMoveError :: MovesFromPattern { span, ref kind, .. }
221
- | GroupedMoveError :: OtherIllegalMove { span, ref kind } => ( span, kind) ,
222
- } ;
231
+ let ( span, original_path, kind) : ( Span , & Place < ' tcx > , & IllegalMoveOriginKind ) =
232
+ match error {
233
+ GroupedMoveError :: MovesFromMatchPlace {
234
+ span,
235
+ ref original_path,
236
+ ref kind,
237
+ ..
238
+ } |
239
+ GroupedMoveError :: MovesFromPattern { span, ref original_path, ref kind, .. } |
240
+ GroupedMoveError :: OtherIllegalMove { span, ref original_path, ref kind } => {
241
+ ( span, original_path, kind)
242
+ } ,
243
+ } ;
223
244
let origin = Origin :: Mir ;
245
+ debug ! ( "report: original_path={:?} span={:?}, kind={:?} \
246
+ original_path.is_upvar_field_projection={:?}", original_path, span, kind,
247
+ original_path. is_upvar_field_projection( self . mir, & self . tcx) ) ;
224
248
(
225
249
match kind {
226
250
IllegalMoveOriginKind :: Static => {
@@ -231,22 +255,17 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
231
255
// borrow to provide feedback about why this
232
256
// was a move rather than a copy.
233
257
let ty = place. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
258
+ let is_upvar_field_projection =
259
+ self . prefixes ( & original_path, PrefixSet :: All )
260
+ . any ( |p| p. is_upvar_field_projection ( self . mir , & self . tcx )
261
+ . is_some ( ) ) ;
234
262
match ty. sty {
235
263
ty:: TyArray ( ..) | ty:: TySlice ( ..) => self
236
264
. tcx
237
265
. cannot_move_out_of_interior_noncopy ( span, ty, None , origin) ,
238
266
ty:: TyClosure ( def_id, closure_substs)
239
- if !self . mir . upvar_decls . is_empty ( )
240
- && {
241
- match place {
242
- Place :: Projection ( ref proj) => {
243
- proj. base == Place :: Local ( Local :: new ( 1 ) )
244
- }
245
- Place :: Promoted ( _) |
246
- Place :: Local ( _) | Place :: Static ( _) => unreachable ! ( ) ,
247
- }
248
- } =>
249
- {
267
+ if !self . mir . upvar_decls . is_empty ( ) && is_upvar_field_projection
268
+ => {
250
269
let closure_kind_ty =
251
270
closure_substs. closure_kind_ty ( def_id, self . tcx ) ;
252
271
let closure_kind = closure_kind_ty. to_opt_closure_kind ( ) ;
@@ -262,7 +281,28 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
262
281
}
263
282
None => bug ! ( "closure kind not inferred by borrowck" ) ,
264
283
} ;
265
- self . tcx . cannot_move_out_of ( span, place_description, origin)
284
+ debug ! ( "report: closure_kind_ty={:?} closure_kind={:?} \
285
+ place_description={:?}", closure_kind_ty, closure_kind,
286
+ place_description) ;
287
+
288
+ let mut diag = self . tcx . cannot_move_out_of (
289
+ span, place_description, origin) ;
290
+
291
+ for prefix in self . prefixes ( & original_path, PrefixSet :: All ) {
292
+ if let Some ( field) = prefix. is_upvar_field_projection (
293
+ self . mir , & self . tcx ) {
294
+ let upvar_decl = & self . mir . upvar_decls [ field. index ( ) ] ;
295
+ let upvar_hir_id =
296
+ upvar_decl. var_hir_id . assert_crate_local ( ) ;
297
+ let upvar_node_id =
298
+ self . tcx . hir . hir_to_node_id ( upvar_hir_id) ;
299
+ let upvar_span = self . tcx . hir . span ( upvar_node_id) ;
300
+ diag. span_label ( upvar_span, "captured outer variable" ) ;
301
+ break ;
302
+ }
303
+ }
304
+
305
+ diag
266
306
}
267
307
_ => self
268
308
. tcx
0 commit comments