From f24e90ec25c066578b7ff33bbc27331e31649a14 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Tue, 19 Jun 2018 05:08:24 -0400
Subject: [PATCH] extract more helpers from instantiating query result

---
 src/librustc/infer/canonical/query_result.rs | 103 ++++++++++++++-----
 1 file changed, 79 insertions(+), 24 deletions(-)

diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs
index 3fc68994e21..71cefda6b66 100644
--- a/src/librustc/infer/canonical/query_result.rs
+++ b/src/librustc/infer/canonical/query_result.rs
@@ -19,8 +19,8 @@
 
 use infer::canonical::substitute::substitute_value;
 use infer::canonical::{
-    Canonical, CanonicalVarValues, CanonicalizedQueryResult, Certainty,
-    QueryRegionConstraint, QueryResult,
+    Canonical, CanonicalVarValues, CanonicalizedQueryResult, Certainty, QueryRegionConstraint,
+    QueryResult,
 };
 use infer::region_constraints::{Constraint, RegionConstraintData};
 use infer::{InferCtxt, InferOk, InferResult, RegionObligation};
@@ -155,12 +155,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     where
         R: Debug + TypeFoldable<'tcx>,
     {
-        let InferOk { value: result_subst, mut obligations } = self.query_result_substitution(
-            cause,
-            param_env,
-            original_values,
-            query_result,
-        )?;
+        let InferOk {
+            value: result_subst,
+            mut obligations,
+        } = self.query_result_substitution(cause, param_env, original_values, query_result)?;
 
         obligations.extend(self.query_region_constraints_into_obligations(
             cause,
@@ -188,7 +186,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// example) we are doing lazy normalization and the value
     /// assigned to a type variable is unified with an unnormalized
     /// projection.
-    pub fn query_result_substitution<R>(
+    fn query_result_substitution<R>(
         &self,
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -199,7 +197,49 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         R: Debug + TypeFoldable<'tcx>,
     {
         debug!(
-            "instantiate_query_result(original_values={:#?}, query_result={:#?})",
+            "query_result_substitution(original_values={:#?}, query_result={:#?})",
+            original_values, query_result,
+        );
+
+        let result_subst =
+            self.query_result_substitution_guess(cause, original_values, query_result);
+
+        let obligations = self
+            .unify_query_result_substitution_guess(
+                cause,
+                param_env,
+                original_values,
+                &result_subst,
+                query_result,
+            )?
+            .into_obligations();
+
+        Ok(InferOk {
+            value: result_subst,
+            obligations,
+        })
+    }
+
+    /// Given the original values and the (canonicalized) result from
+    /// computing a query, returns a **guess** at a substitution that
+    /// can be applied to the query result to convert the result back
+    /// into the original namespace. This is called a **guess**
+    /// because it uses a quick heuristic to find the values for each
+    /// canonical variable; if that quick heuristic fails, then we
+    /// will instantiate fresh inference variables for each canonical
+    /// variable instead. Therefore, the result of this method must be
+    /// properly unified
+    fn query_result_substitution_guess<R>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        original_values: &CanonicalVarValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+    ) -> CanonicalVarValues<'tcx>
+    where
+        R: Debug + TypeFoldable<'tcx>,
+    {
+        debug!(
+            "query_result_substitution_guess(original_values={:#?}, query_result={:#?})",
             original_values, query_result,
         );
 
@@ -256,22 +296,37 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                 .collect(),
         };
 
-        // Unify the original values for the canonical variables in
-        // the input with the value found in the query
-        // post-substitution. Often, but not always, this is a no-op,
-        // because we already found the mapping in the first step.
-        let obligations = {
-            let substituted_values = |index: CanonicalVar| -> Kind<'tcx> {
-                query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
-            };
-            self.unify_canonical_vars(cause, param_env, original_values, substituted_values)?
-                .into_obligations()
+        result_subst
+    }
+
+    /// Given a "guess" at the values for the canonical variables in
+    /// the input, try to unify with the *actual* values found in the
+    /// query result.  Often, but not always, this is a no-op, because
+    /// we already found the mapping in the "guessing" step.
+    ///
+    /// See also: `query_result_substitution_guess`
+    fn unify_query_result_substitution_guess<R>(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        original_values: &CanonicalVarValues<'tcx>,
+        result_subst: &CanonicalVarValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
+    ) -> InferResult<'tcx, ()>
+    where
+        R: Debug + TypeFoldable<'tcx>,
+    {
+        // A closure that yields the result value for the given
+        // canonical variable; this is taken from
+        // `query_result.var_values` after applying the substitution
+        // `result_subst`.
+        let substituted_query_result = |index: CanonicalVar| -> Kind<'tcx> {
+            query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
         };
 
-        Ok(InferOk {
-            value: result_subst,
-            obligations,
-        })
+        // Unify the original value for each variable with the value
+        // taken from `query_result` (after applying `result_subst`).
+        Ok(self.unify_canonical_vars(cause, param_env, original_values, substituted_query_result)?)
     }
 
     /// Converts the region constraints resulting from a query into an