From 8a356011aeae6895e4d89dd95b37e8c7706ec5a3 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 14:32:00 -0400 Subject: [PATCH 01/10] Remove duplicates --- .../borrow_check/nll/region_infer/mod.rs | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) 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 2e1f7fc9e70..f6d5de63f17 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -24,6 +24,7 @@ use rustc::mir::{ 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,6 +67,7 @@ pub struct RegionInferenceContext<'tcx> { /// The constraints we have accumulated and used during solving. constraints: IndexVec, + seen_constraints: FxHashSet<(RegionVid, RegionVid)>, /// Type constraints that we check after solving. type_tests: Vec>, @@ -143,6 +145,12 @@ pub struct OutlivesConstraint { pub span: Span, } +impl OutlivesConstraint { + fn dedup_key(&self) -> (RegionVid, RegionVid) { + (self.sup, self.sub) + } +} + newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); /// A "type test" corresponds to an outlives constraint between a type @@ -266,11 +274,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { liveness_constraints: RegionValues::new(elements, num_region_variables), inferred_values: None, dependency_map: None, - constraints: IndexVec::from_raw(outlives_constraints), + constraints: Default::default(), + seen_constraints: Default::default(), type_tests, universal_regions, }; + for c in outlives_constraints { + result.add_outlives_iner(c); + } + result.init_universal_regions(); result @@ -392,15 +405,29 @@ impl<'tcx> RegionInferenceContext<'tcx> { sub: RegionVid, point: Location, ) { - debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point); - assert!(self.inferred_values.is_none(), "values already inferred"); - self.constraints.push(OutlivesConstraint { + self.add_outlives_iner(OutlivesConstraint { span, sup, sub, point, next: None, - }); + }) + } + + /// 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 From 0119669711af204d1205cf64fed11f5ad3c1bbdd Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 14:50:55 -0400 Subject: [PATCH 02/10] use retain to avoid the allocation --- .../borrow_check/nll/region_infer/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 f6d5de63f17..624636652f3 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -251,7 +251,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { var_infos: VarInfos, universal_regions: UniversalRegions<'tcx>, mir: &Mir<'tcx>, - outlives_constraints: Vec, + mut outlives_constraints: Vec, type_tests: Vec>, ) -> Self { // The `next` field should not yet have been initialized: @@ -268,22 +268,22 @@ impl<'tcx> RegionInferenceContext<'tcx> { .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: Default::default(), - seen_constraints: Default::default(), + constraints: IndexVec::from_raw(outlives_constraints), + seen_constraints, type_tests, universal_regions, }; - for c in outlives_constraints { - result.add_outlives_iner(c); - } - result.init_universal_regions(); result From e4f03682df6cff533d7897c4e12f57d63c3635a3 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 16:25:41 -0400 Subject: [PATCH 03/10] 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 @@ mod renumber; 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - 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 @@ impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> { 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::mir::{ 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { .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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } - /// 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 @@ impl<'tcx> RegionInferenceContext<'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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { // - `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 @@ impl<'tcx> RegionInferenceContext<'tcx> { // 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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::facts::AllFacts; 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 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { 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 @@ crate struct MirTypeckRegionConstraints<'tcx> { /// 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>, } From e2c0378a63041e8c2696760039b9117251dbee30 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 16:46:27 -0400 Subject: [PATCH 04/10] move related types into the new module --- .../borrow_check/nll/constraint_set.rs | 54 ++++++++++++++++++- .../borrow_check/nll/region_infer/graphviz.rs | 2 + .../borrow_check/nll/region_infer/mod.rs | 50 +---------------- .../nll/type_check/constraint_conversion.rs | 3 +- 4 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 4b0a0c9bce9..5d4ffc8f4fd 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -1,7 +1,10 @@ -use borrow_check::nll::region_infer::{ConstraintIndex, OutlivesConstraint}; -use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::fx::FxHashSet; use rustc::ty::RegionVid; +use rustc::mir::Location; + +use std::fmt; +use syntax_pos::Span; #[derive(Clone, Default)] crate struct ConstraintSet { @@ -31,3 +34,50 @@ impl ConstraintSet { } } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct OutlivesConstraint { + // NB. The ordering here is not significant for correctness, but + // it is for convenience. Before we dump the constraints in the + // debugging logs, we sort them, and we'd like the "super region" + // to be first, etc. (In particular, span should remain last.) + /// The region SUP must outlive SUB... + pub sup: RegionVid, + + /// Region that must be outlived. + pub sub: RegionVid, + + /// At this location. + pub point: Location, + + /// Later on, we thread the constraints onto a linked list + /// grouped by their `sub` field. So if you had: + /// + /// Index | Constraint | Next Field + /// ----- | ---------- | ---------- + /// 0 | `'a: 'b` | Some(2) + /// 1 | `'b: 'c` | None + /// 2 | `'c: 'b` | None + pub next: Option, + + /// Where did this constraint arise? + pub span: Span, +} + +impl OutlivesConstraint { + pub fn dedup_key(&self) -> (RegionVid, RegionVid) { + (self.sup, self.sub) + } +} + +impl fmt::Debug for OutlivesConstraint { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "({:?}: {:?} @ {:?}) due to {:?}", + self.sup, self.sub, self.point, self.span + ) + } +} + +newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); + 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 ad15a435359..78ec60baa87 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -17,6 +17,8 @@ use rustc_data_structures::indexed_vec::Idx; use std::borrow::Cow; use std::io::{self, Write}; use super::*; +use borrow_check::nll::constraint_set::OutlivesConstraint; + impl<'tcx> RegionInferenceContext<'tcx> { /// Write out the region constraint graph. 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 5da486815e1..0f6c98920d7 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -10,7 +10,7 @@ use super::universal_regions::UniversalRegions; use borrow_check::nll::region_infer::values::ToElementIndex; -use borrow_check::nll::constraint_set::ConstraintSet; +use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint}; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::error_reporting::nice_region_error::NiceRegionError; @@ -26,7 +26,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::indexed_vec::{Idx, IndexVec}; -use std::fmt; use std::rc::Rc; use syntax_pos::Span; @@ -115,43 +114,6 @@ pub(crate) enum Cause { UniversalRegion(RegionVid), } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct OutlivesConstraint { - // NB. The ordering here is not significant for correctness, but - // it is for convenience. Before we dump the constraints in the - // debugging logs, we sort them, and we'd like the "super region" - // to be first, etc. (In particular, span should remain last.) - /// The region SUP must outlive SUB... - pub sup: RegionVid, - - /// Region that must be outlived. - pub sub: RegionVid, - - /// At this location. - pub point: Location, - - /// Later on, we thread the constraints onto a linked list - /// grouped by their `sub` field. So if you had: - /// - /// Index | Constraint | Next Field - /// ----- | ---------- | ---------- - /// 0 | `'a: 'b` | Some(2) - /// 1 | `'b: 'c` | None - /// 2 | `'c: 'b` | None - pub next: Option, - - /// Where did this constraint arise? - pub span: Span, -} - -impl OutlivesConstraint { - pub fn dedup_key(&self) -> (RegionVid, RegionVid) { - (self.sup, self.sub) - } -} - -newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); - /// A "type test" corresponds to an outlives constraint between a type /// and a lifetime, like `T: 'x` or `::Bar: 'x`. They are /// translated from the `Verify` region constraints in the ordinary @@ -1153,16 +1115,6 @@ impl<'tcx> RegionDefinition<'tcx> { } } -impl fmt::Debug for OutlivesConstraint { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!( - formatter, - "({:?}: {:?} @ {:?}) due to {:?}", - self.sup, self.sub, self.point, self.span - ) - } -} - pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> { fn apply_requirements( &self, 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 263dd334e78..3100df3e8f6 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 @@ -9,8 +9,9 @@ // except according to those terms. use borrow_check::location::LocationTable; +use borrow_check::nll::constraint_set::OutlivesConstraint; use borrow_check::nll::facts::AllFacts; -use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest}; +use borrow_check::nll::region_infer::{RegionTest, TypeTest}; use borrow_check::nll::type_check::Locations; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::constraint_set::ConstraintSet; From 497a3b4fd5d0b9d773f40dd7acef952a7acd4ce5 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 17:19:43 -0400 Subject: [PATCH 05/10] fix typo and tidy --- .../borrow_check/nll/constraint_set.rs | 23 +++++++++++++++---- .../borrow_check/nll/region_infer/dump_mir.rs | 2 +- .../borrow_check/nll/region_infer/graphviz.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 20 ++++++++-------- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 5d4ffc8f4fd..249b03e0c8b 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -1,3 +1,13 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::fx::FxHashSet; use rustc::ty::RegionVid; @@ -14,7 +24,10 @@ crate struct ConstraintSet { impl ConstraintSet { pub fn push(&mut self, outlives_constraint: OutlivesConstraint) { - debug!("add_outlives({:?}: {:?} @ {:?}", outlives_constraint.sup, outlives_constraint.sub, outlives_constraint.point); + 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; @@ -24,12 +37,14 @@ impl ConstraintSet { } } - pub fn iner(&self) -> &IndexVec { + pub fn inner(&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 { + /// Do Not use this to add nor remove items to the Vec, + /// nor change the `sup`, + /// nor `sub` of the data. + pub fn inner_mut(&mut self) -> &mut IndexVec { &mut self.constraints } } 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 7c17f6a1aeb..b10e7cf21e9 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - let mut constraints: Vec<_> = self.constraints.iner().iter().collect(); + let mut constraints: Vec<_> = self.constraints.inner().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 78ec60baa87..f9c1b799c08 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -57,7 +57,7 @@ impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> { vids.into_cow() } fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> { - (&self.constraints.iner().raw[..]).into_cow() + (&self.constraints.inner().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 0f6c98920d7..3a2eb7faaa5 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -216,7 +216,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { type_tests: Vec>, ) -> Self { // The `next` field should not yet have been initialized: - debug_assert!(outlives_constraints.iner().iter().all(|c| c.next.is_none())); + debug_assert!(outlives_constraints.inner().iter().all(|c| c.next.is_none())); let num_region_variables = var_infos.len(); let num_universal_regions = universal_regions.len(); @@ -438,7 +438,7 @@ impl<'tcx> RegionInferenceContext<'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.iner().iter().collect(); + let mut constraints: Vec<_> = self.constraints.inner().iter().collect(); constraints.sort(); constraints }); @@ -450,7 +450,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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.iner().indices().collect(); + let mut dirty_list: Vec<_> = self.constraints.inner().indices().collect(); // Set to 0 for each constraint that is on the dirty list: let mut clean_bit_vec = BitVector::new(dirty_list.len()); @@ -459,7 +459,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { while let Some(constraint_idx) = dirty_list.pop() { clean_bit_vec.insert(constraint_idx.index()); - let constraint = &self.constraints.iner()[constraint_idx]; + let constraint = &self.constraints.inner()[constraint_idx]; debug!("propagate_constraints: constraint={:?}", constraint); if inferred_values.add_region(constraint.sup, constraint.sub) { @@ -471,7 +471,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { if clean_bit_vec.remove(dep_idx.index()) { dirty_list.push(dep_idx); } - opt_dep_idx = self.constraints.iner()[dep_idx].next; + opt_dep_idx = self.constraints.inner()[dep_idx].next; } } @@ -488,7 +488,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { fn build_dependency_map(&mut self) -> IndexVec> { let mut map = IndexVec::from_elem(None, &self.definitions); - for (idx, constraint) in self.constraints.iner_mut().iter_enumerated_mut().rev() { + for (idx, constraint) in self.constraints.inner_mut().iter_enumerated_mut().rev() { let mut head = &mut map[constraint.sub]; debug_assert!(constraint.next.is_none()); constraint.next = *head; @@ -936,7 +936,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let blame_index = self.blame_constraint(longer_fr, shorter_fr); - let blame_span = self.constraints.iner()[blame_index].span; + let blame_span = self.constraints.inner()[blame_index].span; if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). @@ -1027,7 +1027,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // - `fr1: X` transitively // - and `Y` is live at `elem` let index = self.blame_constraint(fr1, elem); - let region_sub = self.constraints.iner()[index].sub; + let region_sub = self.constraints.inner()[index].sub; // then return why `Y` was live at `elem` self.liveness_constraints.cause(region_sub, elem) @@ -1048,7 +1048,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // 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() + .inner() .iter_enumerated() .filter_map(|(i, constraint)| { if !self.liveness_constraints.contains(constraint.sub, elem) { @@ -1084,7 +1084,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { while changed { changed = false; - for constraint in self.constraints.iner() { + for constraint in self.constraints.inner() { if let Some(n) = result_set[constraint.sup] { let m = n + 1; if result_set[constraint.sub] From 9bd2a63f29d4a64643aa6c25fe2e8390fa14b277 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 17:47:55 -0400 Subject: [PATCH 06/10] remove inner_mut as it can mess up invariants --- .../borrow_check/nll/constraint_set.rs | 34 ++++++++++++------- .../borrow_check/nll/region_infer/mod.rs | 11 +----- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 249b03e0c8b..c927aa871fc 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -23,17 +23,21 @@ crate struct ConstraintSet { } impl ConstraintSet { - pub fn push(&mut self, outlives_constraint: OutlivesConstraint) { + pub fn new() -> Self { + Default::default() + } + + pub fn push(&mut self, constraint: OutlivesConstraint) { debug!("add_outlives({:?}: {:?} @ {:?}", - outlives_constraint.sup, - outlives_constraint.sub, - outlives_constraint.point); - if outlives_constraint.sup == outlives_constraint.sub { + constraint.sup, + constraint.sub, + constraint.point); + if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting return; } - if self.seen_constraints.insert(outlives_constraint.dedup_key()) { - self.constraints.push(outlives_constraint); + if self.seen_constraints.insert(constraint.dedup_key()) { + self.constraints.push(constraint); } } @@ -41,11 +45,17 @@ impl ConstraintSet { &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 inner_mut(&mut self) -> &mut IndexVec { - &mut self.constraints + pub fn link(&mut self, len: usize) -> IndexVec> { + let mut map = IndexVec::from_elem_n(None, len); + + for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() { + let mut head = &mut map[constraint.sub]; + debug_assert!(constraint.next.is_none()); + constraint.next = *head; + *head = Some(idx); + } + + map } } 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 3a2eb7faaa5..ef61b162e9c 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -486,16 +486,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// These are constraints like Y: X @ P -- so if X changed, we may /// need to grow Y. fn build_dependency_map(&mut self) -> IndexVec> { - let mut map = IndexVec::from_elem(None, &self.definitions); - - for (idx, constraint) in self.constraints.inner_mut().iter_enumerated_mut().rev() { - let mut head = &mut map[constraint.sub]; - debug_assert!(constraint.next.is_none()); - constraint.next = *head; - *head = Some(idx); - } - - map + self.constraints.link(self.definitions.len()) } /// Once regions have been propagated, this method is used to see From 4b44db126ef7701e76a6048c784764151d71d6c4 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 18:15:57 -0400 Subject: [PATCH 07/10] each_affected_by_dirty --- .../borrow_check/nll/constraint_set.rs | 30 +++++++++++-------- .../borrow_check/nll/region_infer/mod.rs | 6 ++-- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index c927aa871fc..154db25145e 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::fx::FxHashSet; -use rustc::ty::RegionVid; use rustc::mir::Location; +use rustc::ty::RegionVid; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::fmt; use syntax_pos::Span; @@ -23,15 +23,11 @@ crate struct ConstraintSet { } impl ConstraintSet { - pub fn new() -> Self { - Default::default() - } - pub fn push(&mut self, constraint: OutlivesConstraint) { - debug!("add_outlives({:?}: {:?} @ {:?}", - constraint.sup, - constraint.sub, - constraint.point); + debug!( + "add_outlives({:?}: {:?} @ {:?}", + constraint.sup, constraint.sub, constraint.point + ); if constraint.sup == constraint.sub { // 'a: 'a is pretty uninteresting return; @@ -57,6 +53,17 @@ impl ConstraintSet { map } + + pub fn each_affected_by_dirty( + &self, + mut opt_dep_idx: Option, + mut op: impl FnMut(ConstraintIndex), + ) { + while let Some(dep_idx) = opt_dep_idx { + op(dep_idx); + opt_dep_idx = self.constraints[dep_idx].next; + } + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -105,4 +112,3 @@ impl fmt::Debug for OutlivesConstraint { } newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" }); - 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 ef61b162e9c..488223e22e2 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -466,13 +466,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("propagate_constraints: sub={:?}", constraint.sub); debug!("propagate_constraints: sup={:?}", constraint.sup); - let mut opt_dep_idx = dependency_map[constraint.sup]; - while let Some(dep_idx) = opt_dep_idx { + self.constraints.each_affected_by_dirty(dependency_map[constraint.sup], |dep_idx| { if clean_bit_vec.remove(dep_idx.index()) { dirty_list.push(dep_idx); } - opt_dep_idx = self.constraints.inner()[dep_idx].next; - } + }); } debug!("\n"); From ad71cbfe66f29f9a9ba3c3d2af5d487d727edc1e Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 18:50:48 -0400 Subject: [PATCH 08/10] use deref instead of inner --- .../borrow_check/nll/constraint_set.rs | 11 +++++++---- .../borrow_check/nll/region_infer/dump_mir.rs | 2 +- .../borrow_check/nll/region_infer/graphviz.rs | 2 +- .../borrow_check/nll/region_infer/mod.rs | 15 +++++++-------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 154db25145e..cbef674b269 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -15,6 +15,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::fmt; use syntax_pos::Span; +use std::ops::Deref; #[derive(Clone, Default)] crate struct ConstraintSet { @@ -37,10 +38,6 @@ impl ConstraintSet { } } - pub fn inner(&self) -> &IndexVec { - &self.constraints - } - pub fn link(&mut self, len: usize) -> IndexVec> { let mut map = IndexVec::from_elem_n(None, len); @@ -66,6 +63,12 @@ impl ConstraintSet { } } +impl Deref for ConstraintSet { + type Target = IndexVec; + + fn deref(&self) -> &Self::Target { &self.constraints } +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OutlivesConstraint { // NB. The ordering here is not significant for correctness, but 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 b10e7cf21e9..6c796ea4c73 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 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - let mut constraints: Vec<_> = self.constraints.inner().iter().collect(); + let mut constraints: Vec<_> = self.constraints.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 f9c1b799c08..106dd003cea 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs @@ -57,7 +57,7 @@ impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> { vids.into_cow() } fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> { - (&self.constraints.inner().raw[..]).into_cow() + (&self.constraints.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 488223e22e2..a576dc5f7f4 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -216,7 +216,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { type_tests: Vec>, ) -> Self { // The `next` field should not yet have been initialized: - debug_assert!(outlives_constraints.inner().iter().all(|c| c.next.is_none())); + debug_assert!(outlives_constraints.iter().all(|c| c.next.is_none())); let num_region_variables = var_infos.len(); let num_universal_regions = universal_regions.len(); @@ -438,7 +438,7 @@ impl<'tcx> RegionInferenceContext<'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.inner().iter().collect(); + let mut constraints: Vec<_> = self.constraints.iter().collect(); constraints.sort(); constraints }); @@ -450,7 +450,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { 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.inner().indices().collect(); + let mut dirty_list: Vec<_> = self.constraints.indices().collect(); // Set to 0 for each constraint that is on the dirty list: let mut clean_bit_vec = BitVector::new(dirty_list.len()); @@ -459,7 +459,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { while let Some(constraint_idx) = dirty_list.pop() { clean_bit_vec.insert(constraint_idx.index()); - let constraint = &self.constraints.inner()[constraint_idx]; + let constraint = &self.constraints[constraint_idx]; debug!("propagate_constraints: constraint={:?}", constraint); if inferred_values.add_region(constraint.sup, constraint.sub) { @@ -925,7 +925,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); let blame_index = self.blame_constraint(longer_fr, shorter_fr); - let blame_span = self.constraints.inner()[blame_index].span; + let blame_span = self.constraints[blame_index].span; if let Some(propagated_outlives_requirements) = propagated_outlives_requirements { // Shrink `fr` until we find a non-local region (if we do). @@ -1016,7 +1016,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // - `fr1: X` transitively // - and `Y` is live at `elem` let index = self.blame_constraint(fr1, elem); - let region_sub = self.constraints.inner()[index].sub; + let region_sub = self.constraints[index].sub; // then return why `Y` was live at `elem` self.liveness_constraints.cause(region_sub, elem) @@ -1037,7 +1037,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // of dependencies, which doesn't account for the locations of // contraints at all. But it will do for now. let relevant_constraint = self.constraints - .inner() .iter_enumerated() .filter_map(|(i, constraint)| { if !self.liveness_constraints.contains(constraint.sub, elem) { @@ -1073,7 +1072,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { while changed { changed = false; - for constraint in self.constraints.inner() { + for constraint in self.constraints.iter() { if let Some(n) = result_set[constraint.sup] { let m = n + 1; if result_set[constraint.sub] From 6e0cefe3dbbfa981063028078aba94ada0dcb066 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Wed, 27 Jun 2018 18:57:11 -0400 Subject: [PATCH 09/10] add comments --- src/librustc_mir/borrow_check/nll/constraint_set.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index cbef674b269..78bd4504443 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -38,6 +38,10 @@ impl ConstraintSet { } } + /// Once all constraints have been added, `link()` is used to thread together the constraints + /// based on which would be affected when a particular region changes. See the next field of + /// `OutlivesContraint` for more details. + /// link returns a map that is needed later by `each_affected_by_dirty`. pub fn link(&mut self, len: usize) -> IndexVec> { let mut map = IndexVec::from_elem_n(None, len); @@ -51,6 +55,11 @@ impl ConstraintSet { map } + /// When a region R1 changes, we need to reprocess all constraints R2: R1 to take into account + /// any new elements that R1 now has. This method will quickly enumerate all such constraints + /// (that is, constraints where R1 is in the "subregion" position). + /// To use it, invoke with `map[R1]` where map is the map returned by `link`; + /// the callback op will be invoked for each affected constraint. pub fn each_affected_by_dirty( &self, mut opt_dep_idx: Option, From ac5bd5dd2b4abd8eb888f14ea01b59028173c0db Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 1 Jul 2018 05:51:33 -0400 Subject: [PATCH 10/10] remove the FxHashSet since it's not helping us in practice It turns out that we don't have duplicates, just self-cycles. --- src/librustc_mir/borrow_check/nll/constraint_set.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/constraint_set.rs b/src/librustc_mir/borrow_check/nll/constraint_set.rs index 78bd4504443..4c6e445293d 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_set.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_set.rs @@ -10,7 +10,6 @@ use rustc::mir::Location; use rustc::ty::RegionVid; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use std::fmt; @@ -20,7 +19,6 @@ use std::ops::Deref; #[derive(Clone, Default)] crate struct ConstraintSet { constraints: IndexVec, - seen_constraints: FxHashSet<(RegionVid, RegionVid)>, } impl ConstraintSet { @@ -33,9 +31,7 @@ impl ConstraintSet { // 'a: 'a is pretty uninteresting return; } - if self.seen_constraints.insert(constraint.dedup_key()) { - self.constraints.push(constraint); - } + self.constraints.push(constraint); } /// Once all constraints have been added, `link()` is used to thread together the constraints @@ -107,12 +103,6 @@ pub struct OutlivesConstraint { pub span: Span, } -impl OutlivesConstraint { - pub fn dedup_key(&self) -> (RegionVid, RegionVid) { - (self.sup, self.sub) - } -} - impl fmt::Debug for OutlivesConstraint { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(