@@ -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,7 +31,9 @@ mod region_name;
3031enum ConstraintCategory {
3132 Cast ,
3233 Assignment ,
34+ AssignmentToUpvar ,
3335 Return ,
36+ CallArgumentToUpvar ,
3437 CallArgument ,
3538 Other ,
3639 Boring ,
@@ -39,10 +42,12 @@ enum ConstraintCategory {
3942impl fmt:: Display for ConstraintCategory {
4043 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
4144 match self {
42- ConstraintCategory :: Assignment => write ! ( f, "assignment" ) ,
45+ ConstraintCategory :: Assignment |
46+ ConstraintCategory :: AssignmentToUpvar => write ! ( f, "assignment" ) ,
4347 ConstraintCategory :: Return => write ! ( f, "return" ) ,
4448 ConstraintCategory :: Cast => write ! ( f, "cast" ) ,
45- ConstraintCategory :: CallArgument => write ! ( f, "argument" ) ,
49+ ConstraintCategory :: CallArgument |
50+ ConstraintCategory :: CallArgumentToUpvar => write ! ( f, "argument" ) ,
4651 _ => write ! ( f, "free region" ) ,
4752 }
4853 }
@@ -130,8 +135,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
130135 & self ,
131136 index : ConstraintIndex ,
132137 mir : & Mir < ' tcx > ,
138+ _infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
133139 ) -> ( ConstraintCategory , Span ) {
134140 let constraint = self . constraints [ index] ;
141+ debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
135142 let span = constraint. locations . span ( mir) ;
136143 let location = constraint. locations . from_location ( ) . unwrap_or ( Location :: START ) ;
137144
@@ -140,8 +147,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
140147 }
141148
142149 let data = & mir[ location. block ] ;
150+ debug ! ( "classify_constraint: location={:?} data={:?}" , location, data) ;
143151 let category = if location. statement_index == data. statements . len ( ) {
144152 if let Some ( ref terminator) = data. terminator {
153+ debug ! ( "classify_constraint: terminator.kind={:?}" , terminator. kind) ;
145154 match terminator. kind {
146155 TerminatorKind :: DropAndReplace { .. } => ConstraintCategory :: Assignment ,
147156 TerminatorKind :: Call { .. } => ConstraintCategory :: CallArgument ,
@@ -152,14 +161,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
152161 }
153162 } else {
154163 let statement = & data. statements [ location. statement_index ] ;
164+ debug ! ( "classify_constraint: statement.kind={:?}" , statement. kind) ;
155165 match statement. kind {
156166 StatementKind :: Assign ( ref place, ref rvalue) => {
167+ debug ! ( "classify_constraint: place={:?} rvalue={:?}" , place, rvalue) ;
157168 if * place == Place :: Local ( mir:: RETURN_PLACE ) {
158169 ConstraintCategory :: Return
159170 } else {
160171 match rvalue {
161172 Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
162- Rvalue :: Use ( ..) => ConstraintCategory :: Assignment ,
173+ Rvalue :: Use ( ..) |
174+ Rvalue :: Aggregate ( ..) => ConstraintCategory :: Assignment ,
163175 _ => ConstraintCategory :: Other ,
164176 }
165177 }
@@ -208,7 +220,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
208220
209221 // Classify each of the constraints along the path.
210222 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 ) )
212224 . collect ( ) ;
213225 debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
214226
@@ -218,30 +230,100 @@ impl<'tcx> RegionInferenceContext<'tcx> {
218230
219231 // Get a span
220232 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+ ) {
221313 let diag = & mut infcx. tcx . sess . struct_span_err (
222- * span,
223- & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
314+ * span, & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
224315 ) ;
225316
226- // Figure out how we can refer
227317 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) ;
229320 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) ;
237322
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+ ) ) ;
245327
246328 diag. emit ( ) ;
247329 }
0 commit comments