@@ -22,6 +22,7 @@ use std::fmt;
22
22
use syntax_pos:: Span ;
23
23
24
24
mod region_name;
25
+ mod var_name;
25
26
26
27
/// Constraints that are considered interesting can be categorized to
27
28
/// determine why they are interesting. Order of variants indicates
@@ -30,6 +31,7 @@ mod region_name;
30
31
enum ConstraintCategory {
31
32
Cast ,
32
33
Assignment ,
34
+ AssignmentToUpvar ,
33
35
Return ,
34
36
CallArgument ,
35
37
Other ,
@@ -39,7 +41,8 @@ enum ConstraintCategory {
39
41
impl fmt:: Display for ConstraintCategory {
40
42
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
41
43
match self {
42
- ConstraintCategory :: Assignment => write ! ( f, "assignment" ) ,
44
+ ConstraintCategory :: Assignment |
45
+ ConstraintCategory :: AssignmentToUpvar => write ! ( f, "assignment" ) ,
43
46
ConstraintCategory :: Return => write ! ( f, "return" ) ,
44
47
ConstraintCategory :: Cast => write ! ( f, "cast" ) ,
45
48
ConstraintCategory :: CallArgument => write ! ( f, "argument" ) ,
@@ -130,6 +133,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
130
133
& self ,
131
134
index : ConstraintIndex ,
132
135
mir : & Mir < ' tcx > ,
136
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
133
137
) -> ( ConstraintCategory , Span ) {
134
138
let constraint = self . constraints [ index] ;
135
139
debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
@@ -159,7 +163,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
159
163
match statement. kind {
160
164
StatementKind :: Assign ( ref place, ref rvalue) => {
161
165
debug ! ( "classify_constraint: place={:?} rvalue={:?}" , place, rvalue) ;
162
- if * place == Place :: Local ( mir:: RETURN_PLACE ) {
166
+ let initial_category = if * place == Place :: Local ( mir:: RETURN_PLACE ) {
163
167
ConstraintCategory :: Return
164
168
} else {
165
169
match rvalue {
@@ -168,6 +172,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
168
172
Rvalue :: Aggregate ( ..) => ConstraintCategory :: Assignment ,
169
173
_ => ConstraintCategory :: Other ,
170
174
}
175
+ } ;
176
+
177
+ if initial_category == ConstraintCategory :: Assignment
178
+ && place. is_upvar_field_projection ( mir, & infcx. tcx , true ) . is_some ( ) {
179
+ ConstraintCategory :: AssignmentToUpvar
180
+ } else {
181
+ initial_category
171
182
}
172
183
}
173
184
_ => ConstraintCategory :: Other ,
@@ -214,7 +225,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
214
225
215
226
// Classify each of the constraints along the path.
216
227
let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path. iter ( )
217
- . map ( |& index| self . classify_constraint ( index, mir) )
228
+ . map ( |& index| self . classify_constraint ( index, mir, infcx ) )
218
229
. collect ( ) ;
219
230
debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
220
231
@@ -224,30 +235,75 @@ impl<'tcx> RegionInferenceContext<'tcx> {
224
235
225
236
// Get a span
226
237
let ( category, span) = categorized_path. first ( ) . unwrap ( ) ;
238
+
239
+ match category {
240
+ ConstraintCategory :: AssignmentToUpvar =>
241
+ self . report_closure_error ( mir, infcx, fr, outlived_fr, span) ,
242
+ _ =>
243
+ self . report_general_error ( mir, infcx, mir_def_id, fr, outlived_fr, category, span) ,
244
+ }
245
+ }
246
+
247
+ fn report_closure_error (
248
+ & self ,
249
+ mir : & Mir < ' tcx > ,
250
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
251
+ fr : RegionVid ,
252
+ outlived_fr : RegionVid ,
253
+ span : & Span ,
254
+ ) {
227
255
let diag = & mut infcx. tcx . sess . struct_span_err (
228
- * span,
229
- & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
256
+ * span, & format ! ( "borrowed data escapes outside of closure" ) ,
257
+ ) ;
258
+
259
+ let ( outlived_fr_name, outlived_fr_span) = self . get_var_name_and_span_for_region (
260
+ infcx. tcx , mir, outlived_fr) ;
261
+
262
+ if let Some ( name) = outlived_fr_name {
263
+ diag. span_label (
264
+ outlived_fr_span,
265
+ format ! ( "`{}` is declared here, outside of the closure body" , name) ,
266
+ ) ;
267
+ }
268
+
269
+ let ( fr_name, fr_span) = self . get_var_name_and_span_for_region ( infcx. tcx , mir, fr) ;
270
+
271
+ if let Some ( name) = fr_name {
272
+ diag. span_label (
273
+ fr_span,
274
+ format ! ( "`{}` is a reference that is only valid in the closure body" , name) ,
275
+ ) ;
276
+
277
+ diag. span_label ( * span, format ! ( "`{}` escapes the closure body here" , name) ) ;
278
+ }
279
+
280
+ diag. emit ( ) ;
281
+ }
282
+
283
+ fn report_general_error (
284
+ & self ,
285
+ mir : & Mir < ' tcx > ,
286
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
287
+ mir_def_id : DefId ,
288
+ fr : RegionVid ,
289
+ outlived_fr : RegionVid ,
290
+ category : & ConstraintCategory ,
291
+ span : & Span ,
292
+ ) {
293
+ let diag = & mut infcx. tcx . sess . struct_span_err (
294
+ * span, & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
230
295
) ;
231
296
232
- // Figure out how we can refer
233
297
let counter = & mut 1 ;
234
- let fr_name = self . give_region_a_name ( infcx. tcx , mir, mir_def_id, fr, counter, diag) ;
298
+ let fr_name = self . give_region_a_name (
299
+ infcx. tcx , mir, mir_def_id, fr, counter, diag) ;
235
300
let outlived_fr_name = self . give_region_a_name (
236
- infcx. tcx ,
237
- mir,
238
- mir_def_id,
239
- outlived_fr,
240
- counter,
241
- diag,
242
- ) ;
301
+ infcx. tcx , mir, mir_def_id, outlived_fr, counter, diag) ;
243
302
244
- diag. span_label (
245
- * span,
246
- format ! (
247
- "{} requires that `{}` must outlive `{}`" ,
248
- category, fr_name, outlived_fr_name,
249
- ) ,
250
- ) ;
303
+ diag. span_label ( * span, format ! (
304
+ "{} requires that `{}` must outlive `{}`" ,
305
+ category, fr_name, outlived_fr_name,
306
+ ) ) ;
251
307
252
308
diag. emit ( ) ;
253
309
}
0 commit comments