10
10
11
11
use super :: universal_regions:: UniversalRegions ;
12
12
use borrow_check:: nll:: region_infer:: values:: ToElementIndex ;
13
- use borrow_check:: nll:: constraint_set:: { ConstraintIndex , ConstraintSet , OutlivesConstraint } ;
13
+ use borrow_check:: nll:: constraint_set:: { ConstraintIndex , ConstraintCategory , ConstraintSet } ;
14
+ use borrow_check:: nll:: constraint_set:: { OutlivesConstraint } ;
14
15
use borrow_check:: nll:: type_check:: Locations ;
15
16
use rustc:: hir:: def_id:: DefId ;
16
17
use rustc:: infer:: canonical:: QueryRegionConstraint ;
@@ -21,13 +22,14 @@ use rustc::infer::NLLRegionVariableOrigin;
21
22
use rustc:: infer:: RegionVariableOrigin ;
22
23
use rustc:: mir:: {
23
24
ClosureOutlivesRequirement , ClosureOutlivesSubject , ClosureRegionRequirements , Local , Location ,
24
- Mir ,
25
+ Mir , StatementKind , TerminatorKind , Rvalue
25
26
} ;
26
27
use rustc:: ty:: { self , RegionVid , Ty , TyCtxt , TypeFoldable } ;
27
28
use rustc:: util:: common:: { self , ErrorReported } ;
28
29
use rustc_data_structures:: bitvec:: BitVector ;
29
30
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
30
31
use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
32
+
31
33
use std:: rc:: Rc ;
32
34
use syntax_pos:: Span ;
33
35
@@ -961,10 +963,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
961
963
// Note: in this case, we use the unapproximated regions
962
964
// to report the error. This gives better error messages
963
965
// in some cases.
964
- self . report_error ( infcx, mir_def_id, longer_fr, shorter_fr, blame_span) ;
966
+ self . report_error ( mir , infcx, mir_def_id, longer_fr, shorter_fr, blame_span) ;
965
967
}
966
968
}
967
969
970
+ /// When reporting an error, it is useful to be able to determine which constraints influenced
971
+ /// the region being reported as an error. This function finds all of the paths from the
972
+ /// constraint.
968
973
fn find_constraint_paths_from_region (
969
974
& self ,
970
975
r0 : RegionVid
@@ -1055,6 +1060,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1055
1060
paths
1056
1061
}
1057
1062
1063
+ /// This function will return true if a constraint is interesting and false if a constraint
1064
+ /// is not. It is useful in filtering constraint paths to only interesting points.
1058
1065
fn constraint_is_interesting ( & self , index : & ConstraintIndex ) -> bool {
1059
1066
self . constraints . get ( * index) . filter ( |constraint| {
1060
1067
debug ! ( "constraint_is_interesting: locations={:?} constraint={:?}" ,
@@ -1063,6 +1070,32 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1063
1070
} ) . is_some ( )
1064
1071
}
1065
1072
1073
+ /// This function classifies a constraint from a location.
1074
+ fn classify_constraint ( & self , location : Location , mir : & Mir < ' tcx > ) -> ConstraintCategory {
1075
+ let data = & mir[ location. block ] ;
1076
+ if location. statement_index == data. statements . len ( ) {
1077
+ if let Some ( ref terminator) = data. terminator {
1078
+ match terminator. kind {
1079
+ TerminatorKind :: DropAndReplace { .. } => ConstraintCategory :: Assignment ,
1080
+ TerminatorKind :: Call { .. } => ConstraintCategory :: CallArgument ,
1081
+ _ => ConstraintCategory :: Other ,
1082
+ }
1083
+ } else {
1084
+ ConstraintCategory :: Other
1085
+ }
1086
+ } else {
1087
+ let statement = & data. statements [ location. statement_index ] ;
1088
+ match statement. kind {
1089
+ StatementKind :: Assign ( _, ref rvalue) => match rvalue {
1090
+ Rvalue :: Cast ( ..) => ConstraintCategory :: Cast ,
1091
+ Rvalue :: Use ( ..) => ConstraintCategory :: Assignment ,
1092
+ _ => ConstraintCategory :: Other ,
1093
+ } ,
1094
+ _ => ConstraintCategory :: Other ,
1095
+ }
1096
+ }
1097
+ }
1098
+
1066
1099
/// Report an error because the universal region `fr` was required to outlive
1067
1100
/// `outlived_fr` but it is not known to do so. For example:
1068
1101
///
@@ -1073,6 +1106,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1073
1106
/// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
1074
1107
fn report_error (
1075
1108
& self ,
1109
+ mir : & Mir < ' tcx > ,
1076
1110
infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
1077
1111
mir_def_id : DefId ,
1078
1112
fr : RegionVid ,
@@ -1095,27 +1129,57 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1095
1129
let constraints = self . find_constraint_paths_from_region ( fr. clone ( ) ) ;
1096
1130
let path = constraints. iter ( ) . min_by_key ( |p| p. len ( ) ) . unwrap ( ) ;
1097
1131
debug ! ( "report_error: path={:?}" , path) ;
1132
+
1098
1133
let path = path. iter ( )
1099
1134
. filter ( |index| self . constraint_is_interesting ( index) )
1100
1135
. collect :: < Vec < & ConstraintIndex > > ( ) ;
1101
1136
debug ! ( "report_error: path={:?}" , path) ;
1102
1137
1103
- let fr_string = match fr_name {
1104
- Some ( r) => format ! ( "free region `{}`" , r) ,
1105
- None => format ! ( "free region `{:?}`" , fr) ,
1106
- } ;
1138
+ let mut categorized_path = path. iter ( ) . filter_map ( |index| {
1139
+ self . constraints . get ( * * index) . iter ( ) . filter_map ( |constraint| {
1140
+ let span = constraint. locations . span ( mir) ;
1141
+ constraint. locations . from_location ( ) . iter ( ) . filter_map ( |location| {
1142
+ let classification = self . classify_constraint ( * location, mir) ;
1143
+ Some ( ( classification, span) )
1144
+ } ) . next ( )
1145
+ } ) . next ( )
1146
+ } ) . collect :: < Vec < ( ConstraintCategory , Span ) > > ( ) ;
1147
+ debug ! ( "report_error: categorized_path={:?}" , categorized_path) ;
1148
+
1149
+ categorized_path. sort_by ( |p0, p1| p0. 0 . cmp ( & p1. 0 ) ) ;
1150
+ debug ! ( "report_error: sorted_path={:?}" , categorized_path) ;
1151
+
1152
+ if categorized_path. len ( ) > 0 {
1153
+ let blame_constraint = & categorized_path[ 0 ] ;
1154
+
1155
+ let mut diag = infcx. tcx . sess . struct_span_err (
1156
+ blame_constraint. 1 ,
1157
+ & format ! ( "{:?}" , blame_constraint. 0 ) ,
1158
+ ) ;
1107
1159
1108
- let outlived_fr_string = match outlived_fr_name {
1109
- Some ( r) => format ! ( "free region `{}`" , r) ,
1110
- None => format ! ( "free region `{:?}`" , outlived_fr) ,
1111
- } ;
1160
+ for secondary in categorized_path. iter ( ) . skip ( 1 ) {
1161
+ diag. span_label ( secondary. 1 , format ! ( "{:?}" , secondary. 0 ) ) ;
1162
+ }
1112
1163
1113
- let mut diag = infcx. tcx . sess . struct_span_err (
1114
- blame_span,
1115
- & format ! ( "{} does not outlive {}" , fr_string, outlived_fr_string, ) ,
1116
- ) ;
1164
+ diag. emit ( ) ;
1165
+ } else {
1166
+ let fr_string = match fr_name {
1167
+ Some ( r) => format ! ( "free region `{}`" , r) ,
1168
+ None => format ! ( "free region `{:?}`" , fr) ,
1169
+ } ;
1170
+
1171
+ let outlived_fr_string = match outlived_fr_name {
1172
+ Some ( r) => format ! ( "free region `{}`" , r) ,
1173
+ None => format ! ( "free region `{:?}`" , outlived_fr) ,
1174
+ } ;
1175
+
1176
+ let mut diag = infcx. tcx . sess . struct_span_err (
1177
+ blame_span,
1178
+ & format ! ( "{} does not outlive {}" , fr_string, outlived_fr_string, ) ,
1179
+ ) ;
1117
1180
1118
- diag. emit ( ) ;
1181
+ diag. emit ( ) ;
1182
+ }
1119
1183
}
1120
1184
1121
1185
crate fn why_region_contains_point ( & self , fr1 : RegionVid , elem : Location ) -> Option < Cause > {
0 commit comments