Skip to content

Commit 38755e6

Browse files
committed
Always check upper bounds when choosing member regions
Also correctly calculate what the upper bounds are.
1 parent 4b8b0e8 commit 38755e6

File tree

2 files changed

+81
-40
lines changed

2 files changed

+81
-40
lines changed

src/librustc_mir/borrow_check/region_infer/mod.rs

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
1111
use rustc_data_structures::binary_search_util;
1212
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1313
use rustc_data_structures::graph::scc::Sccs;
14-
use rustc_data_structures::graph::vec_graph::VecGraph;
15-
use rustc_data_structures::graph::WithSuccessors;
1614
use rustc_hir::def_id::DefId;
1715
use rustc_index::bit_set::BitSet;
1816
use rustc_index::vec::IndexVec;
@@ -25,6 +23,7 @@ use crate::borrow_check::{
2523
diagnostics::{RegionErrorKind, RegionErrors},
2624
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
2725
nll::{PoloniusOutput, ToRegionVid},
26+
region_infer::reverse_sccs::ReverseSccGraph,
2827
region_infer::values::{
2928
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
3029
ToElementIndex,
@@ -36,6 +35,7 @@ use crate::borrow_check::{
3635
mod dump_mir;
3736
mod graphviz;
3837
mod opaque_types;
38+
mod reverse_sccs;
3939

4040
pub mod values;
4141

@@ -65,9 +65,10 @@ pub struct RegionInferenceContext<'tcx> {
6565
/// compute the values of each region.
6666
pub(in crate::borrow_check) constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
6767

68-
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
69-
/// exists if `B: A`. Computed lazilly.
70-
pub(in crate::borrow_check) rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
68+
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
69+
/// `B: A`. This is used to compute the universal regions that are required
70+
/// to outlive a given SCC. Computed lazily.
71+
pub(in crate::borrow_check) rev_scc_graph: Option<Rc<ReverseSccGraph>>,
7172

7273
/// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
7374
pub(in crate::borrow_check) member_constraints:
@@ -281,7 +282,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
281282
constraints,
282283
constraint_graph,
283284
constraint_sccs,
284-
rev_constraint_graph: None,
285+
rev_scc_graph: None,
285286
member_constraints,
286287
member_constraints_applied: Vec::new(),
287288
closure_bounds_mapping,
@@ -673,15 +674,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
673674
// free region that must outlive the member region `R0` (`UB:
674675
// R0`). Therefore, we need only keep an option `O` if `UB: O`
675676
// for all UB.
676-
if choice_regions.len() > 1 {
677-
let universal_region_relations = self.universal_region_relations.clone();
678-
let rev_constraint_graph = self.rev_constraint_graph();
679-
for ub in self.upper_bounds(scc, &rev_constraint_graph) {
680-
debug!("apply_member_constraint: ub={:?}", ub);
681-
choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
682-
}
683-
debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
677+
let rev_scc_graph = self.reverse_scc_graph();
678+
let universal_region_relations = &self.universal_region_relations;
679+
for ub in rev_scc_graph.upper_bounds(scc) {
680+
debug!("apply_member_constraint: ub={:?}", ub);
681+
choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
684682
}
683+
debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
685684

686685
// If we ruled everything out, we're done.
687686
if choice_regions.is_empty() {
@@ -737,32 +736,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
737736
}
738737
}
739738

740-
/// Compute and return the reverse SCC-based constraint graph (lazilly).
741-
fn upper_bounds(
742-
&'a mut self,
743-
scc0: ConstraintSccIndex,
744-
rev_constraint_graph: &'a VecGraph<ConstraintSccIndex>,
745-
) -> impl Iterator<Item = RegionVid> + 'a {
746-
let scc_values = &self.scc_values;
747-
let mut duplicates = FxHashSet::default();
748-
rev_constraint_graph
749-
.depth_first_search(scc0)
750-
.skip(1)
751-
.flat_map(move |scc1| scc_values.universal_regions_outlived_by(scc1))
752-
.filter(move |&r| duplicates.insert(r))
753-
}
754-
755-
/// Compute and return the reverse SCC-based constraint graph (lazilly).
756-
fn rev_constraint_graph(&mut self) -> Rc<VecGraph<ConstraintSccIndex>> {
757-
if let Some(g) = &self.rev_constraint_graph {
758-
return g.clone();
759-
}
760-
761-
let rev_graph = Rc::new(self.constraint_sccs.reverse());
762-
self.rev_constraint_graph = Some(rev_graph.clone());
763-
rev_graph
764-
}
765-
766739
/// Returns `true` if all the elements in the value of `scc_b` are nameable
767740
/// in `scc_a`. Used during constraint propagation, and only once
768741
/// the value of `scc_b` has been computed.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crate::borrow_check::constraints::ConstraintSccIndex;
2+
use crate::borrow_check::RegionInferenceContext;
3+
use itertools::Itertools;
4+
use rustc::ty::RegionVid;
5+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
6+
use rustc_data_structures::graph::vec_graph::VecGraph;
7+
use rustc_data_structures::graph::WithSuccessors;
8+
use std::ops::Range;
9+
use std::rc::Rc;
10+
11+
crate struct ReverseSccGraph {
12+
graph: VecGraph<ConstraintSccIndex>,
13+
/// For each SCC, the range of `universal_regions` that use that SCC as
14+
/// their value.
15+
scc_regions: FxHashMap<ConstraintSccIndex, Range<usize>>,
16+
/// All of the universal regions, in grouped so that `scc_regions` can
17+
/// index into here.
18+
universal_regions: Vec<RegionVid>,
19+
}
20+
21+
impl ReverseSccGraph {
22+
/// Find all universal regions that are required to outlive the given SCC.
23+
pub(super) fn upper_bounds<'a>(
24+
&'a self,
25+
scc0: ConstraintSccIndex,
26+
) -> impl Iterator<Item = RegionVid> + 'a {
27+
let mut duplicates = FxHashSet::default();
28+
self.graph
29+
.depth_first_search(scc0)
30+
.flat_map(move |scc1| {
31+
self.scc_regions
32+
.get(&scc1)
33+
.map_or(&[][..], |range| &self.universal_regions[range.clone()])
34+
})
35+
.copied()
36+
.filter(move |r| duplicates.insert(*r))
37+
}
38+
}
39+
40+
impl RegionInferenceContext<'_> {
41+
/// Compute and return the reverse SCC-based constraint graph (lazily).
42+
pub(super) fn reverse_scc_graph(&mut self) -> Rc<ReverseSccGraph> {
43+
if let Some(g) = &self.rev_scc_graph {
44+
return g.clone();
45+
}
46+
47+
let graph = self.constraint_sccs.reverse();
48+
let mut paired_scc_regions = self
49+
.universal_regions
50+
.universal_regions()
51+
.map(|region| (self.constraint_sccs.scc(region), region))
52+
.collect_vec();
53+
paired_scc_regions.sort();
54+
let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect();
55+
56+
let mut scc_regions = FxHashMap::default();
57+
let mut start = 0;
58+
for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) {
59+
let group_size = group.into_iter().count();
60+
scc_regions.insert(scc, start..start + group_size);
61+
start += group_size;
62+
}
63+
64+
let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions });
65+
self.rev_scc_graph = Some(rev_graph.clone());
66+
rev_graph
67+
}
68+
}

0 commit comments

Comments
 (0)