diff options
6 files changed, 175 insertions, 101 deletions
diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs index 6aafebe79c6..93079b04669 100644 --- a/src/librustc/infer/outlives/mod.rs +++ b/src/librustc/infer/outlives/mod.rs @@ -13,4 +13,4 @@ pub mod env; pub mod free_region_map; pub mod bounds; -mod obligations; +pub mod obligations; diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index c0d530618ec..07286f1250c 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -250,7 +250,7 @@ impl<'cx, 'gcx, 'tcx, D> TypeOutlives<'cx, 'gcx, 'tcx, D> where D: TypeOutlivesDelegate<'tcx>, { - fn new( + pub fn new( delegate: D, tcx: TyCtxt<'cx, 'gcx, 'tcx>, region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], @@ -274,7 +274,7 @@ where /// - `origin`, the reason we need this constraint /// - `ty`, the type `T` /// - `region`, the region `'a` - fn type_must_outlive( + pub fn type_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, ty: Ty<'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 06aaf6810fa..44f8420ca7e 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,64 +11,66 @@ 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; +use borrow_check::nll::type_check::{Locations, LexicalRegionConstraintData}; use borrow_check::nll::universal_regions::UniversalRegions; -use rustc::infer::region_constraints::Constraint; -use rustc::infer::region_constraints::RegionConstraintData; -use rustc::infer::region_constraints::{Verify, VerifyBound}; +use rustc::infer::{self, RegionObligation, SubregionOrigin}; +use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; +use rustc::infer::region_constraints::{Constraint, GenericKind, VerifyBound}; use rustc::mir::{Location, Mir}; -use rustc::ty; +use rustc::ty::{self, TyCtxt}; use syntax::codemap::Span; -crate struct ConstraintConversion<'a, 'tcx: 'a> { +crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, + region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], + implicit_region_bound: Option<ty::Region<'tcx>>, + param_env: ty::ParamEnv<'tcx>, + locations: Locations, outlives_constraints: &'a mut Vec<OutlivesConstraint>, type_tests: &'a mut Vec<TypeTest<'tcx>>, all_facts: &'a mut Option<AllFacts>, - } -impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> { crate fn new( + tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a LocationTable, + region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], + implicit_region_bound: Option<ty::Region<'tcx>>, + param_env: ty::ParamEnv<'tcx>, + locations: Locations, outlives_constraints: &'a mut Vec<OutlivesConstraint>, type_tests: &'a mut Vec<TypeTest<'tcx>>, all_facts: &'a mut Option<AllFacts>, ) -> Self { Self { + tcx, mir, universal_regions, location_table, + region_bound_pairs, + implicit_region_bound, + param_env, + locations, outlives_constraints, type_tests, all_facts, } } - crate fn convert( - &mut self, - locations: Locations, - data: &RegionConstraintData<'tcx>, - ) { - debug!("generate: constraints at: {:#?}", locations); - let RegionConstraintData { + pub(super) fn convert(&mut self, data: &LexicalRegionConstraintData<'tcx>) { + debug!("generate: constraints at: {:#?}", self.locations); + let LexicalRegionConstraintData { constraints, - verifys, - givens, + region_obligations, } = data; - let span = self - .mir - .source_info(locations.from_location().unwrap_or(Location::START)) - .span; - - let at_location = locations.at_location().unwrap_or(Location::START); - - for constraint in constraints.keys() { + 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), @@ -84,13 +86,13 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // reverse direction, because `regioncx` talks about // "outlives" (`>=`) whereas the region constraints // talk about `<=`. - self.add_outlives(span, b_vid, a_vid, at_location); + 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) = locations.from_location() { + if let Some(from_location) = self.locations.from_location() { all_facts.outlives.push(( b_vid, a_vid, @@ -104,36 +106,50 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } - for verify in verifys { - let type_test = self.verify_to_type_test(verify, span, locations); - self.add_type_test(type_test); + let ConstraintConversion { + tcx, + region_bound_pairs, + implicit_region_bound, + 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); + + TypeOutlives::new( + &mut *self, + tcx, + region_bound_pairs, + implicit_region_bound, + param_env, + ).type_must_outlive(origin, sup_type, sub_region); } - - assert!( - givens.is_empty(), - "MIR type-checker does not use givens (thank goodness)" - ); } fn verify_to_type_test( &self, - verify: &Verify<'tcx>, - span: Span, - locations: Locations, + generic_kind: GenericKind<'tcx>, + region: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, ) -> TypeTest<'tcx> { - let generic_kind = verify.kind; + let lower_bound = self.to_region_vid(region); - let lower_bound = self.to_region_vid(verify.region); + let point = self.locations.at_location().unwrap_or(Location::START); - let point = locations.at_location().unwrap_or(Location::START); - - let test = self.verify_bound_to_region_test(&verify.bound); + let test = self.verify_bound_to_region_test(&bound); TypeTest { generic_kind, lower_bound, point, - span, + span: self.span(), test, } } @@ -168,13 +184,21 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.universal_regions.to_region_vid(r) } + fn span(&self) -> Span { + self + .mir + .source_info(self.locations.from_location().unwrap_or(Location::START)) + .span + } + fn add_outlives( &mut self, - span: Span, sup: ty::RegionVid, sub: ty::RegionVid, - point: Location, ) { + let span = self.span(); + let point = self.locations.at_location().unwrap_or(Location::START); + self.outlives_constraints.push(OutlivesConstraint { span, sub, @@ -188,3 +212,27 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.type_tests.push(type_test); } } + +impl<'a, 'b, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'gcx, 'tcx> { + fn push_sub_region_constraint( + &mut self, + _origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) { + let b = self.universal_regions.to_region_vid(b); + let a = self.universal_regions.to_region_vid(a); + self.add_outlives(b, a); + } + + fn push_verify( + &mut self, + _origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ) { + let type_test = self.verify_to_type_test(kind, a, bound); + self.add_type_test(type_test); + } +} 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 9c854e38cc5..92a60602b79 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness.rs @@ -10,11 +10,10 @@ use borrow_check::nll::region_infer::Cause; use borrow_check::nll::type_check::type_op::{DropckOutlives, TypeOp}; -use borrow_check::nll::type_check::AtLocation; +use borrow_check::nll::type_check::{AtLocation, LexicalRegionConstraintData}; use dataflow::move_paths::{HasMoveData, MoveData}; use dataflow::MaybeInitializedPlaces; use dataflow::{FlowAtLocation, FlowsAtLocation}; -use rustc::infer::region_constraints::RegionConstraintData; use rustc::mir::Local; use rustc::mir::{BasicBlock, Location, Mir}; use rustc::ty::subst::Kind; @@ -71,7 +70,7 @@ where struct DropData<'tcx> { dropped_kinds: Vec<Kind<'tcx>>, - region_constraint_data: Option<Rc<RegionConstraintData<'tcx>>>, + region_constraint_data: Option<Rc<LexicalRegionConstraintData<'tcx>>>, } impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flow, 'gcx, 'tcx> { @@ -198,8 +197,7 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo }); if let Some(data) = &drop_data.region_constraint_data { - self.cx - .push_region_constraints(location.at_self(), data.clone()); + self.cx.push_region_constraints(location.at_self(), data); } // All things in the `outlives` array may be touched by @@ -217,16 +215,9 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,); let param_env = cx.param_env; - let (dropped_kinds, region_constraint_data) = - DropckOutlives::new( - param_env, - dropped_ty, - ).fully_perform( - cx.infcx, - cx.region_bound_pairs, - cx.implicit_region_bound, - cx.param_env, - ).unwrap(); + let (dropped_kinds, region_constraint_data) = DropckOutlives::new(param_env, dropped_ty) + .fully_perform(cx.infcx) + .unwrap(); DropData { dropped_kinds, 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 e2f6ad0bde3..cb16461de49 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,8 @@ use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; use dataflow::MaybeInitializedPlaces; use rustc::hir::def_id::DefId; -use rustc::infer::region_constraints::{GenericKind, RegionConstraintData}; -use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, UnitResult}; +use rustc::infer::region_constraints::{Constraint, GenericKind}; +use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, RegionObligation, UnitResult}; use rustc::mir::interpret::EvalErrorKind::BoundsCheck; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; @@ -31,7 +31,6 @@ use rustc::ty::error::TypeError; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants}; use std::fmt; -use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; use transform::{MirPass, MirSource}; use util::liveness::LivenessResults; @@ -626,6 +625,21 @@ 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 @@ -733,14 +747,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations: Locations, op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>, ) -> Result<R, TypeError<'tcx>> { - let (r, opt_data) = op.fully_perform( - self.infcx, - self.region_bound_pairs, - self.implicit_region_bound, - self.param_env, - )?; - - if let Some(data) = opt_data { + let (r, opt_data) = op.fully_perform(self.infcx)?; + + if let Some(data) = &opt_data { self.push_region_constraints(locations, data); } @@ -750,7 +759,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn push_region_constraints( &mut self, locations: Locations, - data: Rc<RegionConstraintData<'tcx>>, + data: &LexicalRegionConstraintData<'tcx>, ) { debug!( "push_region_constraints: constraints generated at {:?} are {:#?}", @@ -759,13 +768,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Some(borrowck_context) = &mut self.borrowck_context { constraint_conversion::ConstraintConversion::new( + self.infcx.tcx, self.mir, borrowck_context.universal_regions, borrowck_context.location_table, + self.region_bound_pairs, + self.implicit_region_bound, + self.param_env, + locations, &mut self.constraints.outlives_constraints, &mut self.constraints.type_tests, &mut borrowck_context.all_facts, - ).convert(locations, &data); + ).convert(&data); } } @@ -1689,3 +1703,10 @@ 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 c3801b4fbac..263bce8067f 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,16 +8,17 @@ // 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::{InferCtxt, InferOk, InferResult}; -use rustc::infer::region_constraints::{GenericKind, RegionConstraintData}; use rustc::traits::query::NoSolution; use rustc::traits::{Normalized, Obligation, ObligationCause, PredicateObligation, TraitEngine}; use rustc::ty::error::TypeError; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Kind; -use rustc::ty::{self, ParamEnv, Predicate, Ty}; -use std::rc::Rc; +use rustc::ty::{ParamEnv, Predicate, Ty}; use std::fmt; +use std::rc::Rc; use syntax::codemap::DUMMY_SP; pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug { @@ -43,10 +44,7 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug { fn fully_perform( self, infcx: &InferCtxt<'_, 'gcx, 'tcx>, - region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)], - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ParamEnv<'tcx>, - ) -> Result<(Self::Output, Option<Rc<RegionConstraintData<'tcx>>>), TypeError<'tcx>> { + ) -> Result<(Self::Output, Option<Rc<LexicalRegionConstraintData<'tcx>>>), TypeError<'tcx>> { let op = match self.trivial_noop() { Ok(r) => return Ok((r, None)), Err(op) => op, @@ -68,14 +66,29 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug { ); } - infcx.process_registered_region_obligations( - region_bound_pairs, - implicit_region_bound, - param_env, - dummy_body_id, - ); + let region_obligations: Vec<_> = infcx + .take_registered_region_obligations() + .into_iter() + .map(|(_node_id, region_obligation)| region_obligation) + .collect(); + + let RegionConstraintData { + constraints, + verifys, + givens, + } = infcx.take_and_reset_region_constraints(); - let 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(), + region_obligations, + }; if data.is_empty() { Ok((value, None)) } else { @@ -84,8 +97,6 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug { } } - - pub(super) struct CustomTypeOp<F, G> { closure: F, description: G, @@ -97,7 +108,10 @@ impl<F, G> CustomTypeOp<F, G> { F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R>, G: Fn() -> String, { - CustomTypeOp { closure, description } + CustomTypeOp { + closure, + description, + } } } @@ -277,11 +291,11 @@ pub(super) struct DropckOutlives<'tcx> { } impl<'tcx> DropckOutlives<'tcx> { - pub(super) fn new( - param_env: ParamEnv<'tcx>, - dropped_ty: Ty<'tcx>, - ) -> Self { - DropckOutlives { param_env, dropped_ty } + pub(super) fn new(param_env: ParamEnv<'tcx>, dropped_ty: Ty<'tcx>) -> Self { + DropckOutlives { + param_env, + dropped_ty, + } } } @@ -294,7 +308,7 @@ impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for DropckOutlives<'tcx> { fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> { Ok(infcx - .at(&ObligationCause::dummy(), self.param_env) - .dropck_outlives(self.dropped_ty)) + .at(&ObligationCause::dummy(), self.param_env) + .dropck_outlives(self.dropped_ty)) } } |
