@@ -22,6 +22,7 @@ use std::fmt;
2222use syntax_pos:: Span ;
2323
2424mod region_name;
25+ mod var_name;
2526
2627/// Constraints that are considered interesting can be categorized to
2728/// determine why they are interesting. Order of variants indicates
@@ -30,6 +31,7 @@ mod region_name;
3031enum ConstraintCategory {
3132 Cast ,
3233 Assignment ,
34+ AssignmentToUpvar ,
3335 Return ,
3436 CallArgument ,
3537 Other ,
@@ -39,7 +41,8 @@ enum ConstraintCategory {
3941impl fmt:: Display for ConstraintCategory {
4042 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
4143 match self {
42- ConstraintCategory :: Assignment => write ! ( f, "assignment" ) ,
44+ ConstraintCategory :: Assignment |
45+ ConstraintCategory :: AssignmentToUpvar => write ! ( f, "assignment" ) ,
4346 ConstraintCategory :: Return => write ! ( f, "return" ) ,
4447 ConstraintCategory :: Cast => write ! ( f, "cast" ) ,
4548 ConstraintCategory :: CallArgument => write ! ( f, "argument" ) ,
@@ -130,6 +133,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
130133 & self ,
131134 index : ConstraintIndex ,
132135 mir : & Mir < ' tcx > ,
136+ infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
133137 ) -> ( ConstraintCategory , Span ) {
134138 let constraint = self . constraints [ index] ;
135139 debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
@@ -159,7 +163,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
159163 match statement. kind {
160164 StatementKind :: Assign ( ref place, ref rvalue) => {
161165 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 ) {
163167 ConstraintCategory :: Return
164168 } else {
165169 match rvalue {
@@ -168,6 +172,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
168172 Rvalue :: Aggregate ( ..) => ConstraintCategory :: Assignment ,
169173 _ => ConstraintCategory :: Other ,
170174 }
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
171182 }
172183 }
173184 _ => ConstraintCategory :: Other ,
@@ -214,7 +225,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
214225
215226 // Classify each of the constraints along the path.
216227 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 ) )
218229 . collect ( ) ;
219230 debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
220231
@@ -224,30 +235,75 @@ impl<'tcx> RegionInferenceContext<'tcx> {
224235
225236 // Get a span
226237 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+ ) {
227255 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
230295 ) ;
231296
232- // Figure out how we can refer
233297 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) ;
235300 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) ;
243302
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+ ) ) ;
251307
252308 diag. emit ( ) ;
253309 }
0 commit comments