Skip to content

Commit 56274be

Browse files
committed
Added bfs for constraint paths from regions.
1 parent 9e2157f commit 56274be

File tree

1 file changed

+109
-1
lines changed
  • src/librustc_mir/borrow_check/nll/region_infer

1 file changed

+109
-1
lines changed

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc::mir::{
2626
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
2727
use rustc::util::common::{self, ErrorReported};
2828
use rustc_data_structures::bitvec::BitVector;
29+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
2930
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
3031
use std::rc::Rc;
3132
use syntax_pos::Span;
@@ -504,7 +505,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
504505
}
505506

506507
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) {
508510
continue;
509511
}
510512
}
@@ -963,6 +965,104 @@ impl<'tcx> RegionInferenceContext<'tcx> {
963965
}
964966
}
965967

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+
9661066
/// Report an error because the universal region `fr` was required to outlive
9671067
/// `outlived_fr` but it is not known to do so. For example:
9681068
///
@@ -992,6 +1092,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9921092
}
9931093
}
9941094

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+
9951103
let fr_string = match fr_name {
9961104
Some(r) => format!("free region `{}`", r),
9971105
None => format!("free region `{:?}`", fr),

0 commit comments

Comments
 (0)