From c8cf710ce032e87947d0107dcfb5d3f4c90a6849 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 8 Jun 2018 10:08:44 -0400 Subject: [PATCH] replace `LexicalRegionConstraintData` with `QueryRegionConstraint` --- src/librustc/infer/canonical/mod.rs | 2 +- src/librustc/infer/canonical/query_result.rs | 2 +- .../nll/type_check/constraint_conversion.rs | 130 +++++++++--------- .../borrow_check/nll/type_check/liveness.rs | 5 +- .../borrow_check/nll/type_check/mod.rs | 29 +--- .../nll/type_check/type_op/mod.rs | 37 ++--- 6 files changed, 84 insertions(+), 121 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 037fc637ec91..33e5f6cd3e27 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -44,7 +44,7 @@ use rustc_data_structures::indexed_vec::IndexVec; mod canonicalizer; -mod query_result; +pub mod query_result; mod substitute; diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index 88d5d10d3c2b..4d03ccb42a9f 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -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>, 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 44f8420ca7ed..96e99aae6937 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 @@ -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>, diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs index 92a60602b796..37898adeb923 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -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>, - region_constraint_data: Option>>, + region_constraint_data: Option>>>, } impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> { 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 cb16461de491..92ee1f2a892e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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>, } -/// 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>, - - /// The `T: 'a` (and `'a: 'b`, in some cases) constraints - /// extracted from the pending "region obligations". - region_obligations: Vec>, -} - /// 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() - } -} diff --git a/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs index 263bce8067f2..434b1d799ae1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/type_op/mod.rs @@ -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>>), TypeError<'tcx>> { + ) -> Result<(Self::Output, Option>>>), 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() { + ®ion_constraint_data, + ); + + if outlives.is_empty() { Ok((value, None)) } else { - Ok((value, Some(Rc::new(data)))) + Ok((value, Some(Rc::new(outlives)))) } } }