From e4f03682df6cff533d7897c4e12f57d63c3635a3 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 16:25:41 -0400 Subject: [PATCH] use the type system to ensure we dedup from the start --- .../borrow_check/nll/constraint_set.rs | 33 ++++++++++++ src/librustc_mir/borrow_check/nll/mod.rs | 2 + .../borrow_check/nll/region_infer/dump_mir.rs | 2 +- .../borrow_check/nll/region_infer/graphviz.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 54 ++++++------------- .../nll/type_check/constraint_conversion.rs | 5 +- .../borrow_check/nll/type_check/mod.rs | 5 +- 7 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 src/librustc_mir/borrow_check/nll/constraint_set.rs diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs new file mode 100644 index 00000000000..4b0a0c9bce9 --- /dev/null +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -0,0 +1,33 @@ +use borrow_check::nll::region_infer::{ConstraintIndex, OutlivesConstraint}; +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::FxHashSet; +use rustc::ty::RegionVid; + +#[derive(Clone, Default)] +crate struct ConstraintSet { + constraints: IndexVec, + seen_constraints: FxHashSet<(RegionVid, RegionVid)>, +} + +impl ConstraintSet { + pub fn push(&mut self, outlives_constraint: OutlivesConstraint) { + debug!("add_outlives({:?}: {:?} @ {:?}", outlives_constraint.sup, outlives_constraint.sub, outlives_constraint.point); + if outlives_constraint.sup == outlives_constraint.sub { + // 'a: 'a is pretty uninteresting + return; + } + if self.seen_constraints.insert(outlives_constraint.dedup_key()) { + self.constraints.push(outlives_constraint); + } + } + + pub fn iner(&self) -> &IndexVec { + &self.constraints + } + + /// Do Not use this to add nor remove items to the Vec, nor change the `sup`, nor `sub` of the data. + pub fn iner_mut(&mut self) -> &mut IndexVec { + &mut self.constraints + } +} + diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index e26665e8291..07b160ed66f 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -45,6 +45,8 @@ crate mod type_check; mod universal_regions; +crate mod constraint_set; + use self::facts::AllFacts; use self::region_infer::RegionInferenceContext; use self::universal_regions::UniversalRegions; diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs index 6c796ea4c73..7c17f6a1aeb 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs @@ -76,7 +76,7 @@ fn for_each_constraint( } } - let mut constraints: Vec<_> = self.constraints.iter().collect(); + let mut constraints: Vec<_> = self.constraints.iner().iter().collect(); constraints.sort(); for constraint in &constraints { let OutlivesConstraint { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs index c02e4ff3156..ad15a435359 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -55,7 +55,7 @@ fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> { vids.into_cow() } fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> { - (&self.constraints.raw[..]).into_cow() + (&self.constraints.iner().raw[..]).into_cow() } // Render `a: b` as `a <- b`, indicating the flow diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 624636652f3..5da486815e1 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -10,6 +10,7 @@ use super::universal_regions::UniversalRegions; use borrow_check::nll::region_infer::values::ToElementIndex; +use borrow_check::nll::constraint_set::ConstraintSet; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; @@ -24,7 +25,6 @@ use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc::util::common::{self, ErrorReported}; use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::fmt; use std::rc::Rc; @@ -66,8 +66,7 @@ pub struct RegionInferenceContext<'tcx> { dependency_map: Option>>, /// The constraints we have accumulated and used during solving. - constraints: IndexVec, - seen_constraints: FxHashSet<(RegionVid, RegionVid)>, + constraints: ConstraintSet, /// Type constraints that we check after solving. type_tests: Vec>, @@ -146,7 +145,7 @@ pub struct OutlivesConstraint { } impl OutlivesConstraint { - fn dedup_key(&self) -> (RegionVid, RegionVid) { + pub fn dedup_key(&self) -> (RegionVid, RegionVid) { (self.sup, self.sub) } } @@ -251,11 +250,11 @@ pub(crate) fn new( var_infos: VarInfos, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, - mut outlives_constraints: Vec, + outlives_constraints: ConstraintSet, type_tests: Vec>, ) -> Self { // The `next` field should not yet have been initialized: - debug_assert!(outlives_constraints.iter().all(|c| c.next.is_none())); + debug_assert!(outlives_constraints.iner().iter().all(|c| c.next.is_none())); let num_region_variables = var_infos.len(); let num_universal_regions = universal_regions.len(); @@ -268,18 +267,13 @@ pub(crate) fn new( .map(|info| RegionDefinition::new(info.origin)) .collect(); - let mut seen_constraints: FxHashSet<(RegionVid, RegionVid)> = Default::default(); - - outlives_constraints.retain(|c| c.sup != c.sub && seen_constraints.insert(c.dedup_key())); - let mut result = Self { definitions, elements: elements.clone(), liveness_constraints: RegionValues::new(elements, num_region_variables), inferred_values: None, dependency_map: None, - constraints: IndexVec::from_raw(outlives_constraints), - seen_constraints, + constraints: outlives_constraints, type_tests, universal_regions, }; @@ -405,7 +399,8 @@ pub(super) fn add_outlives( sub: RegionVid, point: Location, ) { - self.add_outlives_iner(OutlivesConstraint { + assert!(self.inferred_values.is_none(), "values already inferred"); + self.constraints.push(OutlivesConstraint { span, sup, sub, @@ -414,22 +409,6 @@ pub(super) fn add_outlives( }) } - /// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`. - fn add_outlives_iner( - &mut self, - outlives_constraint: OutlivesConstraint - ) { - debug!("add_outlives({:?}: {:?} @ {:?}", outlives_constraint.sup, outlives_constraint.sub, outlives_constraint.point); - assert!(self.inferred_values.is_none(), "values already inferred"); - if outlives_constraint.sup == outlives_constraint.sub { - // 'a: 'a is pretty uninteresting - return; - } - if self.seen_constraints.insert(outlives_constraint.dedup_key()) { - self.constraints.push(outlives_constraint); - } - } - /// Perform region inference and report errors if we see any /// unsatisfiable constraints. If this is a closure, returns the /// region requirements to propagate to our creator, if any. @@ -497,7 +476,7 @@ fn propagate_constraints(&mut self, mir: &Mir<'tcx>) { fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { debug!("compute_region_values()"); debug!("compute_region_values: constraints={:#?}", { - let mut constraints: Vec<_> = self.constraints.iter().collect(); + let mut constraints: Vec<_> = self.constraints.iner().iter().collect(); constraints.sort(); constraints }); @@ -509,7 +488,7 @@ fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { let dependency_map = self.dependency_map.as_ref().unwrap(); // Constraints that may need to be repropagated (initially all): - let mut dirty_list: Vec<_> = self.constraints.indices().collect(); + let mut dirty_list: Vec<_> = self.constraints.iner().indices().collect(); // Set to 0 for each constraint that is on the dirty list: let mut clean_bit_vec = BitVector::new(dirty_list.len()); @@ -518,7 +497,7 @@ fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { while let Some(constraint_idx) = dirty_list.pop() { clean_bit_vec.insert(constraint_idx.index()); - let constraint = &self.constraints[constraint_idx]; + let constraint = &self.constraints.iner()[constraint_idx]; debug!("propagate_constraints: constraint={:?}", constraint); if inferred_values.add_region(constraint.sup, constraint.sub) { @@ -530,7 +509,7 @@ fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { if clean_bit_vec.remove(dep_idx.index()) { dirty_list.push(dep_idx); } - opt_dep_idx = self.constraints[dep_idx].next; + opt_dep_idx = self.constraints.iner()[dep_idx].next; } } @@ -547,7 +526,7 @@ fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues { fn build_dependency_map(&mut self) -> IndexVec> { let mut map = IndexVec::from_elem(None, &self.definitions); - for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() { + for (idx, constraint) in self.constraints.iner_mut().iter_enumerated_mut().rev() { let mut head = &mut map[constraint.sub]; debug_assert!(constraint.next.is_none()); constraint.next = *head; @@ -995,7 +974,7 @@ fn check_universal_region<'gcx>( ); let blame_index = self.blame_constraint(longer_fr, shorter_fr); - let blame_span = self.constraints[blame_index].span; + let blame_span = self.constraints.iner()[blame_index].span; if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). @@ -1086,7 +1065,7 @@ fn report_error( // - `fr1: X` transitively // - and `Y` is live at `elem` let index = self.blame_constraint(fr1, elem); - let region_sub = self.constraints[index].sub; + let region_sub = self.constraints.iner()[index].sub; // then return why `Y` was live at `elem` self.liveness_constraints.cause(region_sub, elem) @@ -1107,6 +1086,7 @@ fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> Constra // of dependencies, which doesn't account for the locations of // contraints at all. But it will do for now. let relevant_constraint = self.constraints + .iner() .iter_enumerated() .filter_map(|(i, constraint)| { if !self.liveness_constraints.contains(constraint.sub, elem) { @@ -1142,7 +1122,7 @@ fn dependencies(&self, r0: RegionVid) -> IndexVec> { while changed { changed = false; - for constraint in &self.constraints { + for constraint in self.constraints.iner() { if let Some(n) = result_set[constraint.sup] { let m = n + 1; if result_set[constraint.sub] diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs index 900899b9cde..263dd334e78 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs @@ -13,6 +13,7 @@ use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest}; use borrow_check::nll::type_check::Locations; use borrow_check::nll::universal_regions::UniversalRegions; +use borrow_check::nll::constraint_set::ConstraintSet; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; use rustc::infer::region_constraints::{GenericKind, VerifyBound}; @@ -31,7 +32,7 @@ implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, locations: Locations, - outlives_constraints: &'a mut Vec, + outlives_constraints: &'a mut ConstraintSet, type_tests: &'a mut Vec>, all_facts: &'a mut Option, } @@ -46,7 +47,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, locations: Locations, - outlives_constraints: &'a mut Vec, + outlives_constraints: &'a mut ConstraintSet, type_tests: &'a mut Vec>, all_facts: &'a mut Option, ) -> Self { diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 2da2b10edb8..ee607ccae89 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -12,9 +12,10 @@ #![allow(unreachable_code)] use borrow_check::location::LocationTable; +use borrow_check::nll::constraint_set::ConstraintSet; use borrow_check::nll::facts::AllFacts; use borrow_check::nll::region_infer::Cause; -use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, OutlivesConstraint, TypeTest}; +use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest}; use borrow_check::nll::universal_regions::UniversalRegions; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; @@ -621,7 +622,7 @@ struct BorrowCheckContext<'a, 'tcx: 'a> { /// hence it must report on their liveness constraints. crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>, - crate outlives_constraints: Vec, + crate outlives_constraints: ConstraintSet, crate type_tests: Vec>, } -- GitLab