From fd046a2ede1f83383e7a4a5f653f75550db91ea4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 24 Sep 2018 15:15:25 -0400 Subject: [PATCH] bundle up "canonical instantiation" with infcx creation --- src/librustc/infer/canonical/mod.rs | 19 ++++++++++----- src/librustc/infer/canonical/query_result.rs | 4 +--- src/librustc/infer/mod.rs | 25 ++++++++++++++++++-- src/librustc_traits/dropck_outlives.rs | 17 ++++++------- src/librustc_traits/evaluate_obligation.rs | 15 +++++------- 5 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index 85aa4f62f214..6e9d87c089b4 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -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( + /// 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( &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); diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index a327f1f5c9d5..d75d39201c49 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -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) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 291b46edccfb..0c1615368317 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -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(&'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( + &'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(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R { let InferCtxtBuilder { global_tcx, diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 2996fe032004..1745679bc27f 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -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>>>, 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![], diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs index b5ee346569a6..4487bb11f6da 100644 --- a/src/librustc_traits/evaluate_obligation.rs +++ b/src/librustc_traits/evaluate_obligation.rs @@ -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 { - 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);