@@ -23,7 +23,9 @@ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
23
23
use rustc:: util:: common:: { self , ErrorReported } ;
24
24
use rustc_data_structures:: bit_set:: BitSet ;
25
25
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
26
+ use crate :: rustc_data_structures:: graph:: WithSuccessors ;
26
27
use rustc_data_structures:: graph:: scc:: Sccs ;
28
+ use rustc_data_structures:: graph:: vec_graph:: VecGraph ;
27
29
use rustc_data_structures:: indexed_vec:: IndexVec ;
28
30
use rustc_errors:: { Diagnostic , DiagnosticBuilder } ;
29
31
use syntax_pos:: Span ;
@@ -60,10 +62,15 @@ pub struct RegionInferenceContext<'tcx> {
60
62
/// the SCC (see `constraint_sccs`) and for error reporting.
61
63
constraint_graph : Rc < NormalConstraintGraph > ,
62
64
63
- /// The SCC computed from `constraints` and the constraint graph. Used to
65
+ /// The SCC computed from `constraints` and the constraint
66
+ /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
64
67
/// compute the values of each region.
65
68
constraint_sccs : Rc < Sccs < RegionVid , ConstraintSccIndex > > ,
66
69
70
+ /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
71
+ /// exists if `B: A`. Computed lazilly.
72
+ rev_constraint_graph : Option < Rc < VecGraph < ConstraintSccIndex > > > ,
73
+
67
74
/// The "pick R0 from [R1..Rn]" constraints, indexed by SCC.
68
75
pick_constraints : Rc < PickConstraintSet < ' tcx , ConstraintSccIndex > > ,
69
76
@@ -234,6 +241,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
234
241
constraints,
235
242
constraint_graph,
236
243
constraint_sccs,
244
+ rev_constraint_graph : None ,
237
245
pick_constraints,
238
246
closure_bounds_mapping,
239
247
scc_universes,
@@ -602,21 +610,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
602
610
. universal_regions_outlived_by ( scc)
603
611
. all ( |lb| self . universal_region_relations . outlives ( o_r, lb) )
604
612
} ) ;
613
+ debug ! ( "apply_pick_constraint: after lb, option_regions={:?}" , option_regions) ;
605
614
606
615
// Now find all the *upper bounds* -- that is, each UB is a free
607
616
// region that must outlive pick region R0 (`UB: R0`). Therefore,
608
- // we need only keep an option O if `UB: O`.
609
- //
610
- // TODO -- need to implement the reverse graph construction for this
611
- //
612
- // let mut upper_bounds = ...;
613
- // option_regions.retain(|&o_r| {
614
- // upper_bounds
615
- // .all(|ub| self.universal_region_relations.outlives(
616
- // ub,
617
- // o_r,
618
- // })
619
- // });
617
+ // we need only keep an option O if `UB: O` for all UB.
618
+ if option_regions. len ( ) > 1 {
619
+ let universal_region_relations = self . universal_region_relations . clone ( ) ;
620
+ for ub in self . upper_bounds ( scc) {
621
+ debug ! ( "apply_pick_constraint: ub={:?}" , ub) ;
622
+ option_regions. retain ( |& o_r| universal_region_relations. outlives ( ub, o_r) ) ;
623
+ }
624
+ debug ! ( "apply_pick_constraint: after ub, option_regions={:?}" , option_regions) ;
625
+ }
620
626
621
627
// If we ruled everything out, we're done.
622
628
if option_regions. is_empty ( ) {
@@ -656,8 +662,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
656
662
}
657
663
}
658
664
659
- debug ! ( "apply_pick_constraint: best_choice={:?}" , best_option) ;
660
- self . scc_values . add_element ( scc, best_option)
665
+ let best_option_scc = self . constraint_sccs . scc ( best_option) ;
666
+ debug ! (
667
+ "apply_pick_constraint: best_choice={:?} best_option_scc={:?}" ,
668
+ best_option,
669
+ best_option_scc,
670
+ ) ;
671
+ self . scc_values . add_region ( scc, best_option_scc)
672
+ }
673
+
674
+ /// Compute and return the reverse SCC-based constraint graph (lazilly).
675
+ fn upper_bounds (
676
+ & mut self ,
677
+ scc0 : ConstraintSccIndex ,
678
+ ) -> Vec < RegionVid > {
679
+ // I wanted to return an `impl Iterator` here, but it's
680
+ // annoying because the `rev_constraint_graph` is in a local
681
+ // variable. We'd need a "once-cell" or some such thing to let
682
+ // us borrow it for the right amount of time.
683
+ let rev_constraint_graph = self . rev_constraint_graph ( ) ;
684
+ let scc_values = & self . scc_values ;
685
+ let mut duplicates = FxHashSet :: default ( ) ;
686
+ rev_constraint_graph
687
+ . depth_first_search ( scc0)
688
+ . skip ( 1 )
689
+ . flat_map ( |scc1| scc_values. universal_regions_outlived_by ( scc1) )
690
+ . filter ( |& r| duplicates. insert ( r) )
691
+ . collect ( )
692
+ }
693
+
694
+ /// Compute and return the reverse SCC-based constraint graph (lazilly).
695
+ fn rev_constraint_graph (
696
+ & mut self ,
697
+ ) -> Rc < VecGraph < ConstraintSccIndex > > {
698
+ if let Some ( g) = & self . rev_constraint_graph {
699
+ return g. clone ( ) ;
700
+ }
701
+
702
+ let rev_graph = Rc :: new ( self . constraint_sccs . reverse ( ) ) ;
703
+ self . rev_constraint_graph = Some ( rev_graph. clone ( ) ) ;
704
+ rev_graph
661
705
}
662
706
663
707
/// Returns `true` if all the elements in the value of `scc_b` are nameable
@@ -1145,8 +1189,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1145
1189
fn eval_outlives ( & self , sup_region : RegionVid , sub_region : RegionVid ) -> bool {
1146
1190
debug ! ( "eval_outlives({:?}: {:?})" , sup_region, sub_region) ;
1147
1191
1148
- debug ! ( "eval_outlives: sup_region's value = {:?}" , self . region_value_str( sup_region) , ) ;
1149
- debug ! ( "eval_outlives: sub_region's value = {:?}" , self . region_value_str( sub_region) , ) ;
1192
+ debug ! (
1193
+ "eval_outlives: sup_region's value = {:?} universal={:?}" ,
1194
+ self . region_value_str( sup_region) ,
1195
+ self . universal_regions. is_universal_region( sup_region) ,
1196
+ ) ;
1197
+ debug ! (
1198
+ "eval_outlives: sub_region's value = {:?} universal={:?}" ,
1199
+ self . region_value_str( sub_region) ,
1200
+ self . universal_regions. is_universal_region( sub_region) ,
1201
+ ) ;
1150
1202
1151
1203
let sub_region_scc = self . constraint_sccs . scc ( sub_region) ;
1152
1204
let sup_region_scc = self . constraint_sccs . scc ( sup_region) ;
0 commit comments