88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use std:: collections:: HashMap ;
12-
1311use super :: universal_regions:: UniversalRegions ;
1412use rustc:: hir:: def_id:: DefId ;
1513use rustc:: infer:: InferCtxt ;
@@ -23,9 +21,9 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegi
2321 Local , Location , Mir } ;
2422use rustc:: traits:: ObligationCause ;
2523use rustc:: ty:: { self , RegionVid , Ty , TypeFoldable } ;
26- use rustc:: util:: common:: ErrorReported ;
24+ use rustc:: util:: common:: { self , ErrorReported } ;
2725use rustc_data_structures:: bitvec:: BitVector ;
28- use rustc_data_structures:: indexed_vec:: IndexVec ;
26+ use rustc_data_structures:: indexed_vec:: { Idx , IndexVec } ;
2927use std:: fmt;
3028use std:: rc:: Rc ;
3129use syntax:: ast;
@@ -61,8 +59,15 @@ pub struct RegionInferenceContext<'tcx> {
6159 /// until `solve` is invoked.
6260 inferred_values : Option < RegionValues > ,
6361
62+ /// For each variable, stores the index of the first constraint
63+ /// where that variable appears on the RHS. This is the start of a
64+ /// 'linked list' threaded by the `next` field in `Constraint`.
65+ ///
66+ /// This map is build when values are inferred.
67+ dependency_map : Option < IndexVec < RegionVid , Option < ConstraintIndex > > > ,
68+
6469 /// The constraints we have accumulated and used during solving.
65- constraints : Vec < Constraint > ,
70+ constraints : IndexVec < ConstraintIndex , Constraint > ,
6671
6772 /// Type constraints that we check after solving.
6873 type_tests : Vec < TypeTest < ' tcx > > ,
@@ -143,10 +148,22 @@ pub struct Constraint {
143148 /// At this location.
144149 point : Location ,
145150
151+ /// Later on, we thread the constraints onto a linked list
152+ /// sorted by their `sub` field. So if you had:
153+ ///
154+ /// Index | Constraint | Next Field
155+ /// ----- | ---------- | ----------
156+ /// 0 | `'a: 'b` | Some(2)
157+ /// 1 | `'b: 'c` | None
158+ /// 2 | `'c: 'b` | None
159+ next : Option < ConstraintIndex > ,
160+
146161 /// Where did this constraint arise?
147162 span : Span ,
148163}
149164
165+ newtype_index ! ( ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" } ) ;
166+
150167/// A "type test" corresponds to an outlives constraint between a type
151168/// and a lifetime, like `T: 'x` or `<T as Foo>::Bar: 'x`. They are
152169/// translated from the `Verify` region constraints in the ordinary
@@ -259,7 +276,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
259276 elements : elements. clone ( ) ,
260277 liveness_constraints : RegionValues :: new ( elements, num_region_variables) ,
261278 inferred_values : None ,
262- constraints : Vec :: new ( ) ,
279+ dependency_map : None ,
280+ constraints : IndexVec :: new ( ) ,
263281 type_tests : Vec :: new ( ) ,
264282 universal_regions,
265283 } ;
@@ -387,6 +405,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
387405 sup,
388406 sub,
389407 point,
408+ next : None ,
390409 } ) ;
391410 }
392411
@@ -403,6 +422,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
403422 infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
404423 mir : & Mir < ' tcx > ,
405424 mir_def_id : DefId ,
425+ ) -> Option < ClosureRegionRequirements < ' gcx > > {
426+ common:: time ( infcx. tcx . sess , & format ! ( "solve({:?})" , mir_def_id) , || {
427+ self . solve_inner ( infcx, mir, mir_def_id)
428+ } )
429+ }
430+
431+ fn solve_inner < ' gcx > (
432+ & mut self ,
433+ infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
434+ mir : & Mir < ' tcx > ,
435+ mir_def_id : DefId ,
406436 ) -> Option < ClosureRegionRequirements < ' gcx > > {
407437 assert ! ( self . inferred_values. is_none( ) , "values already inferred" ) ;
408438
@@ -448,6 +478,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
448478 /// satisfied. Note that some values may grow **too** large to be
449479 /// feasible, but we check this later.
450480 fn propagate_constraints ( & mut self , mir : & Mir < ' tcx > ) {
481+ self . dependency_map = Some ( self . build_dependency_map ( ) ) ;
451482 let inferred_values = self . compute_region_values ( mir, TrackCauses ( false ) ) ;
452483 self . inferred_values = Some ( inferred_values) ;
453484 }
@@ -465,17 +496,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
465496 // constraints we have accumulated.
466497 let mut inferred_values = self . liveness_constraints . duplicate ( track_causes) ;
467498
468- let dependency_map = self . build_dependency_map ( ) ;
499+ let dependency_map = self . dependency_map . as_ref ( ) . unwrap ( ) ;
469500
470501 // Constraints that may need to be repropagated (initially all):
471- let mut dirty_list: Vec < _ > = ( 0 .. self . constraints . len ( ) ) . collect ( ) ;
502+ let mut dirty_list: Vec < _ > = self . constraints . indices ( ) . collect ( ) ;
472503
473504 // Set to 0 for each constraint that is on the dirty list:
474505 let mut clean_bit_vec = BitVector :: new ( dirty_list. len ( ) ) ;
475506
476507 debug ! ( "propagate_constraints: --------------------" ) ;
477508 while let Some ( constraint_idx) = dirty_list. pop ( ) {
478- clean_bit_vec. insert ( constraint_idx) ;
509+ clean_bit_vec. insert ( constraint_idx. index ( ) ) ;
479510
480511 let constraint = & self . constraints [ constraint_idx] ;
481512 debug ! ( "propagate_constraints: constraint={:?}" , constraint) ;
@@ -497,10 +528,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
497528 debug ! ( "propagate_constraints: sub={:?}" , constraint. sub) ;
498529 debug ! ( "propagate_constraints: sup={:?}" , constraint. sup) ;
499530
500- for & dep_idx in dependency_map. get ( & constraint. sup ) . unwrap_or ( & vec ! [ ] ) {
501- if clean_bit_vec. remove ( dep_idx) {
531+ let mut opt_dep_idx = dependency_map[ constraint. sup ] ;
532+ while let Some ( dep_idx) = opt_dep_idx {
533+ if clean_bit_vec. remove ( dep_idx. index ( ) ) {
502534 dirty_list. push ( dep_idx) ;
503535 }
536+ opt_dep_idx = self . constraints [ dep_idx] . next ;
504537 }
505538 }
506539
@@ -514,11 +547,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
514547 /// indices of constraints that need to be re-evaluated when X changes.
515548 /// These are constraints like Y: X @ P -- so if X changed, we may
516549 /// need to grow Y.
517- fn build_dependency_map ( & self ) -> HashMap < RegionVid , Vec < usize > > {
518- let mut map = HashMap :: new ( ) ;
519-
520- for ( idx, constraint) in self . constraints . iter ( ) . enumerate ( ) {
521- map. entry ( constraint. sub ) . or_insert ( Vec :: new ( ) ) . push ( idx) ;
550+ #[ inline( never) ]
551+ fn build_dependency_map ( & mut self ) -> IndexVec < RegionVid , Option < ConstraintIndex > > {
552+ let mut map = IndexVec :: from_elem ( None , & self . definitions ) ;
553+
554+ for ( idx, constraint) in self . constraints . iter_enumerated_mut ( ) . rev ( ) {
555+ let mut head = & mut map[ constraint. sub ] ;
556+ debug_assert ! ( constraint. next. is_none( ) ) ;
557+ constraint. next = * head;
558+ * head = Some ( idx) ;
522559 }
523560
524561 map
0 commit comments