diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs index b6d8f6ae946e87c815f167ad77f21904202dfd26..d40daf73115fcedf2aeb8decfbb2d97aaae77b69 100644 --- a/src/librustc/infer/canonical/query_result.rs +++ b/src/librustc/infer/canonical/query_result.rs @@ -152,6 +152,49 @@ pub fn instantiate_query_result_and_region_obligations( original_values: &CanonicalVarValues<'tcx>, query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, ) -> InferResult<'tcx, R> + where + R: Debug + TypeFoldable<'tcx>, + { + 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, + param_env, + &query_result.value.region_constraints, + &result_subst, + )); + + let user_result: R = + query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + + Ok(InferOk { + value: user_result, + obligations, + }) + } + + /// Given the original values and the (canonicalized) result from + /// computing a query, returns a substitution that can be applied + /// to the query result to convert the result back into the + /// original namespace. + /// + /// The substitution also comes accompanied with subobligations + /// that arose from unification; these might occur if (for + /// 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( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &CanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> where R: Debug + TypeFoldable<'tcx>, { @@ -201,7 +244,7 @@ pub fn instantiate_query_result_and_region_obligations( // Create a result substitution: if we found a value for a // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. - let result_subst = &CanonicalVarValues { + let result_subst = CanonicalVarValues { var_values: query_result .variables .iter() @@ -217,25 +260,16 @@ pub fn instantiate_query_result_and_region_obligations( // 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 substituted_values = |index: CanonicalVar| -> Kind<'tcx> { - query_result.substitute_projected(self.tcx, result_subst, |v| &v.var_values[index]) + 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() }; - let mut obligations = self - .unify_canonical_vars(cause, param_env, original_values, substituted_values)? - .into_obligations(); - - obligations.extend(self.query_region_constraints_into_obligations( - cause, - param_env, - &query_result.value.region_constraints, - result_subst, - )); - - let user_result: R = - query_result.substitute_projected(self.tcx, result_subst, |q_r| &q_r.value); Ok(InferOk { - value: user_result, + value: result_subst, obligations, }) }