1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! This module contains the code to instantiate a "query result", and
12 //! in particular to extract out the resulting region obligations and
13 //! encode them therein.
15 //! For an overview of what canonicaliation is and how it fits into
16 //! rustc, check out the [chapter in the rustc guide][c].
18 //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html
20 use infer::canonical::substitute::substitute_value;
21 use infer::canonical::{
22 Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
23 OriginalQueryValues, QueryRegionConstraint, QueryResponse,
25 use infer::region_constraints::{Constraint, RegionConstraintData};
26 use infer::InferCtxtBuilder;
27 use infer::{InferCtxt, InferOk, InferResult};
28 use rustc_data_structures::indexed_vec::Idx;
29 use rustc_data_structures::indexed_vec::IndexVec;
30 use rustc_data_structures::sync::Lrc;
32 use syntax_pos::DUMMY_SP;
33 use traits::query::{Fallible, NoSolution};
34 use traits::{FulfillmentContext, TraitEngine};
35 use traits::{Obligation, ObligationCause, PredicateObligation};
36 use ty::fold::TypeFoldable;
37 use ty::subst::{Kind, UnpackedKind};
38 use ty::{self, BoundTyIndex, Lift, Ty, TyCtxt};
40 impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> {
41 /// The "main method" for a canonicalized trait query. Given the
42 /// canonical key `canonical_key`, this method will create a new
43 /// inference context, instantiate the key, and run your operation
44 /// `op`. The operation should yield up a result (of type `R`) as
45 /// well as a set of trait obligations that must be fully
46 /// satisfied. These obligations will be processed and the
47 /// canonical result created.
49 /// Returns `NoSolution` in the event of any error.
51 /// (It might be mildly nicer to implement this on `TyCtxt`, and
52 /// not `InferCtxtBuilder`, but that is a bit tricky right now.
53 /// In part because we would need a `for<'gcx: 'tcx>` sort of
54 /// bound for the closure and in part because it is convenient to
55 /// have `'tcx` be free on this function so that we can talk about
56 /// `K: TypeFoldable<'tcx>`.)
57 pub fn enter_canonical_trait_query<K, R>(
59 canonical_key: &Canonical<'tcx, K>,
60 operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut FulfillmentContext<'tcx>, K)
62 ) -> Fallible<CanonicalizedQueryResponse<'gcx, R>>
64 K: TypeFoldable<'tcx>,
65 R: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
67 self.enter_with_canonical(
70 |ref infcx, key, canonical_inference_vars| {
71 let fulfill_cx = &mut FulfillmentContext::new();
72 let value = operation(infcx, fulfill_cx, key)?;
73 infcx.make_canonicalized_query_response(canonical_inference_vars, value, fulfill_cx)
79 impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
80 /// This method is meant to be invoked as the final step of a canonical query
81 /// implementation. It is given:
83 /// - the instantiated variables `inference_vars` created from the query key
84 /// - the result `answer` of the query
85 /// - a fulfillment context `fulfill_cx` that may contain various obligations which
86 /// have yet to be proven.
88 /// Given this, the function will process the obligations pending
91 /// - If all the obligations can be proven successfully, it will
92 /// package up any resulting region obligations (extracted from
93 /// `infcx`) along with the fully resolved value `answer` into a
94 /// query result (which is then itself canonicalized).
95 /// - If some obligations can be neither proven nor disproven, then
96 /// the same thing happens, but the resulting query is marked as ambiguous.
97 /// - Finally, if any of the obligations result in a hard error,
98 /// then `Err(NoSolution)` is returned.
99 pub fn make_canonicalized_query_response<T>(
101 inference_vars: CanonicalVarValues<'tcx>,
103 fulfill_cx: &mut FulfillmentContext<'tcx>,
104 ) -> Fallible<CanonicalizedQueryResponse<'gcx, T>>
106 T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
108 let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?;
109 let canonical_result = self.canonicalize_response(&query_response);
112 "make_canonicalized_query_response: canonical_result = {:#?}",
116 Ok(Lrc::new(canonical_result))
119 /// Helper for `make_canonicalized_query_response` that does
120 /// everything up until the final canonicalization.
121 fn make_query_response<T>(
123 inference_vars: CanonicalVarValues<'tcx>,
125 fulfill_cx: &mut FulfillmentContext<'tcx>,
126 ) -> Result<QueryResponse<'tcx, T>, NoSolution>
128 T: Debug + TypeFoldable<'tcx> + Lift<'gcx>,
133 "make_query_response(\
134 inference_vars={:?}, \
136 inference_vars, answer,
139 // Select everything, returning errors.
140 let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
141 debug!("true_errors = {:#?}", true_errors);
143 if !true_errors.is_empty() {
144 // FIXME -- we don't indicate *why* we failed to solve
145 debug!("make_query_response: true_errors={:#?}", true_errors);
146 return Err(NoSolution);
149 // Anything left unselected *now* must be an ambiguity.
150 let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
151 debug!("ambig_errors = {:#?}", ambig_errors);
153 let region_obligations = self.take_registered_region_obligations();
154 let region_constraints = self.with_region_constraints(|region_constraints| {
159 .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)),
164 let certainty = if ambig_errors.is_empty() {
171 var_values: inference_vars,
178 /// Given the (canonicalized) result to a canonical query,
179 /// instantiates the result so it can be used, plugging in the
180 /// values from the canonical query. (Note that the result may
181 /// have been ambiguous; you should check the certainty level of
182 /// the query before applying this function.)
184 /// To get a good understanding of what is happening here, check
185 /// out the [chapter in the rustc guide][c].
187 /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result
188 pub fn instantiate_query_response_and_region_obligations<R>(
190 cause: &ObligationCause<'tcx>,
191 param_env: ty::ParamEnv<'tcx>,
192 original_values: &OriginalQueryValues<'tcx>,
193 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
194 ) -> InferResult<'tcx, R>
196 R: Debug + TypeFoldable<'tcx>,
201 } = self.query_response_substitution(cause, param_env, original_values, query_response)?;
203 obligations.extend(self.query_region_constraints_into_obligations(
206 &query_response.value.region_constraints,
211 query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
219 /// An alternative to
220 /// `instantiate_query_response_and_region_obligations` that is more
221 /// efficient for NLL. NLL is a bit more advanced in the
222 /// "transition to chalk" than the rest of the compiler. During
223 /// the NLL type check, all of the "processing" of types and
224 /// things happens in queries -- the NLL checker itself is only
225 /// interested in the region obligations (`'a: 'b` or `T: 'b`)
226 /// that come out of these queries, which it wants to convert into
227 /// MIR-based constraints and solve. Therefore, it is most
228 /// convenient for the NLL Type Checker to **directly consume**
229 /// the `QueryRegionConstraint` values that arise from doing a
230 /// query. This is contrast to other parts of the compiler, which
231 /// would prefer for those `QueryRegionConstraint` to be converted
232 /// into the older infcx-style constraints (e.g., calls to
233 /// `sub_regions` or `register_region_obligation`).
235 /// Therefore, `instantiate_nll_query_response_and_region_obligations` performs the same
236 /// basic operations as `instantiate_query_response_and_region_obligations` but
237 /// it returns its result differently:
239 /// - It creates a substitution `S` that maps from the original
240 /// query variables to the values computed in the query
241 /// result. If any errors arise, they are propagated back as an
243 /// - In the case of a successful substitution, we will append
244 /// `QueryRegionConstraint` values onto the
245 /// `output_query_region_constraints` vector for the solver to
246 /// use (if an error arises, some values may also be pushed, but
247 /// they should be ignored).
248 /// - It **can happen** (though it rarely does currently) that
249 /// equating types and things will give rise to subobligations
250 /// that must be processed. In this case, those subobligations
251 /// are propagated back in the return value.
252 /// - Finally, the query result (of type `R`) is propagated back,
253 /// after applying the substitution `S`.
254 pub fn instantiate_nll_query_response_and_region_obligations<R>(
256 cause: &ObligationCause<'tcx>,
257 param_env: ty::ParamEnv<'tcx>,
258 original_values: &OriginalQueryValues<'tcx>,
259 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
260 output_query_region_constraints: &mut Vec<QueryRegionConstraint<'tcx>>,
261 ) -> InferResult<'tcx, R>
263 R: Debug + TypeFoldable<'tcx>,
266 self.query_response_substitution_guess(cause, original_values, query_response);
268 // Compute `QueryRegionConstraint` values that unify each of
269 // the original values `v_o` that was canonicalized into a
271 let mut obligations = vec![];
273 for (index, original_value) in original_values.var_values.iter().enumerate() {
274 // ...with the value `v_r` of that variable from the query.
275 let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| {
276 &v.var_values[BoundTyIndex::new(index)]
278 match (original_value.unpack(), result_value.unpack()) {
279 (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => {
283 (UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => {
284 // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
286 output_query_region_constraints
287 .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)));
288 output_query_region_constraints
289 .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)));
293 (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
294 let ok = self.at(cause, param_env).eq(v1, v2)?;
295 obligations.extend(ok.into_obligations());
300 "kind mismatch, cannot unify {:?} and {:?}",
308 // ...also include the other query region constraints from the query.
309 output_query_region_constraints.extend(
310 query_response.value.region_constraints.iter().filter_map(|r_c| {
311 let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below
312 let k1 = substitute_value(self.tcx, &result_subst, &k1);
313 let r2 = substitute_value(self.tcx, &result_subst, &r2);
315 Some(ty::Binder::bind(ty::OutlivesPredicate(k1, r2)))
323 query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
331 /// Given the original values and the (canonicalized) result from
332 /// computing a query, returns a substitution that can be applied
333 /// to the query result to convert the result back into the
334 /// original namespace.
336 /// The substitution also comes accompanied with subobligations
337 /// that arose from unification; these might occur if (for
338 /// example) we are doing lazy normalization and the value
339 /// assigned to a type variable is unified with an unnormalized
341 fn query_response_substitution<R>(
343 cause: &ObligationCause<'tcx>,
344 param_env: ty::ParamEnv<'tcx>,
345 original_values: &OriginalQueryValues<'tcx>,
346 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
347 ) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
349 R: Debug + TypeFoldable<'tcx>,
352 "query_response_substitution(original_values={:#?}, query_response={:#?})",
353 original_values, query_response,
357 self.query_response_substitution_guess(cause, original_values, query_response);
359 let obligations = self.unify_query_response_substitution_guess(
374 /// Given the original values and the (canonicalized) result from
375 /// computing a query, returns a **guess** at a substitution that
376 /// can be applied to the query result to convert the result back
377 /// into the original namespace. This is called a **guess**
378 /// because it uses a quick heuristic to find the values for each
379 /// canonical variable; if that quick heuristic fails, then we
380 /// will instantiate fresh inference variables for each canonical
381 /// variable instead. Therefore, the result of this method must be
383 fn query_response_substitution_guess<R>(
385 cause: &ObligationCause<'tcx>,
386 original_values: &OriginalQueryValues<'tcx>,
387 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
388 ) -> CanonicalVarValues<'tcx>
390 R: Debug + TypeFoldable<'tcx>,
393 "query_response_substitution_guess(original_values={:#?}, query_response={:#?})",
394 original_values, query_response,
397 // Every canonical query result includes values for each of
398 // the inputs to the query. Therefore, we begin by unifying
399 // these values with the original inputs that were
401 let result_values = &query_response.value.var_values;
402 assert_eq!(original_values.var_values.len(), result_values.len());
404 // Quickly try to find initial values for the canonical
405 // variables in the result in terms of the query. We do this
406 // by iterating down the values that the query gave to each of
407 // the canonical inputs. If we find that one of those values
408 // is directly equal to one of the canonical variables in the
409 // result, then we can type the corresponding value from the
410 // input. See the example above.
411 let mut opt_values: IndexVec<BoundTyIndex, Option<Kind<'tcx>>> =
412 IndexVec::from_elem_n(None, query_response.variables.len());
414 // In terms of our example above, we are iterating over pairs like:
415 // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
416 for (original_value, result_value) in original_values.var_values.iter().zip(result_values) {
417 match result_value.unpack() {
418 UnpackedKind::Type(result_value) => {
419 // e.g., here `result_value` might be `?0` in the example above...
420 if let ty::Infer(ty::InferTy::BoundTy(b)) = result_value.sty {
421 // in which case we would set `canonical_vars[0]` to `Some(?U)`.
422 opt_values[b.var] = Some(*original_value);
425 UnpackedKind::Lifetime(result_value) => {
426 // e.g., here `result_value` might be `'?1` in the example above...
427 if let &ty::RegionKind::ReCanonical(index) = result_value {
428 // in which case we would set `canonical_vars[0]` to `Some('static)`.
429 opt_values[index] = Some(*original_value);
435 // Create a result substitution: if we found a value for a
436 // given variable in the loop above, use that. Otherwise, use
437 // a fresh inference variable.
438 let result_subst = CanonicalVarValues {
439 var_values: query_response
443 .map(|(index, info)| opt_values[BoundTyIndex::new(index)].unwrap_or_else(||
444 self.fresh_inference_var_for_canonical_var(cause.span, *info)
452 /// Given a "guess" at the values for the canonical variables in
453 /// the input, try to unify with the *actual* values found in the
454 /// query result. Often, but not always, this is a no-op, because
455 /// we already found the mapping in the "guessing" step.
457 /// See also: `query_response_substitution_guess`
458 fn unify_query_response_substitution_guess<R>(
460 cause: &ObligationCause<'tcx>,
461 param_env: ty::ParamEnv<'tcx>,
462 original_values: &OriginalQueryValues<'tcx>,
463 result_subst: &CanonicalVarValues<'tcx>,
464 query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
465 ) -> InferResult<'tcx, ()>
467 R: Debug + TypeFoldable<'tcx>,
469 // A closure that yields the result value for the given
470 // canonical variable; this is taken from
471 // `query_response.var_values` after applying the substitution
473 let substituted_query_response = |index: BoundTyIndex| -> Kind<'tcx> {
474 query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index])
477 // Unify the original value for each variable with the value
478 // taken from `query_response` (after applying `result_subst`).
479 Ok(self.unify_canonical_vars(
483 substituted_query_response,
487 /// Converts the region constraints resulting from a query into an
488 /// iterator of obligations.
489 fn query_region_constraints_into_obligations<'a>(
491 cause: &'a ObligationCause<'tcx>,
492 param_env: ty::ParamEnv<'tcx>,
493 unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>],
494 result_subst: &'a CanonicalVarValues<'tcx>,
495 ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
497 unsubstituted_region_constraints
499 .map(move |constraint| {
500 let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
501 let k1 = substitute_value(self.tcx, result_subst, k1);
502 let r2 = substitute_value(self.tcx, result_subst, r2);
508 UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
510 ty::OutlivesPredicate(r1, r2)
512 UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives(
513 ty::Binder::dummy(ty::OutlivesPredicate(
519 ) as Box<dyn Iterator<Item = _>>
522 /// Given two sets of values for the same set of canonical variables, unify them.
523 /// The second set is produced lazilly by supplying indices from the first set.
524 fn unify_canonical_vars(
526 cause: &ObligationCause<'tcx>,
527 param_env: ty::ParamEnv<'tcx>,
528 variables1: &OriginalQueryValues<'tcx>,
529 variables2: impl Fn(BoundTyIndex) -> Kind<'tcx>,
530 ) -> InferResult<'tcx, ()> {
531 self.commit_if_ok(|_| {
532 let mut obligations = vec![];
533 for (index, value1) in variables1.var_values.iter().enumerate() {
534 let value2 = variables2(BoundTyIndex::new(index));
536 match (value1.unpack(), value2.unpack()) {
537 (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
539 .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
542 UnpackedKind::Lifetime(ty::ReErased),
543 UnpackedKind::Lifetime(ty::ReErased),
547 (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => {
549 .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
552 bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
564 /// Given the region obligations and constraints scraped from the infcx,
565 /// creates query region constraints.
566 pub fn make_query_outlives<'tcx>(
567 tcx: TyCtxt<'_, '_, 'tcx>,
568 outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>,
569 region_constraints: &RegionConstraintData<'tcx>,
570 ) -> Vec<QueryRegionConstraint<'tcx>> {
571 let RegionConstraintData {
575 } = region_constraints;
577 assert!(verifys.is_empty());
578 assert!(givens.is_empty());
580 let outlives: Vec<_> = constraints
582 .map(|(k, _)| match *k {
583 // Swap regions because we are going from sub (<=) to outlives
585 Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
586 tcx.mk_region(ty::ReVar(v2)).into(),
587 tcx.mk_region(ty::ReVar(v1)),
589 Constraint::VarSubReg(v1, r2) => {
590 ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
592 Constraint::RegSubVar(r1, v2) => {
593 ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
595 Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
597 .map(ty::Binder::dummy) // no bound regions in the code above
600 .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
601 .map(ty::Binder::dummy), // no bound regions in the code above