@@ -28,7 +28,7 @@ mod var_name;
2828/// Constraints that are considered interesting can be categorized to
2929/// determine why they are interesting. Order of variants indicates
3030/// sort order of the category, thereby influencing diagnostic output.
31- #[ derive( Debug , Eq , PartialEq , PartialOrd , Ord ) ]
31+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , PartialOrd , Ord ) ]
3232enum ConstraintCategory {
3333 Cast ,
3434 Assignment ,
@@ -43,12 +43,14 @@ enum ConstraintCategory {
4343impl fmt:: Display for ConstraintCategory {
4444 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
4545 match self {
46- ConstraintCategory :: Assignment |
47- ConstraintCategory :: AssignmentToUpvar => write ! ( f, "assignment" ) ,
46+ ConstraintCategory :: Assignment | ConstraintCategory :: AssignmentToUpvar => {
47+ write ! ( f, "assignment" )
48+ }
4849 ConstraintCategory :: Return => write ! ( f, "return" ) ,
4950 ConstraintCategory :: Cast => write ! ( f, "cast" ) ,
50- ConstraintCategory :: CallArgument |
51- ConstraintCategory :: CallArgumentToUpvar => write ! ( f, "argument" ) ,
51+ ConstraintCategory :: CallArgument | ConstraintCategory :: CallArgumentToUpvar => {
52+ write ! ( f, "argument" )
53+ }
5254 _ => write ! ( f, "free region" ) ,
5355 }
5456 }
@@ -62,6 +64,43 @@ enum Trace {
6264}
6365
6466impl < ' tcx > RegionInferenceContext < ' tcx > {
67+ /// Tries to find the best constraint to blame for the fact that
68+ /// `R: from_region`, where `R` is some region that meets
69+ /// `target_test`. This works by following the constraint graph,
70+ /// creating a constraint path that forces `R` to outlive
71+ /// `from_region`, and then finding the best choices within that
72+ /// path to blame.
73+ fn best_blame_constraint (
74+ & self ,
75+ mir : & Mir < ' tcx > ,
76+ from_region : RegionVid ,
77+ target_test : impl Fn ( RegionVid ) -> bool ,
78+ ) -> ( ConstraintCategory , Span ) {
79+ debug ! ( "best_blame_constraint(from_region={:?})" , from_region) ;
80+
81+ // Find all paths
82+ let path = self
83+ . find_constraint_paths_between_regions ( from_region, target_test)
84+ . unwrap ( ) ;
85+ debug ! ( "best_blame_constraint: path={:#?}" , path) ;
86+
87+ // Classify each of the constraints along the path.
88+ let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path
89+ . iter ( )
90+ . map ( |& index| self . classify_constraint ( index, mir) )
91+ . collect ( ) ;
92+ debug ! (
93+ "best_blame_constraint: categorized_path={:?}" ,
94+ categorized_path
95+ ) ;
96+
97+ // Find what appears to be the most interesting path to report to the user.
98+ categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
99+ debug ! ( "best_blame_constraint: sorted_path={:?}" , categorized_path) ;
100+
101+ * categorized_path. first ( ) . unwrap ( )
102+ }
103+
65104 /// Walks the graph of constraints (where `'a: 'b` is considered
66105 /// an edge `'a -> 'b`) to find all paths from `from_region` to
67106 /// `to_region`. The paths are accumulated into the vector
@@ -89,7 +128,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
89128 let mut p = r;
90129 loop {
91130 match context[ p] {
92- Trace :: NotVisited => bug ! ( "found unvisited region {:?} on path to {:?}" , p, r) ,
131+ Trace :: NotVisited => {
132+ bug ! ( "found unvisited region {:?} on path to {:?}" , p, r)
133+ }
93134 Trace :: FromConstraint ( c) => {
94135 result. push ( c) ;
95136 p = self . constraints [ c] . sup ;
@@ -139,19 +180,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
139180 & self ,
140181 index : ConstraintIndex ,
141182 mir : & Mir < ' tcx > ,
142- _infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
143183 ) -> ( ConstraintCategory , Span ) {
144184 let constraint = self . constraints [ index] ;
145185 debug ! ( "classify_constraint: constraint={:?}" , constraint) ;
146186 let span = constraint. locations . span ( mir) ;
147- let location = constraint. locations . from_location ( ) . unwrap_or ( Location :: START ) ;
187+ let location = constraint
188+ . locations
189+ . from_location ( )
190+ . unwrap_or ( Location :: START ) ;
148191
149192 if !self . constraint_is_interesting ( index) {
150193 return ( ConstraintCategory :: Boring , span) ;
151194 }
152195
153196 let data = & mir[ location. block ] ;
154- debug ! ( "classify_constraint: location={:?} data={:?}" , location, data) ;
197+ debug ! (
198+ "classify_constraint: location={:?} data={:?}" ,
199+ location, data
200+ ) ;
155201 let category = if location. statement_index == data. statements . len ( ) {
156202 if let Some ( ref terminator) = data. terminator {
157203 debug ! ( "classify_constraint: terminator.kind={:?}" , terminator. kind) ;
@@ -174,8 +220,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
174220 } else {
175221 match rvalue {
176222 Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
177- Rvalue :: Use ( ..) |
178- Rvalue :: Aggregate ( ..) => ConstraintCategory :: Assignment ,
223+ Rvalue :: Use ( ..) | Rvalue :: Aggregate ( ..) => {
224+ ConstraintCategory :: Assignment
225+ }
179226 _ => ConstraintCategory :: Other ,
180227 }
181228 }
@@ -206,27 +253,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
206253 ) {
207254 debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
208255
209- // Find all paths
210- let path = self . find_constraint_paths_between_regions ( fr, |r| r == outlived_fr) . unwrap ( ) ;
211- debug ! ( "report_error: path={:#?}" , path) ;
212-
213- // Classify each of the constraints along the path.
214- let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path. iter ( )
215- . map ( |& index| self . classify_constraint ( index, mir, infcx) )
216- . collect ( ) ;
217- debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
218-
219- // Find what appears to be the most interesting path to report to the user.
220- categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
221- debug ! ( "report_error: sorted_path={:?}" , categorized_path) ;
222-
223- // Get a span
224- let ( category, span) = categorized_path. first ( ) . unwrap ( ) ;
256+ let ( category, span) = self . best_blame_constraint ( mir, fr, |r| r == outlived_fr) ;
225257
226258 // Check if we can use one of the "nice region errors".
227259 if let ( Some ( f) , Some ( o) ) = ( self . to_error_region ( fr) , self . to_error_region ( outlived_fr) ) {
228260 let tables = infcx. tcx . typeck_tables_of ( mir_def_id) ;
229- let nice = NiceRegionError :: new_from_span ( infcx. tcx , * span, o, f, Some ( tables) ) ;
261+ let nice = NiceRegionError :: new_from_span ( infcx. tcx , span, o, f, Some ( tables) ) ;
230262 if let Some ( _error_reported) = nice. try_report ( ) {
231263 return ;
232264 }
@@ -237,22 +269,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
237269 self . universal_regions . is_local_free_region ( fr) ,
238270 self . universal_regions . is_local_free_region ( outlived_fr) ,
239271 ) {
240- ( ConstraintCategory :: Assignment , true , false ) =>
241- & ConstraintCategory :: AssignmentToUpvar ,
242- ( ConstraintCategory :: CallArgument , true , false ) =>
243- & ConstraintCategory :: CallArgumentToUpvar ,
272+ ( ConstraintCategory :: Assignment , true , false ) => ConstraintCategory :: AssignmentToUpvar ,
273+ ( ConstraintCategory :: CallArgument , true , false ) => {
274+ ConstraintCategory :: CallArgumentToUpvar
275+ }
244276 ( category, _, _) => category,
245277 } ;
246278
247279 debug ! ( "report_error: category={:?}" , category) ;
248280 match category {
249- ConstraintCategory :: AssignmentToUpvar |
250- ConstraintCategory :: CallArgumentToUpvar =>
251- self . report_closure_error (
252- mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer) ,
253- _ =>
254- self . report_general_error (
255- mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer) ,
281+ ConstraintCategory :: AssignmentToUpvar | ConstraintCategory :: CallArgumentToUpvar => self
282+ . report_closure_error (
283+ mir,
284+ infcx,
285+ mir_def_id,
286+ fr,
287+ outlived_fr,
288+ category,
289+ span,
290+ errors_buffer,
291+ ) ,
292+ _ => self . report_general_error (
293+ mir,
294+ infcx,
295+ mir_def_id,
296+ fr,
297+ outlived_fr,
298+ category,
299+ span,
300+ errors_buffer,
301+ ) ,
256302 }
257303 }
258304
@@ -263,23 +309,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
263309 mir_def_id : DefId ,
264310 fr : RegionVid ,
265311 outlived_fr : RegionVid ,
266- category : & ConstraintCategory ,
267- span : & Span ,
312+ category : ConstraintCategory ,
313+ span : Span ,
268314 errors_buffer : & mut Vec < Diagnostic > ,
269315 ) {
270- let fr_name_and_span = self . get_var_name_and_span_for_region (
271- infcx. tcx , mir, fr) ;
272- let outlived_fr_name_and_span = self . get_var_name_and_span_for_region (
273- infcx. tcx , mir, outlived_fr) ;
316+ let fr_name_and_span = self . get_var_name_and_span_for_region ( infcx. tcx , mir, fr) ;
317+ let outlived_fr_name_and_span =
318+ self . get_var_name_and_span_for_region ( infcx. tcx , mir, outlived_fr) ;
274319
275320 if fr_name_and_span. is_none ( ) && outlived_fr_name_and_span. is_none ( ) {
276321 return self . report_general_error (
277- mir, infcx, mir_def_id, fr, outlived_fr, category, span, errors_buffer) ;
322+ mir,
323+ infcx,
324+ mir_def_id,
325+ fr,
326+ outlived_fr,
327+ category,
328+ span,
329+ errors_buffer,
330+ ) ;
278331 }
279332
280- let mut diag = infcx. tcx . sess . struct_span_err (
281- * span, & format ! ( "borrowed data escapes outside of closure" ) ,
282- ) ;
333+ let mut diag = infcx
334+ . tcx
335+ . sess
336+ . struct_span_err ( span, & format ! ( "borrowed data escapes outside of closure" ) ) ;
283337
284338 if let Some ( ( outlived_fr_name, outlived_fr_span) ) = outlived_fr_name_and_span {
285339 if let Some ( name) = outlived_fr_name {
@@ -294,10 +348,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
294348 if let Some ( name) = fr_name {
295349 diag. span_label (
296350 fr_span,
297- format ! ( "`{}` is a reference that is only valid in the closure body" , name) ,
351+ format ! (
352+ "`{}` is a reference that is only valid in the closure body" ,
353+ name
354+ ) ,
298355 ) ;
299356
300- diag. span_label ( * span, format ! ( "`{}` escapes the closure body here" , name) ) ;
357+ diag. span_label ( span, format ! ( "`{}` escapes the closure body here" , name) ) ;
301358 }
302359 }
303360
@@ -311,24 +368,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
311368 mir_def_id : DefId ,
312369 fr : RegionVid ,
313370 outlived_fr : RegionVid ,
314- category : & ConstraintCategory ,
315- span : & Span ,
371+ category : ConstraintCategory ,
372+ span : Span ,
316373 errors_buffer : & mut Vec < Diagnostic > ,
317374 ) {
318375 let mut diag = infcx. tcx . sess . struct_span_err (
319- * span, & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
376+ span,
377+ & format ! ( "unsatisfied lifetime constraints" ) , // FIXME
320378 ) ;
321379
322380 let counter = & mut 1 ;
323- let fr_name = self . give_region_a_name (
324- infcx. tcx , mir, mir_def_id, fr, counter, & mut diag) ;
325- let outlived_fr_name = self . give_region_a_name (
326- infcx. tcx , mir, mir_def_id, outlived_fr, counter, & mut diag) ;
327-
328- diag. span_label ( * span, format ! (
329- "{} requires that `{}` must outlive `{}`" ,
330- category, fr_name, outlived_fr_name,
331- ) ) ;
381+ let fr_name = self . give_region_a_name ( infcx. tcx , mir, mir_def_id, fr, counter, & mut diag) ;
382+ let outlived_fr_name =
383+ self . give_region_a_name ( infcx. tcx , mir, mir_def_id, outlived_fr, counter, & mut diag) ;
384+
385+ diag. span_label (
386+ span,
387+ format ! (
388+ "{} requires that `{}` must outlive `{}`" ,
389+ category, fr_name, outlived_fr_name,
390+ ) ,
391+ ) ;
332392
333393 diag. buffer ( errors_buffer) ;
334394 }
0 commit comments