replace LexicalRegionConstraintData with QueryRegionConstraint

This commit is contained in:
Niko Matsakis 2018-06-08 10:08:44 -04:00
parent 2624c14a26
commit c8cf710ce0
6 changed files with 84 additions and 121 deletions

View file

@ -44,7 +44,7 @@ use rustc_data_structures::indexed_vec::IndexVec;
mod canonicalizer;
mod query_result;
pub mod query_result;
mod substitute;

View file

@ -325,7 +325,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
/// Given the region obligations and constraints scraped from the infcx,
/// creates query region constraints.
fn make_query_outlives<'tcx>(
pub fn make_query_outlives<'tcx>(
tcx: TyCtxt<'_, '_, 'tcx>,
region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,

View file

@ -11,13 +11,15 @@
use borrow_check::location::LocationTable;
use borrow_check::nll::facts::AllFacts;
use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest};
use borrow_check::nll::type_check::{Locations, LexicalRegionConstraintData};
use borrow_check::nll::type_check::Locations;
use borrow_check::nll::universal_regions::UniversalRegions;
use rustc::infer::{self, RegionObligation, SubregionOrigin};
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc::infer::region_constraints::{Constraint, GenericKind, VerifyBound};
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
use rustc::infer::{self, SubregionOrigin};
use rustc::mir::{Location, Mir};
use rustc::ty::{self, TyCtxt};
use rustc::ty::subst::UnpackedKind;
use syntax::codemap::Span;
crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
@ -63,49 +65,10 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
}
}
pub(super) fn convert(&mut self, data: &LexicalRegionConstraintData<'tcx>) {
pub(super) fn convert(&mut self, query_constraints: &[QueryRegionConstraint<'tcx>]) {
debug!("generate: constraints at: {:#?}", self.locations);
let LexicalRegionConstraintData {
constraints,
region_obligations,
} = data;
for constraint in constraints {
debug!("generate: constraint: {:?}", constraint);
let (a_vid, b_vid) = match constraint {
Constraint::VarSubVar(a_vid, b_vid) => (*a_vid, *b_vid),
Constraint::RegSubVar(a_r, b_vid) => (self.to_region_vid(a_r), *b_vid),
Constraint::VarSubReg(a_vid, b_r) => (*a_vid, self.to_region_vid(b_r)),
Constraint::RegSubReg(a_r, b_r) => {
(self.to_region_vid(a_r), self.to_region_vid(b_r))
}
};
// We have the constraint that `a_vid <= b_vid`. Add
// `b_vid: a_vid` to our region checker. Note that we
// reverse direction, because `regioncx` talks about
// "outlives" (`>=`) whereas the region constraints
// talk about `<=`.
self.add_outlives(b_vid, a_vid);
// In the new analysis, all outlives relations etc
// "take effect" at the mid point of the statement
// that requires them, so ignore the `at_location`.
if let Some(all_facts) = &mut self.all_facts {
if let Some(from_location) = self.locations.from_location() {
all_facts.outlives.push((
b_vid,
a_vid,
self.location_table.mid_index(from_location),
));
} else {
for location in self.location_table.all_points() {
all_facts.outlives.push((b_vid, a_vid, location));
}
}
}
}
// Extract out various useful fields we'll need below.
let ConstraintConversion {
tcx,
region_bound_pairs,
@ -113,23 +76,59 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
param_env,
..
} = *self;
for r_o in region_obligations {
let RegionObligation {
sup_type,
sub_region,
cause,
} = r_o;
// we don't actually use this for anything.
let origin = infer::RelateParamBound(cause.span, sup_type);
for query_constraint in query_constraints {
// At the moment, we never generate any "higher-ranked"
// region constraints like `for<'a> 'a: 'b`. At some point
// when we move to universes, we will, and this assertion
// will start to fail.
let ty::OutlivesPredicate(k1, r2) =
query_constraint.no_late_bound_regions().unwrap_or_else(|| {
span_bug!(
self.span(),
"query_constraint {:?} contained bound regions",
query_constraint,
);
});
TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
implicit_region_bound,
param_env,
).type_must_outlive(origin, sup_type, sub_region);
match k1.unpack() {
UnpackedKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
self.add_outlives(r1_vid, r2_vid);
// In the new analysis, all outlives relations etc
// "take effect" at the mid point of the statement
// that requires them, so ignore the `at_location`.
if let Some(all_facts) = &mut self.all_facts {
if let Some(from_location) = self.locations.from_location() {
all_facts.outlives.push((
r1_vid,
r2_vid,
self.location_table.mid_index(from_location),
));
} else {
for location in self.location_table.all_points() {
all_facts.outlives.push((r1_vid, r2_vid, location));
}
}
}
}
UnpackedKind::Type(t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(self.span(), t1);
TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
implicit_region_bound,
param_env,
).type_must_outlive(origin, t1, r2);
}
}
}
}
@ -185,17 +184,12 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
}
fn span(&self) -> Span {
self
.mir
self.mir
.source_info(self.locations.from_location().unwrap_or(Location::START))
.span
}
fn add_outlives(
&mut self,
sup: ty::RegionVid,
sub: ty::RegionVid,
) {
fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
let span = self.span();
let point = self.locations.at_location().unwrap_or(Location::START);
@ -213,7 +207,9 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
}
}
impl<'a, 'b, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'gcx, 'tcx> {
impl<'a, 'b, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx>
for &'a mut ConstraintConversion<'b, 'gcx, 'tcx>
{
fn push_sub_region_constraint(
&mut self,
_origin: SubregionOrigin<'tcx>,

View file

@ -10,10 +10,11 @@
use borrow_check::nll::region_infer::Cause;
use borrow_check::nll::type_check::type_op::{DropckOutlives, TypeOp};
use borrow_check::nll::type_check::{AtLocation, LexicalRegionConstraintData};
use borrow_check::nll::type_check::AtLocation;
use dataflow::move_paths::{HasMoveData, MoveData};
use dataflow::MaybeInitializedPlaces;
use dataflow::{FlowAtLocation, FlowsAtLocation};
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::mir::Local;
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::ty::subst::Kind;
@ -70,7 +71,7 @@ where
struct DropData<'tcx> {
dropped_kinds: Vec<Kind<'tcx>>,
region_constraint_data: Option<Rc<LexicalRegionConstraintData<'tcx>>>,
region_constraint_data: Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>,
}
impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> {

View file

@ -20,8 +20,9 @@ use dataflow::move_paths::MoveData;
use dataflow::FlowAtLocation;
use dataflow::MaybeInitializedPlaces;
use rustc::hir::def_id::DefId;
use rustc::infer::region_constraints::{Constraint, GenericKind};
use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, RegionObligation, UnitResult};
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::infer::region_constraints::GenericKind;
use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, UnitResult};
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor};
@ -625,21 +626,6 @@ crate struct MirTypeckRegionConstraints<'tcx> {
crate type_tests: Vec<TypeTest<'tcx>>,
}
/// The type checker layers on top of the "old" inference engine. The
/// idea is that we run some operations, like trait selection, and
/// then we "scrape out" the region constraints that have accumulated
/// from the old lexical solver. This struct just collects the bits of
/// that data that we care about into one place.
#[derive(Debug)]
struct LexicalRegionConstraintData<'tcx> {
/// The `'a <= 'b` constraints extracted from `RegionConstraintData`.
constraints: Vec<Constraint<'tcx>>,
/// The `T: 'a` (and `'a: 'b`, in some cases) constraints
/// extracted from the pending "region obligations".
region_obligations: Vec<RegionObligation<'tcx>>,
}
/// The `Locations` type summarizes *where* region constraints are
/// required to hold. Normally, this is at a particular point which
/// created the obligation, but for constraints that the user gave, we
@ -759,7 +745,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fn push_region_constraints(
&mut self,
locations: Locations,
data: &LexicalRegionConstraintData<'tcx>,
data: &[QueryRegionConstraint<'tcx>],
) {
debug!(
"push_region_constraints: constraints generated at {:?} are {:#?}",
@ -1703,10 +1689,3 @@ impl ToLocations for Location {
self.at_self()
}
}
impl<'tcx> LexicalRegionConstraintData<'tcx> {
fn is_empty(&self) -> bool {
let LexicalRegionConstraintData { constraints, region_obligations } = self;
constraints.is_empty() && region_obligations.is_empty()
}
}

View file

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use borrow_check::nll::type_check::LexicalRegionConstraintData;
use rustc::infer::region_constraints::RegionConstraintData;
use rustc::infer::canonical::query_result;
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::infer::{InferCtxt, InferOk, InferResult};
use rustc::traits::query::NoSolution;
use rustc::traits::{Normalized, Obligation, ObligationCause, PredicateObligation, TraitEngine};
@ -44,7 +44,7 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
fn fully_perform(
self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
) -> Result<(Self::Output, Option<Rc<LexicalRegionConstraintData<'tcx>>>), TypeError<'tcx>> {
) -> Result<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>), TypeError<'tcx>> {
let op = match self.trivial_noop() {
Ok(r) => return Ok((r, None)),
Err(op) => op,
@ -66,33 +66,20 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
);
}
let region_obligations: Vec<_> = infcx
.take_registered_region_obligations()
.into_iter()
.map(|(_node_id, region_obligation)| region_obligation)
.collect();
let region_obligations = infcx.take_registered_region_obligations();
let RegionConstraintData {
constraints,
verifys,
givens,
} = infcx.take_and_reset_region_constraints();
let region_constraint_data = infcx.take_and_reset_region_constraints();
// These are created when we "process" the registered region
// obliations, and that hasn't happened yet.
assert!(verifys.is_empty());
// NLL doesn't use givens (and thank goodness!).
assert!(givens.is_empty());
let data = LexicalRegionConstraintData {
constraints: constraints.keys().cloned().collect(),
let outlives = query_result::make_query_outlives(
infcx.tcx,
region_obligations,
};
if data.is_empty() {
&region_constraint_data,
);
if outlives.is_empty() {
Ok((value, None))
} else {
Ok((value, Some(Rc::new(data))))
Ok((value, Some(Rc::new(outlives))))
}
}
}