@@ -16,9 +16,9 @@ use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
16
16
use rustc:: infer:: InferCtxt ;
17
17
use rustc:: mir:: { self , Location , Mir , Place , Rvalue , StatementKind , TerminatorKind } ;
18
18
use rustc:: ty:: RegionVid ;
19
- use rustc_data_structures:: fx:: FxHashSet ;
20
19
use rustc_data_structures:: indexed_vec:: IndexVec ;
21
20
use rustc_errors:: Diagnostic ;
21
+ use std:: collections:: VecDeque ;
22
22
use std:: fmt;
23
23
use syntax_pos:: Span ;
24
24
@@ -54,6 +54,13 @@ impl fmt::Display for ConstraintCategory {
54
54
}
55
55
}
56
56
57
+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
58
+ enum Trace {
59
+ StartRegion ,
60
+ FromConstraint ( ConstraintIndex ) ,
61
+ NotVisited ,
62
+ }
63
+
57
64
impl < ' tcx > RegionInferenceContext < ' tcx > {
58
65
/// Walks the graph of constraints (where `'a: 'b` is considered
59
66
/// an edge `'a -> 'b`) to find all paths from `from_region` to
@@ -64,56 +71,52 @@ impl<'tcx> RegionInferenceContext<'tcx> {
64
71
& self ,
65
72
from_region : RegionVid ,
66
73
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
+ }
79
97
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
+ }
94
105
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
+ }
100
116
}
101
- return ;
102
117
}
103
118
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
117
120
}
118
121
119
122
/// This function will return true if a constraint is interesting and false if a constraint
@@ -204,12 +207,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
204
207
debug ! ( "report_error(fr={:?}, outlived_fr={:?})" , fr, outlived_fr) ;
205
208
206
209
// 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) ;
213
212
214
213
// Classify each of the constraints along the path.
215
214
let mut categorized_path: Vec < ( ConstraintCategory , Span ) > = path. iter ( )
0 commit comments