use the type system to ensure we dedup from the start
This commit is contained in:
parent
0119669711
commit
e4f03682df
33
src/librustc_mir/borrow_check/nll/constraint_set.rs
Normal file
33
src/librustc_mir/borrow_check/nll/constraint_set.rs
Normal file
@ -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<ConstraintIndex, OutlivesConstraint>,
|
||||||
|
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<ConstraintIndex, OutlivesConstraint> {
|
||||||
|
&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<ConstraintIndex, OutlivesConstraint> {
|
||||||
|
&mut self.constraints
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,6 +45,8 @@ mod renumber;
|
|||||||
crate mod type_check;
|
crate mod type_check;
|
||||||
mod universal_regions;
|
mod universal_regions;
|
||||||
|
|
||||||
|
crate mod constraint_set;
|
||||||
|
|
||||||
use self::facts::AllFacts;
|
use self::facts::AllFacts;
|
||||||
use self::region_infer::RegionInferenceContext;
|
use self::region_infer::RegionInferenceContext;
|
||||||
use self::universal_regions::UniversalRegions;
|
use self::universal_regions::UniversalRegions;
|
||||||
|
@ -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();
|
constraints.sort();
|
||||||
for constraint in &constraints {
|
for constraint in &constraints {
|
||||||
let OutlivesConstraint {
|
let OutlivesConstraint {
|
||||||
|
@ -55,7 +55,7 @@ impl<'this, 'tcx> dot::GraphWalk<'this> for RegionInferenceContext<'tcx> {
|
|||||||
vids.into_cow()
|
vids.into_cow()
|
||||||
}
|
}
|
||||||
fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
|
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
|
// Render `a: b` as `a <- b`, indicating the flow
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
use super::universal_regions::UniversalRegions;
|
use super::universal_regions::UniversalRegions;
|
||||||
use borrow_check::nll::region_infer::values::ToElementIndex;
|
use borrow_check::nll::region_infer::values::ToElementIndex;
|
||||||
|
use borrow_check::nll::constraint_set::ConstraintSet;
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::canonical::QueryRegionConstraint;
|
use rustc::infer::canonical::QueryRegionConstraint;
|
||||||
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
|
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::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc::util::common::{self, ErrorReported};
|
use rustc::util::common::{self, ErrorReported};
|
||||||
use rustc_data_structures::bitvec::BitVector;
|
use rustc_data_structures::bitvec::BitVector;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
|
||||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -66,8 +66,7 @@ pub struct RegionInferenceContext<'tcx> {
|
|||||||
dependency_map: Option<IndexVec<RegionVid, Option<ConstraintIndex>>>,
|
dependency_map: Option<IndexVec<RegionVid, Option<ConstraintIndex>>>,
|
||||||
|
|
||||||
/// The constraints we have accumulated and used during solving.
|
/// The constraints we have accumulated and used during solving.
|
||||||
constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
|
constraints: ConstraintSet,
|
||||||
seen_constraints: FxHashSet<(RegionVid, RegionVid)>,
|
|
||||||
|
|
||||||
/// Type constraints that we check after solving.
|
/// Type constraints that we check after solving.
|
||||||
type_tests: Vec<TypeTest<'tcx>>,
|
type_tests: Vec<TypeTest<'tcx>>,
|
||||||
@ -146,7 +145,7 @@ pub struct OutlivesConstraint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OutlivesConstraint {
|
impl OutlivesConstraint {
|
||||||
fn dedup_key(&self) -> (RegionVid, RegionVid) {
|
pub fn dedup_key(&self) -> (RegionVid, RegionVid) {
|
||||||
(self.sup, self.sub)
|
(self.sup, self.sub)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,11 +250,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
var_infos: VarInfos,
|
var_infos: VarInfos,
|
||||||
universal_regions: UniversalRegions<'tcx>,
|
universal_regions: UniversalRegions<'tcx>,
|
||||||
mir: &Mir<'tcx>,
|
mir: &Mir<'tcx>,
|
||||||
mut outlives_constraints: Vec<OutlivesConstraint>,
|
outlives_constraints: ConstraintSet,
|
||||||
type_tests: Vec<TypeTest<'tcx>>,
|
type_tests: Vec<TypeTest<'tcx>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// The `next` field should not yet have been initialized:
|
// 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_region_variables = var_infos.len();
|
||||||
let num_universal_regions = universal_regions.len();
|
let num_universal_regions = universal_regions.len();
|
||||||
@ -268,18 +267,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
.map(|info| RegionDefinition::new(info.origin))
|
.map(|info| RegionDefinition::new(info.origin))
|
||||||
.collect();
|
.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 {
|
let mut result = Self {
|
||||||
definitions,
|
definitions,
|
||||||
elements: elements.clone(),
|
elements: elements.clone(),
|
||||||
liveness_constraints: RegionValues::new(elements, num_region_variables),
|
liveness_constraints: RegionValues::new(elements, num_region_variables),
|
||||||
inferred_values: None,
|
inferred_values: None,
|
||||||
dependency_map: None,
|
dependency_map: None,
|
||||||
constraints: IndexVec::from_raw(outlives_constraints),
|
constraints: outlives_constraints,
|
||||||
seen_constraints,
|
|
||||||
type_tests,
|
type_tests,
|
||||||
universal_regions,
|
universal_regions,
|
||||||
};
|
};
|
||||||
@ -405,7 +399,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
sub: RegionVid,
|
sub: RegionVid,
|
||||||
point: Location,
|
point: Location,
|
||||||
) {
|
) {
|
||||||
self.add_outlives_iner(OutlivesConstraint {
|
assert!(self.inferred_values.is_none(), "values already inferred");
|
||||||
|
self.constraints.push(OutlivesConstraint {
|
||||||
span,
|
span,
|
||||||
sup,
|
sup,
|
||||||
sub,
|
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
|
/// Perform region inference and report errors if we see any
|
||||||
/// unsatisfiable constraints. If this is a closure, returns the
|
/// unsatisfiable constraints. If this is a closure, returns the
|
||||||
/// region requirements to propagate to our creator, if any.
|
/// 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 {
|
fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues {
|
||||||
debug!("compute_region_values()");
|
debug!("compute_region_values()");
|
||||||
debug!("compute_region_values: constraints={:#?}", {
|
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.sort();
|
||||||
constraints
|
constraints
|
||||||
});
|
});
|
||||||
@ -509,7 +488,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
let dependency_map = self.dependency_map.as_ref().unwrap();
|
let dependency_map = self.dependency_map.as_ref().unwrap();
|
||||||
|
|
||||||
// Constraints that may need to be repropagated (initially all):
|
// 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:
|
// Set to 0 for each constraint that is on the dirty list:
|
||||||
let mut clean_bit_vec = BitVector::new(dirty_list.len());
|
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() {
|
while let Some(constraint_idx) = dirty_list.pop() {
|
||||||
clean_bit_vec.insert(constraint_idx.index());
|
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);
|
debug!("propagate_constraints: constraint={:?}", constraint);
|
||||||
|
|
||||||
if inferred_values.add_region(constraint.sup, constraint.sub) {
|
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()) {
|
if clean_bit_vec.remove(dep_idx.index()) {
|
||||||
dirty_list.push(dep_idx);
|
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<RegionVid, Option<ConstraintIndex>> {
|
fn build_dependency_map(&mut self) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
|
||||||
let mut map = IndexVec::from_elem(None, &self.definitions);
|
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];
|
let mut head = &mut map[constraint.sub];
|
||||||
debug_assert!(constraint.next.is_none());
|
debug_assert!(constraint.next.is_none());
|
||||||
constraint.next = *head;
|
constraint.next = *head;
|
||||||
@ -995,7 +974,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let blame_index = self.blame_constraint(longer_fr, shorter_fr);
|
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 {
|
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||||
// Shrink `fr` until we find a non-local region (if we do).
|
// Shrink `fr` until we find a non-local region (if we do).
|
||||||
@ -1086,7 +1065,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
// - `fr1: X` transitively
|
// - `fr1: X` transitively
|
||||||
// - and `Y` is live at `elem`
|
// - and `Y` is live at `elem`
|
||||||
let index = self.blame_constraint(fr1, 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`
|
// then return why `Y` was live at `elem`
|
||||||
self.liveness_constraints.cause(region_sub, 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
|
// of dependencies, which doesn't account for the locations of
|
||||||
// contraints at all. But it will do for now.
|
// contraints at all. But it will do for now.
|
||||||
let relevant_constraint = self.constraints
|
let relevant_constraint = self.constraints
|
||||||
|
.iner()
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.filter_map(|(i, constraint)| {
|
.filter_map(|(i, constraint)| {
|
||||||
if !self.liveness_constraints.contains(constraint.sub, elem) {
|
if !self.liveness_constraints.contains(constraint.sub, elem) {
|
||||||
@ -1142,7 +1122,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||||||
|
|
||||||
while changed {
|
while changed {
|
||||||
changed = false;
|
changed = false;
|
||||||
for constraint in &self.constraints {
|
for constraint in self.constraints.iner() {
|
||||||
if let Some(n) = result_set[constraint.sup] {
|
if let Some(n) = result_set[constraint.sup] {
|
||||||
let m = n + 1;
|
let m = n + 1;
|
||||||
if result_set[constraint.sub]
|
if result_set[constraint.sub]
|
||||||
|
@ -13,6 +13,7 @@ use borrow_check::nll::facts::AllFacts;
|
|||||||
use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest};
|
use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest};
|
||||||
use borrow_check::nll::type_check::Locations;
|
use borrow_check::nll::type_check::Locations;
|
||||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
|
use borrow_check::nll::constraint_set::ConstraintSet;
|
||||||
use rustc::infer::canonical::QueryRegionConstraint;
|
use rustc::infer::canonical::QueryRegionConstraint;
|
||||||
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
||||||
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
|
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
|
||||||
@ -31,7 +32,7 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|||||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
outlives_constraints: &'a mut Vec<OutlivesConstraint>,
|
outlives_constraints: &'a mut ConstraintSet,
|
||||||
type_tests: &'a mut Vec<TypeTest<'tcx>>,
|
type_tests: &'a mut Vec<TypeTest<'tcx>>,
|
||||||
all_facts: &'a mut Option<AllFacts>,
|
all_facts: &'a mut Option<AllFacts>,
|
||||||
}
|
}
|
||||||
@ -46,7 +47,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
|
|||||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
outlives_constraints: &'a mut Vec<OutlivesConstraint>,
|
outlives_constraints: &'a mut ConstraintSet,
|
||||||
type_tests: &'a mut Vec<TypeTest<'tcx>>,
|
type_tests: &'a mut Vec<TypeTest<'tcx>>,
|
||||||
all_facts: &'a mut Option<AllFacts>,
|
all_facts: &'a mut Option<AllFacts>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
|
|
||||||
use borrow_check::location::LocationTable;
|
use borrow_check::location::LocationTable;
|
||||||
|
use borrow_check::nll::constraint_set::ConstraintSet;
|
||||||
use borrow_check::nll::facts::AllFacts;
|
use borrow_check::nll::facts::AllFacts;
|
||||||
use borrow_check::nll::region_infer::Cause;
|
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 borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
use dataflow::move_paths::MoveData;
|
use dataflow::move_paths::MoveData;
|
||||||
use dataflow::FlowAtLocation;
|
use dataflow::FlowAtLocation;
|
||||||
@ -621,7 +622,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
|
|||||||
/// hence it must report on their liveness constraints.
|
/// hence it must report on their liveness constraints.
|
||||||
crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
|
crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
|
||||||
|
|
||||||
crate outlives_constraints: Vec<OutlivesConstraint>,
|
crate outlives_constraints: ConstraintSet,
|
||||||
|
|
||||||
crate type_tests: Vec<TypeTest<'tcx>>,
|
crate type_tests: Vec<TypeTest<'tcx>>,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user