mk fully_perform_op_and_get_region_constraint_data a TypeOp method

This commit is contained in:
Niko Matsakis 2018-06-07 06:02:08 -04:00
parent efc84c83f9
commit 6ac89174b8
3 changed files with 82 additions and 56 deletions

View File

@ -9,7 +9,7 @@
// except according to those terms.
use borrow_check::nll::region_infer::Cause;
use borrow_check::nll::type_check::type_op::DropckOutlives;
use borrow_check::nll::type_check::type_op::{DropckOutlives, TypeOp};
use borrow_check::nll::type_check::AtLocation;
use dataflow::move_paths::{HasMoveData, MoveData};
use dataflow::MaybeInitializedPlaces;
@ -218,10 +218,15 @@ impl<'gen, 'typeck, 'flow, 'gcx, 'tcx> TypeLivenessGenerator<'gen, 'typeck, 'flo
let param_env = cx.param_env;
let (dropped_kinds, region_constraint_data) =
cx.fully_perform_op_and_get_region_constraint_data(DropckOutlives::new(
DropckOutlives::new(
param_env,
dropped_ty,
)).unwrap();
).fully_perform(
cx.infcx,
cx.region_bound_pairs,
cx.implicit_region_bound,
cx.param_env,
).unwrap();
DropData {
dropped_kinds,

View File

@ -21,12 +21,12 @@ use dataflow::FlowAtLocation;
use dataflow::MaybeInitializedPlaces;
use rustc::hir::def_id::DefId;
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, UnitResult};
use rustc::infer::{InferCtxt, LateBoundRegionConversionTime, UnitResult};
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
use rustc::mir::tcx::PlaceTy;
use rustc::mir::visit::{PlaceContext, Visitor};
use rustc::mir::*;
use rustc::traits::{ObligationCause, TraitEngine};
use rustc::traits::ObligationCause;
use rustc::ty::error::TypeError;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
@ -733,18 +733,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
locations: Locations,
op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
) -> Result<R, TypeError<'tcx>> {
match op.trivial_noop() {
Ok(r) => Ok(r),
Err(op) => {
let (r, opt_data) = self.fully_perform_op_and_get_region_constraint_data(op)?;
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 {
self.push_region_constraints(locations, data);
}
Ok(r)
}
if let Some(data) = opt_data {
self.push_region_constraints(locations, data);
}
Ok(r)
}
fn push_region_constraints(
@ -769,45 +769,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
/// Helper for `fully_perform_op`, but also used on its own
/// sometimes to enable better caching: executes `op` fully (along
/// with resulting obligations) and returns the full set of region
/// obligations. If the same `op` were to be performed at some
/// other location, then the same set of region obligations would
/// be generated there, so this can be useful for caching.
fn fully_perform_op_and_get_region_constraint_data<R>(
&mut self,
op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
) -> Result<(R, Option<Rc<RegionConstraintData<'tcx>>>), TypeError<'tcx>> {
if cfg!(debug_assertions) {
info!("fully_perform_op_and_get_region_constraint_data({:?})", op,);
}
let infcx = self.infcx;
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op.perform(infcx))?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
}
infcx.process_registered_region_obligations(
self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
dummy_body_id,
);
let data = infcx.take_and_reset_region_constraints();
if data.is_empty() {
Ok((value, None))
} else {
Ok((value, Some(Rc::new(data))))
}
}
fn sub_types(
&mut self,
sub: Ty<'tcx>,

View File

@ -9,12 +9,16 @@
// except according to those terms.
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};
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::{ParamEnv, Predicate, Ty};
use rustc::ty::{self, ParamEnv, Predicate, Ty};
use std::rc::Rc;
use std::fmt;
use syntax::codemap::DUMMY_SP;
pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
type Output;
@ -23,9 +27,65 @@ pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
/// produce the output, else returns `Err(self)` back.
fn trivial_noop(self) -> Result<Self::Output, Self>;
/// Given an infcx, performs **the kernel** of the operation: this does the
/// key action and then, optionally, returns a set of obligations which must be proven.
///
/// This method is not meant to be invoked directly: instead, one
/// should use `fully_perform`, which will take those resulting
/// obligations and prove them, and then process the combined
/// results into region obligations which are returned.
fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output>;
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
#[inline(never)]
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>> {
let op = match self.trivial_noop() {
Ok(r) => return Ok((r, None)),
Err(op) => op,
};
if cfg!(debug_assertions) {
info!("fully_perform_op_and_get_region_constraint_data({:?})", op);
}
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op.perform(infcx))?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
&format!("errors selecting obligation during MIR typeck: {:?}", e)
);
}
infcx.process_registered_region_obligations(
region_bound_pairs,
implicit_region_bound,
param_env,
dummy_body_id,
);
let data = infcx.take_and_reset_region_constraints();
if data.is_empty() {
Ok((value, None))
} else {
Ok((value, Some(Rc::new(data))))
}
}
}
pub(super) struct CustomTypeOp<F, G> {
closure: F,
description: G,