@@ -16,9 +16,9 @@ use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
1616use rustc:: infer:: InferCtxt ;
1717use rustc:: mir:: { self , Location , Mir , Place , Rvalue , StatementKind , TerminatorKind } ;
1818use rustc:: ty:: RegionVid ;
19- use rustc_data_structures:: fx:: FxHashSet ;
2019use rustc_data_structures:: indexed_vec:: IndexVec ;
2120use rustc_errors:: Diagnostic ;
21+ use std:: collections:: VecDeque ;
2222use std:: fmt;
2323use syntax_pos:: Span ;
2424
@@ -54,6 +54,13 @@ impl fmt::Display for ConstraintCategory {
5454 }
5555}
5656
57+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
58+ enum Trace {
59+ StartRegion ,
60+ FromConstraint ( ConstraintIndex ) ,
61+ NotVisited ,
62+ }
63+
5764impl < ' tcx > RegionInferenceContext < ' tcx > {
5865 /// Walks the graph of constraints (where `'a: 'b` is considered
5966 /// an edge `'a -> 'b`) to find all paths from `from_region` to
@@ -64,56 +71,52 @@ impl<'tcx> RegionInferenceContext<'tcx> {
6471 & self ,
6572 from_region : RegionVid ,
6673 target_test : impl Fn ( RegionVid ) -> bool ,
67- ) -> Vec < Vec < ConstraintIndex > > {
68- let mut results = vec ! [ ] ;
69- self . find_constraint_paths_between_regions_helper (
70- from_region,
71- from_region,
72- & target_test,
73- & mut FxHashSet :: default ( ) ,
74- & mut vec ! [ ] ,
75- & mut results,
76- ) ;
77- results
78- }
74+ ) -> Option < Vec < ConstraintIndex > > {
75+ let mut context = IndexVec :: from_elem ( Trace :: NotVisited , & self . definitions ) ;
76+ context[ from_region] = Trace :: StartRegion ;
77+
78+ // Use a deque so that we do a breadth-first search. We will
79+ // stop at the first match, which ought to be the shortest
80+ // path (fewest constraints).
81+ let mut deque = VecDeque :: new ( ) ;
82+ deque. push_back ( from_region) ;
83+
84+ while let Some ( r) = deque. pop_front ( ) {
85+ // Check if we reached the region we were looking for. If so,
86+ // we can reconstruct the path that led to it and return it.
87+ if target_test ( r) {
88+ let mut result = vec ! [ ] ;
89+ let mut p = r;
90+ loop {
91+ match context[ p] {
92+ Trace :: NotVisited => bug ! ( "found unvisited region {:?} on path to {:?}" , p, r) ,
93+ Trace :: FromConstraint ( c) => {
94+ result. push ( c) ;
95+ p = self . constraints [ c] . sup ;
96+ }
7997
80- /// Helper for `find_constraint_paths_between_regions`.
81- fn find_constraint_paths_between_regions_helper (
82- & self ,
83- from_region : RegionVid ,
84- current_region : RegionVid ,
85- target_test : & impl Fn ( RegionVid ) -> bool ,
86- visited : & mut FxHashSet < RegionVid > ,
87- stack : & mut Vec < ConstraintIndex > ,
88- results : & mut Vec < Vec < ConstraintIndex > > ,
89- ) {
90- // Check if we already visited this region.
91- if !visited. insert ( current_region) {
92- return ;
93- }
98+ Trace :: StartRegion => {
99+ result. reverse ( ) ;
100+ return Some ( result) ;
101+ }
102+ }
103+ }
104+ }
94105
95- // Check if we reached the region we were looking for.
96- if target_test ( current_region) {
97- if !stack. is_empty ( ) {
98- assert_eq ! ( self . constraints[ stack[ 0 ] ] . sup, from_region) ;
99- results. push ( stack. clone ( ) ) ;
106+ // Otherwise, walk over the outgoing constraints and
107+ // enqueue any regions we find, keeping track of how we
108+ // reached them.
109+ for constraint in self . constraint_graph . outgoing_edges ( r) {
110+ assert_eq ! ( self . constraints[ constraint] . sup, r) ;
111+ let sub_region = self . constraints [ constraint] . sub ;
112+ if let Trace :: NotVisited = context[ sub_region] {
113+ context[ sub_region] = Trace :: FromConstraint ( constraint) ;
114+ deque. push_back ( sub_region) ;
115+ }
100116 }
101- return ;
102117 }
103118
104- for constraint in self . constraint_graph . outgoing_edges ( current_region) {
105- assert_eq ! ( self . constraints[ constraint] . sup, current_region) ;
106- stack. push ( constraint) ;
107- self . find_constraint_paths_between_regions_helper (
108- from_region,
109- self . constraints [ constraint] . sub ,
110- target_test,
111- visited,
112- stack,
113- results,
114- ) ;
115- stack. pop ( ) ;
116- }
119+ None
117120 }
118121
119122 /// This function will return true if a constraint is interesting and false if a constraint
@@ -204,12 +207,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
204207 debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
205208
206209 // Find all paths
207- let constraint_paths = self . find_constraint_paths_between_regions ( fr, |r| r == outlived_fr) ;
208- debug ! ( "report_error: constraint_paths={:#?}" , constraint_paths) ;
209-
210- // Find the shortest such path.
211- let path = constraint_paths. iter ( ) . min_by_key ( |p| p. len ( ) ) . unwrap ( ) ;
212- debug ! ( "report_error: shortest_path={:?}" , path) ;
210+ let path = self . find_constraint_paths_between_regions ( fr, |r| r == outlived_fr) . unwrap ( ) ;
211+ debug ! ( "report_error: path={:#?}" , path) ;
213212
214213 // Classify each of the constraints along the path.
215214 let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path. iter ( )
0 commit comments