@@ -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,7 +31,9 @@ mod region_name;
30
31
enum ConstraintCategory {
31
32
Cast ,
32
33
Assignment ,
34
+ AssignmentToUpvar ,
33
35
Return ,
36
+ CallArgumentToUpvar ,
34
37
CallArgument ,
35
38
Other ,
36
39
Boring ,
@@ -39,10 +42,12 @@ enum ConstraintCategory {
39
42
impl fmt:: Display for ConstraintCategory {
40
43
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
41
44
match self {
42
- ConstraintCategory :: Assignment => write ! ( f, "assignment" ) ,
45
+ ConstraintCategory :: Assignment |
46
+ ConstraintCategory :: AssignmentToUpvar => write ! ( f, "assignment" ) ,
43
47
ConstraintCategory :: Return => write ! ( f, "return" ) ,
44
48
ConstraintCategory :: Cast => write ! ( f, "cast" ) ,
45
- ConstraintCategory :: CallArgument => write ! ( f, "argument" ) ,
49
+ ConstraintCategory :: CallArgument |
50
+ ConstraintCategory :: CallArgumentToUpvar => write ! ( f, "argument" ) ,
46
51
_ => write ! ( f, "free region" ) ,
47
52
}
48
53
}
@@ -130,8 +135,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
130
135
& self ,
131
136
index : ConstraintIndex ,
132
137
mir : & Mir < ' tcx > ,
138
+ _infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
133
139
) -> ( ConstraintCategory , Span ) {
134
140
let constraint = self . constraints [ index] ;
141
+ debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
135
142
let span = constraint. locations . span ( mir) ;
136
143
let location = constraint. locations . from_location ( ) . unwrap_or ( Location :: START ) ;
137
144
@@ -140,8 +147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
140
147
}
141
148
142
149
let data = & mir[ location. block ] ;
150
+ debug ! ( "classify_constraint: location={:?} data={:?}" , location, data) ;
143
151
let category = if location. statement_index == data. statements . len ( ) {
144
152
if let Some ( ref terminator) = data. terminator {
153
+ debug ! ( "classify_constraint: terminator.kind={:?}" , terminator. kind) ;
145
154
match terminator. kind {
146
155
TerminatorKind :: DropAndReplace { .. } => ConstraintCategory :: Assignment ,
147
156
TerminatorKind :: Call { .. } => ConstraintCategory :: CallArgument ,
@@ -152,14 +161,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
152
161
}
153
162
} else {
154
163
let statement = & data. statements [ location. statement_index ] ;
164
+ debug ! ( "classify_constraint: statement.kind={:?}" , statement. kind) ;
155
165
match statement. kind {
156
166
StatementKind :: Assign ( ref place, ref rvalue) => {
167
+ debug ! ( "classify_constraint: place={:?} rvalue={:?}" , place, rvalue) ;
157
168
if * place == Place :: Local ( mir:: RETURN_PLACE ) {
158
169
ConstraintCategory :: Return
159
170
} else {
160
171
match rvalue {
161
172
Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
162
- Rvalue :: Use ( ..) => ConstraintCategory :: Assignment ,
173
+ Rvalue :: Use ( ..) |
174
+ Rvalue :: Aggregate ( ..) => ConstraintCategory :: Assignment ,
163
175
_ => ConstraintCategory :: Other ,
164
176
}
165
177
}
@@ -208,7 +220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
208
220
209
221
// Classify each of the constraints along the path.
210
222
let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path. iter ( )
211
- . map ( |& index| self . classify_constraint ( index, mir) )
223
+ . map ( |& index| self . classify_constraint ( index, mir, infcx ) )
212
224
. collect ( ) ;
213
225
debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
214
226
@@ -218,30 +230,100 @@ impl<'tcx> RegionInferenceContext<'tcx> {
218
230
219
231
// Get a span
220
232
let ( category, span) = categorized_path. first ( ) . unwrap ( ) ;
233
+
234
+ let category = match (
235
+ category,
236
+ self . universal_regions . is_local_free_region ( fr) ,
237
+ self . universal_regions . is_local_free_region ( outlived_fr) ,
238
+ ) {
239
+ ( ConstraintCategory :: Assignment , true , false ) =>
240
+ & ConstraintCategory :: AssignmentToUpvar ,
241
+ ( ConstraintCategory :: CallArgument , true , false ) =>
242
+ & ConstraintCategory :: CallArgumentToUpvar ,
243
+ ( category, _, _) => category,
244
+ } ;
245
+
246
+ debug ! ( "report_error: category={:?}" , category) ;
247
+ match category {
248
+ ConstraintCategory :: AssignmentToUpvar |
249
+ ConstraintCategory :: CallArgumentToUpvar =>
250
+ self . report_closure_error ( mir, infcx, mir_def_id, fr, outlived_fr, category, span) ,
251
+ _ =>
252
+ self . report_general_error ( mir, infcx, mir_def_id, fr, outlived_fr, category, span) ,
253
+ }
254
+ }
255
+
256
+ fn report_closure_error (
257
+ & self ,
258
+ mir : & Mir < ' tcx > ,
259
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
260
+ mir_def_id : DefId ,
261
+ fr : RegionVid ,
262
+ outlived_fr : RegionVid ,
263
+ category : & ConstraintCategory ,
264
+ span : & Span ,
265
+ ) {
266
+ let fr_name_and_span = self . get_var_name_and_span_for_region (
267
+ infcx. tcx , mir, fr) ;
268
+ let outlived_fr_name_and_span = self . get_var_name_and_span_for_region (
269
+ infcx. tcx , mir, outlived_fr) ;
270
+
271
+ if fr_name_and_span. is_none ( ) && outlived_fr_name_and_span. is_none ( ) {
272
+ return self . report_general_error ( mir, infcx, mir_def_id, fr, outlived_fr, category,
273
+ span) ;
274
+ }
275
+
276
+ let diag = & mut infcx. tcx . sess . struct_span_err (
277
+ * span, & format ! ( "borrowed data escapes outside of closure" ) ,
278
+ ) ;
279
+
280
+ if let Some ( ( outlived_fr_name, outlived_fr_span) ) = outlived_fr_name_and_span {
281
+ if let Some ( name) = outlived_fr_name {
282
+ diag. span_label (
283
+ outlived_fr_span,
284
+ format ! ( "`{}` is declared here, outside of the closure body" , name) ,
285
+ ) ;
286
+ }
287
+ }
288
+
289
+ if let Some ( ( fr_name, fr_span) ) = fr_name_and_span {
290
+ if let Some ( name) = fr_name {
291
+ diag. span_label (
292
+ fr_span,
293
+ format ! ( "`{}` is a reference that is only valid in the closure body" , name) ,
294
+ ) ;
295
+
296
+ diag. span_label ( * span, format ! ( "`{}` escapes the closure body here" , name) ) ;
297
+ }
298
+ }
299
+
300
+ diag. emit ( ) ;
301
+ }
302
+
303
+ fn report_general_error (
304
+ & self ,
305
+ mir : & Mir < ' tcx > ,
306
+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
307
+ mir_def_id : DefId ,
308
+ fr : RegionVid ,
309
+ outlived_fr : RegionVid ,
310
+ category : & ConstraintCategory ,
311
+ span : & Span ,
312
+ ) {
221
313
let diag = & mut infcx. tcx . sess . struct_span_err (
222
- * span,
223
- & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
314
+ * span, & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
224
315
) ;
225
316
226
- // Figure out how we can refer
227
317
let counter = & mut 1 ;
228
- let fr_name = self . give_region_a_name ( infcx. tcx , mir, mir_def_id, fr, counter, diag) ;
318
+ let fr_name = self . give_region_a_name (
319
+ infcx. tcx , mir, mir_def_id, fr, counter, diag) ;
229
320
let outlived_fr_name = self . give_region_a_name (
230
- infcx. tcx ,
231
- mir,
232
- mir_def_id,
233
- outlived_fr,
234
- counter,
235
- diag,
236
- ) ;
321
+ infcx. tcx , mir, mir_def_id, outlived_fr, counter, diag) ;
237
322
238
- diag. span_label (
239
- * span,
240
- format ! (
241
- "{} requires that `{}` must outlive `{}`" ,
242
- category, fr_name, outlived_fr_name,
243
- ) ,
244
- ) ;
323
+ diag. span_label ( * span, format ! (
324
+ "{} requires that `{}` must outlive `{}`" ,
325
+ category, fr_name, outlived_fr_name,
326
+ ) ) ;
245
327
246
328
diag. emit ( ) ;
247
329
}
0 commit comments