@@ -26,6 +26,7 @@ use rustc::mir::{
26
26
use rustc:: ty:: { self , RegionVid , Ty , TyCtxt , TypeFoldable } ;
27
27
use rustc:: util:: common:: { self , ErrorReported } ;
28
28
use rustc_data_structures:: bitvec:: BitVector ;
29
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
29
30
use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
30
31
use std:: rc:: Rc ;
31
32
use syntax_pos:: Span ;
@@ -504,7 +505,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
504
505
}
505
506
506
507
if let Some ( propagated_outlives_requirements) = & mut propagated_outlives_requirements {
507
- if self . try_promote_type_test ( infcx, mir, type_test, propagated_outlives_requirements) {
508
+ if self . try_promote_type_test ( infcx, mir, type_test,
509
+ propagated_outlives_requirements) {
508
510
continue ;
509
511
}
510
512
}
@@ -963,6 +965,104 @@ impl<'tcx> RegionInferenceContext<'tcx> {
963
965
}
964
966
}
965
967
968
+ fn find_constraint_paths_from_region (
969
+ & self ,
970
+ r0 : RegionVid
971
+ ) -> Vec < Vec < ConstraintIndex > > {
972
+ let constraints = self . constraints . clone ( ) ;
973
+
974
+ // Mapping of regions to the previous region and constraint index that led to it.
975
+ let mut previous = FxHashMap ( ) ;
976
+ // Current region in traversal.
977
+ let mut current = r0;
978
+ // Regions yet to be visited.
979
+ let mut next = vec ! [ current ] ;
980
+ // Regions that have been visited.
981
+ let mut visited = FxHashSet ( ) ;
982
+ // Ends of paths.
983
+ let mut end_regions: Vec < RegionVid > = Vec :: new ( ) ;
984
+
985
+ // When we've still got points to visit...
986
+ while !next. is_empty ( ) {
987
+ // ...take the next point...
988
+ debug ! ( "find_constraint_paths_from_region: next={:?}" , next) ;
989
+ current = next. pop ( ) . unwrap ( ) ; // Can unwrap here as we know the vector is not empty.
990
+
991
+ // ...find the edges containing it...
992
+ let mut upcoming = Vec :: new ( ) ;
993
+ for ( index, constraint) in constraints. iter_enumerated ( ) {
994
+ if constraint. sub == current {
995
+ // ...add the regions that join us with to the path we've taken...
996
+ debug ! ( "find_constraint_paths_from_region: index={:?} constraint={:?}" ,
997
+ index, constraint) ;
998
+ let next_region = constraint. sup . clone ( ) ;
999
+
1000
+ // ...unless we've visited it since this was added...
1001
+ if visited. contains ( & next_region) {
1002
+ debug ! ( "find_constraint_paths_from_region: skipping as visited" ) ;
1003
+ continue ;
1004
+ }
1005
+
1006
+ previous. insert ( next_region, ( index, Some ( current) ) ) ;
1007
+ upcoming. push ( next_region) ;
1008
+ }
1009
+ }
1010
+
1011
+ if upcoming. is_empty ( ) {
1012
+ // If we didn't find any edges then this is the end of a path...
1013
+ debug ! ( "find_constraint_paths_from_region: new end region current={:?}" , current) ;
1014
+ end_regions. push ( current) ;
1015
+ } else {
1016
+ // ...but, if we did find edges, then add these to the regions yet to visit...
1017
+ debug ! ( "find_constraint_paths_from_region: extend next upcoming={:?}" , upcoming) ;
1018
+ next. extend ( upcoming) ;
1019
+ }
1020
+
1021
+ // ...and don't visit it again.
1022
+ visited. insert ( current. clone ( ) ) ;
1023
+ debug ! ( "find_constraint_paths_from_region: next={:?} visited={:?}" , next, visited) ;
1024
+ }
1025
+
1026
+ // Now we've visited each point, compute the final paths.
1027
+ let mut paths: Vec < Vec < ConstraintIndex > > = Vec :: new ( ) ;
1028
+ debug ! ( "find_constraint_paths_from_region: end_regions={:?}" , end_regions) ;
1029
+ for end_region in end_regions {
1030
+ debug ! ( "find_constraint_paths_from_region: end_region={:?}" , end_region) ;
1031
+
1032
+ // Get the constraint and region that led to this end point.
1033
+ // We can unwrap as we know if end_point was in the vector that it
1034
+ // must also be in our previous map.
1035
+ let ( mut index, mut region) = previous. get ( & end_region) . unwrap ( ) ;
1036
+ debug ! ( "find_constraint_paths_from_region: index={:?} region={:?}" , index, region) ;
1037
+
1038
+ // Keep track of the indices.
1039
+ let mut path: Vec < ConstraintIndex > = vec ! [ index] ;
1040
+
1041
+ while region. is_some ( ) && region != Some ( r0) {
1042
+ let p = previous. get ( & region. unwrap ( ) ) . unwrap ( ) ;
1043
+ index = p. 0 ;
1044
+ region = p. 1 ;
1045
+
1046
+ debug ! ( "find_constraint_paths_from_region: index={:?} region={:?}" , index, region) ;
1047
+ path. push ( index) ;
1048
+ }
1049
+
1050
+ // Add to our paths.
1051
+ paths. push ( path) ;
1052
+ }
1053
+
1054
+ debug ! ( "find_constraint_paths_from_region: paths={:?}" , paths) ;
1055
+ paths
1056
+ }
1057
+
1058
+ fn constraint_is_interesting ( & self , index : & ConstraintIndex ) -> bool {
1059
+ self . constraints . get ( * index) . filter ( |constraint| {
1060
+ debug ! ( "constraint_is_interesting: locations={:?} constraint={:?}" ,
1061
+ constraint. locations, constraint) ;
1062
+ if let Locations :: Interesting ( _) = constraint. locations { true } else { false }
1063
+ } ) . is_some ( )
1064
+ }
1065
+
966
1066
/// Report an error because the universal region `fr` was required to outlive
967
1067
/// `outlived_fr` but it is not known to do so. For example:
968
1068
///
@@ -992,6 +1092,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
992
1092
}
993
1093
}
994
1094
1095
+ let constraints = self . find_constraint_paths_from_region ( fr. clone ( ) ) ;
1096
+ let path = constraints. iter ( ) . min_by_key ( |p| p. len ( ) ) . unwrap ( ) ;
1097
+ debug ! ( "report_error: path={:?}" , path) ;
1098
+ let path = path. iter ( )
1099
+ . filter ( |index| self . constraint_is_interesting ( index) )
1100
+ . collect :: < Vec < & ConstraintIndex > > ( ) ;
1101
+ debug ! ( "report_error: path={:?}" , path) ;
1102
+
995
1103
let fr_string = match fr_name {
996
1104
Some ( r) => format ! ( "free region `{}`" , r) ,
997
1105
None => format ! ( "free region `{:?}`" , fr) ,
0 commit comments