bundle up "canonical instantiation" with infcx creation

This commit is contained in:
Niko Matsakis 2018-09-24 15:15:25 -04:00
parent 110b3b971e
commit fd046a2ede
5 changed files with 50 additions and 30 deletions

View file

@ -225,12 +225,16 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
/// inference variables and applies it to the canonical value.
/// Returns both the instantiated result *and* the substitution S.
///
/// This is useful at the start of a query: it basically brings
/// the canonical value "into scope" within your new infcx. At the
/// end of processing, the substitution S (once canonicalized)
/// then represents the values that you computed for each of the
/// canonical inputs to your query.
pub fn instantiate_canonical_with_fresh_inference_vars<T>(
/// This is only meant to be invoked as part of constructing an
/// inference context at the start of a query (see
/// `InferCtxtBuilder::enter_with_canonical`). It basically
/// brings the canonical value "into scope" within your new infcx.
///
/// At the end of processing, the substitution S (once
/// canonicalized) then represents the values that you computed
/// for each of the canonical inputs to your query.
pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
&self,
span: Span,
canonical: &Canonical<'tcx, T>,
@ -238,6 +242,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
where
T: TypeFoldable<'tcx>,
{
assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created");
assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created");
let canonical_inference_vars =
self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
let result = canonical.substitute(self.tcx, &canonical_inference_vars);

View file

@ -64,9 +64,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
K: TypeFoldable<'tcx>,
R: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
{
self.enter(|ref infcx| {
let (key, canonical_inference_vars) =
infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_key);
self.enter_with_canonical(DUMMY_SP, canonical_key, |ref infcx, key, canonical_inference_vars| {
let fulfill_cx = &mut FulfillmentContext::new();
let value = operation(infcx, fulfill_cx, key)?;
infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx)

View file

@ -20,6 +20,7 @@ pub use ty::IntVarValue;
use arena::SyncDroplessArena;
use errors::DiagnosticBuilder;
use hir::def_id::DefId;
use infer::canonical::{Canonical, CanonicalVarValues};
use middle::free_region::RegionRelations;
use middle::lang_items;
use middle::region;
@ -494,9 +495,29 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
self
}
pub fn enter<F, R>(&'tcx mut self, f: F) -> R
/// Given a canonical value `C` as a starting point, create an
/// inference context that contains each of the bound values
/// within instantiated as a fresh variable. The `f` closure is
/// invoked with the new infcx, along with the instantiated value
/// `V` and a substitution `S`. This substitution `S` maps from
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
pub fn enter_with_canonical<T, R>(
&'tcx mut self,
span: Span,
canonical: &Canonical<'tcx, T>,
f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
) -> R
where
F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R,
T: TypeFoldable<'tcx>,
{
self.enter(|infcx| {
let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
f(infcx, value, subst)
})
}
pub fn enter<R>(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R
{
let InferCtxtBuilder {
global_tcx,

View file

@ -30,19 +30,16 @@ crate fn provide(p: &mut Providers) {
fn dropck_outlives<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
goal: CanonicalTyGoal<'tcx>,
canonical_goal: CanonicalTyGoal<'tcx>,
) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>, NoSolution> {
debug!("dropck_outlives(goal={:#?})", goal);
debug!("dropck_outlives(goal={:#?})", canonical_goal);
tcx.infer_ctxt().enter(|ref infcx| {
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &canonical_goal, |ref infcx, goal, canonical_inference_vars| {
let tcx = infcx.tcx;
let (
ParamEnvAnd {
param_env,
value: for_ty,
},
canonical_inference_vars,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
let ParamEnvAnd {
param_env,
value: for_ty,
} = goal;
let mut result = DropckOutlivesResult {
kinds: vec![],

View file

@ -24,16 +24,13 @@ crate fn provide(p: &mut Providers) {
fn evaluate_obligation<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
goal: CanonicalPredicateGoal<'tcx>,
canonical_goal: CanonicalPredicateGoal<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
tcx.infer_ctxt().enter(|ref infcx| {
let (
ParamEnvAnd {
param_env,
value: predicate,
},
_canonical_inference_vars,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &canonical_goal, |ref infcx, goal, _canonical_inference_vars| {
let ParamEnvAnd {
param_env,
value: predicate,
} = goal;
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);