8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ use std:: fmt;
11
12
use borrow_check:: nll:: region_infer:: { Cause , ConstraintIndex , RegionInferenceContext } ;
12
13
use borrow_check:: nll:: region_infer:: values:: ToElementIndex ;
13
14
use borrow_check:: nll:: type_check:: Locations ;
14
15
use rustc:: hir:: def_id:: DefId ;
15
16
use rustc:: infer:: InferCtxt ;
16
17
use 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 } ;
18
19
use rustc:: ty:: RegionVid ;
19
20
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
20
21
use rustc_data_structures:: indexed_vec:: IndexVec ;
21
22
use syntax_pos:: Span ;
22
23
23
24
/// 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.
25
27
#[ derive( Debug , Eq , PartialEq , PartialOrd , Ord ) ]
26
28
enum ConstraintCategory {
27
- Assignment ,
28
29
Cast ,
30
+ Assignment ,
31
+ Return ,
29
32
CallArgument ,
30
33
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
+ }
31
47
}
32
48
33
49
impl < ' tcx > RegionInferenceContext < ' tcx > {
@@ -132,9 +148,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
132
148
}
133
149
134
150
/// 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
+
136
161
let data = & mir[ location. block ] ;
137
- if location. statement_index == data. statements . len ( ) {
162
+ let category = if location. statement_index == data. statements . len ( ) {
138
163
if let Some ( ref terminator) = data. terminator {
139
164
match terminator. kind {
140
165
TerminatorKind :: DropAndReplace { .. } => ConstraintCategory :: Assignment ,
@@ -147,14 +172,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
147
172
} else {
148
173
let statement = & data. statements [ location. statement_index ] ;
149
174
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
+ }
154
185
} ,
155
186
_ => ConstraintCategory :: Other ,
156
187
}
157
- }
188
+ } ;
189
+
190
+ Some ( ( category, span) )
158
191
}
159
192
160
193
/// Report an error because the universal region `fr` was required to outlive
@@ -187,53 +220,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
187
220
}
188
221
}
189
222
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
+
190
233
let constraints = self . find_constraint_paths_from_region ( fr. clone ( ) ) ;
191
234
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) ;
198
236
199
237
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)
207
239
} ) . collect :: < Vec < ( ConstraintCategory , Span ) > > ( ) ;
208
240
debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
209
241
210
242
categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
211
243
debug ! ( "report_error: sorted_path={:?}" , categorized_path) ;
212
244
213
- if categorized_path. len ( ) > 0 {
214
- let blame_constraint = & categorized_path[ 0 ] ;
215
-
245
+ if let Some ( ( category, span) ) = & categorized_path. first ( ) {
216
246
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 ) ,
219
249
) ;
220
250
221
- for secondary in categorized_path. iter ( ) . skip ( 1 ) {
222
- diag. span_label ( secondary. 1 , format ! ( "{:?}" , secondary. 0 ) ) ;
223
- }
224
-
225
251
diag. emit ( ) ;
226
252
} 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
-
237
253
let mut diag = infcx. tcx . sess . struct_span_err (
238
254
blame_span,
239
255
& format ! ( "{} does not outlive {}" , fr_string, outlived_fr_string, ) ,
0 commit comments