88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ use std:: fmt;
1112use borrow_check:: nll:: region_infer:: { Cause , ConstraintIndex , RegionInferenceContext } ;
1213use borrow_check:: nll:: region_infer:: values:: ToElementIndex ;
1314use borrow_check:: nll:: type_check:: Locations ;
1415use rustc:: hir:: def_id:: DefId ;
1516use rustc:: infer:: InferCtxt ;
1617use rustc:: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
17- use rustc:: mir:: { Location , Mir , StatementKind , TerminatorKind , Rvalue } ;
18+ use rustc:: mir:: { self , Location , Mir , Place , StatementKind , TerminatorKind , Rvalue } ;
1819use rustc:: ty:: RegionVid ;
1920use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2021use rustc_data_structures:: indexed_vec:: IndexVec ;
2122use syntax_pos:: Span ;
2223
2324/// Constraints that are considered interesting can be categorized to
24- /// determine why they are interesting.
25+ /// determine why they are interesting. Order of variants indicates
26+ /// sort order of the category, thereby influencing diagnostic output.
2527#[ derive( Debug , Eq , PartialEq , PartialOrd , Ord ) ]
2628enum ConstraintCategory {
27- Assignment ,
2829 Cast ,
30+ Assignment ,
31+ Return ,
2932 CallArgument ,
3033 Other ,
34+ Boring ,
35+ }
36+
37+ impl fmt:: Display for ConstraintCategory {
38+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
39+ match self {
40+ ConstraintCategory :: Assignment => write ! ( f, "Assignment" ) ,
41+ ConstraintCategory :: Return => write ! ( f, "Return" ) ,
42+ ConstraintCategory :: Cast => write ! ( f, "Cast" ) ,
43+ ConstraintCategory :: CallArgument => write ! ( f, "Argument" ) ,
44+ _ => write ! ( f, "Free region" ) ,
45+ }
46+ }
3147}
3248
3349impl < ' tcx > RegionInferenceContext < ' tcx > {
@@ -132,9 +148,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
132148 }
133149
134150 /// This function classifies a constraint from a location.
135- fn classify_constraint ( & self , location : Location , mir : & Mir < ' tcx > ) -> ConstraintCategory {
151+ fn classify_constraint ( & self , index : & ConstraintIndex ,
152+ mir : & Mir < ' tcx > ) -> Option < ( ConstraintCategory , Span ) > {
153+ let constraint = self . constraints . get ( * index) ?;
154+ let span = constraint. locations . span ( mir) ;
155+ let location = constraint. locations . from_location ( ) ?;
156+
157+ if !self . constraint_is_interesting ( index) {
158+ return Some ( ( ConstraintCategory :: Boring , span) ) ;
159+ }
160+
136161 let data = & mir[ location. block ] ;
137- if location. statement_index == data. statements . len ( ) {
162+ let category = if location. statement_index == data. statements . len ( ) {
138163 if let Some ( ref terminator) = data. terminator {
139164 match terminator. kind {
140165 TerminatorKind :: DropAndReplace { .. } => ConstraintCategory :: Assignment ,
@@ -147,14 +172,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
147172 } else {
148173 let statement = & data. statements [ location. statement_index ] ;
149174 match statement. kind {
150- StatementKind :: Assign ( _, ref rvalue) => match rvalue {
151- Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
152- Rvalue :: Use ( ..) => ConstraintCategory :: Assignment ,
153- _ => ConstraintCategory :: Other ,
175+ StatementKind :: Assign ( ref place, ref rvalue) => {
176+ if * place == Place :: Local ( mir:: RETURN_PLACE ) {
177+ ConstraintCategory :: Return
178+ } else {
179+ match rvalue {
180+ Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
181+ Rvalue :: Use ( ..) => ConstraintCategory :: Assignment ,
182+ _ => ConstraintCategory :: Other ,
183+ }
184+ }
154185 } ,
155186 _ => ConstraintCategory :: Other ,
156187 }
157- }
188+ } ;
189+
190+ Some ( ( category, span) )
158191 }
159192
160193 /// Report an error because the universal region `fr` was required to outlive
@@ -187,53 +220,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
187220 }
188221 }
189222
223+ let fr_string = match fr_name {
224+ Some ( r) => format ! ( "free region `{}`" , r) ,
225+ None => format ! ( "free region `{:?}`" , fr) ,
226+ } ;
227+
228+ let outlived_fr_string = match outlived_fr_name {
229+ Some ( r) => format ! ( "free region `{}`" , r) ,
230+ None => format ! ( "free region `{:?}`" , outlived_fr) ,
231+ } ;
232+
190233 let constraints = self . find_constraint_paths_from_region ( fr. clone ( ) ) ;
191234 let path = constraints. iter ( ) . min_by_key ( |p| p. len ( ) ) . unwrap ( ) ;
192- debug ! ( "report_error: path={:?}" , path) ;
193-
194- let path = path. iter ( )
195- . filter ( |index| self . constraint_is_interesting ( index) )
196- . collect :: < Vec < & ConstraintIndex > > ( ) ;
197- debug ! ( "report_error: path={:?}" , path) ;
235+ debug ! ( "report_error: shortest_path={:?}" , path) ;
198236
199237 let mut categorized_path = path. iter ( ) . filter_map ( |index| {
200- self . constraints . get ( * * index) . iter ( ) . filter_map ( |constraint| {
201- let span = constraint. locations . span ( mir) ;
202- constraint. locations . from_location ( ) . iter ( ) . filter_map ( |location| {
203- let classification = self . classify_constraint ( * location, mir) ;
204- Some ( ( classification, span) )
205- } ) . next ( )
206- } ) . next ( )
238+ self . classify_constraint ( index, mir)
207239 } ) . collect :: < Vec < ( ConstraintCategory , Span ) > > ( ) ;
208240 debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
209241
210242 categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
211243 debug ! ( "report_error: sorted_path={:?}" , categorized_path) ;
212244
213- if categorized_path. len ( ) > 0 {
214- let blame_constraint = & categorized_path[ 0 ] ;
215-
245+ if let Some ( ( category, span) ) = & categorized_path. first ( ) {
216246 let mut diag = infcx. tcx . sess . struct_span_err (
217- blame_constraint . 1 ,
218- & format ! ( "{:?}" , blame_constraint . 0 ) ,
247+ * span , & format ! ( "{} requires that data must outlive {}" ,
248+ category , outlived_fr_string ) ,
219249 ) ;
220250
221- for secondary in categorized_path. iter ( ) . skip ( 1 ) {
222- diag. span_label ( secondary. 1 , format ! ( "{:?}" , secondary. 0 ) ) ;
223- }
224-
225251 diag. emit ( ) ;
226252 } else {
227- let fr_string = match fr_name {
228- Some ( r) => format ! ( "free region `{}`" , r) ,
229- None => format ! ( "free region `{:?}`" , fr) ,
230- } ;
231-
232- let outlived_fr_string = match outlived_fr_name {
233- Some ( r) => format ! ( "free region `{}`" , r) ,
234- None => format ! ( "free region `{:?}`" , outlived_fr) ,
235- } ;
236-
237253 let mut diag = infcx. tcx . sess . struct_span_err (
238254 blame_span,
239255 & format ! ( "{} does not outlive {}" , fr_string, outlived_fr_string, ) ,
0 commit comments