rustc_infer/infer/canonical/
mod.rs

1//! **Canonicalization** is the key to constructing a query in the
2//! middle of type inference. Ordinarily, it is not possible to store
3//! types from type inference in query keys, because they contain
4//! references to inference variables whose lifetimes are too short
5//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
6//! produces two things:
7//!
8//! - a value T2 where each unbound inference variable has been
9//!   replaced with a **canonical variable**;
10//! - a map M (of type `CanonicalVarValues`) from those canonical
11//!   variables back to the original.
12//!
13//! We can then do queries using T2. These will give back constraints
14//! on the canonical variables which can be translated, using the map
15//! M, into constraints in our source context. This process of
16//! translating the results back is done by the
17//! `instantiate_query_result` method.
18//!
19//! For a more detailed look at what is happening here, check
20//! out the [chapter in the rustc dev guide][c].
21//!
22//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
23
24pub use instantiate::CanonicalExt;
25use rustc_index::IndexVec;
26pub use rustc_middle::infer::canonical::*;
27use rustc_middle::ty::fold::TypeFoldable;
28use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt};
29use rustc_span::Span;
30
31use crate::infer::{InferCtxt, RegionVariableOrigin};
32
33mod canonicalizer;
34mod instantiate;
35pub mod query_response;
36
37impl<'tcx> InferCtxt<'tcx> {
38    /// Creates an instantiation S for the canonical value with fresh inference
39    /// variables and placeholders then applies it to the canonical value.
40    /// Returns both the instantiated result *and* the instantiation S.
41    ///
42    /// This can be invoked as part of constructing an
43    /// inference context at the start of a query (see
44    /// `InferCtxtBuilder::build_with_canonical`). It basically
45    /// brings the canonical value "into scope" within your new infcx.
46    ///
47    /// At the end of processing, the instantiation S (once
48    /// canonicalized) then represents the values that you computed
49    /// for each of the canonical inputs to your query.
50    pub fn instantiate_canonical<T>(
51        &self,
52        span: Span,
53        canonical: &Canonical<'tcx, T>,
54    ) -> (T, CanonicalVarValues<'tcx>)
55    where
56        T: TypeFoldable<TyCtxt<'tcx>>,
57    {
58        // For each universe that is referred to in the incoming
59        // query, create a universe in our local inference context. In
60        // practice, as of this writing, all queries have no universes
61        // in them, so this code has no effect, but it is looking
62        // forward to the day when we *do* want to carry universes
63        // through into queries.
64        //
65        // Instantiate the root-universe content into the current universe,
66        // and create fresh universes for the higher universes.
67        let universes: IndexVec<ty::UniverseIndex, _> = std::iter::once(self.universe())
68            .chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
69            .collect();
70
71        let canonical_inference_vars =
72            self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
73        let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
74        (result, canonical_inference_vars)
75    }
76
77    /// Given the "infos" about the canonical variables from some
78    /// canonical, creates fresh variables with the same
79    /// characteristics (see `instantiate_canonical_var` for
80    /// details). You can then use `instantiate` to instantiate the
81    /// canonical variable with these inference variables.
82    fn instantiate_canonical_vars(
83        &self,
84        span: Span,
85        variables: &List<CanonicalVarInfo<'tcx>>,
86        universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
87    ) -> CanonicalVarValues<'tcx> {
88        CanonicalVarValues {
89            var_values: self.tcx.mk_args_from_iter(
90                variables
91                    .iter()
92                    .map(|info| self.instantiate_canonical_var(span, info, &universe_map)),
93            ),
94        }
95    }
96
97    /// Given the "info" about a canonical variable, creates a fresh
98    /// variable for it. If this is an existentially quantified
99    /// variable, then you'll get a new inference variable; if it is a
100    /// universally quantified variable, you get a placeholder.
101    ///
102    /// FIXME(-Znext-solver): This is public because it's used by the
103    /// new trait solver which has a different canonicalization routine.
104    /// We should somehow deduplicate all of this.
105    pub fn instantiate_canonical_var(
106        &self,
107        span: Span,
108        cv_info: CanonicalVarInfo<'tcx>,
109        universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
110    ) -> GenericArg<'tcx> {
111        match cv_info.kind {
112            CanonicalVarKind::Ty(ty_kind) => {
113                let ty = match ty_kind {
114                    CanonicalTyVarKind::General(ui) => {
115                        self.next_ty_var_in_universe(span, universe_map(ui))
116                    }
117
118                    CanonicalTyVarKind::Int => self.next_int_var(),
119
120                    CanonicalTyVarKind::Float => self.next_float_var(),
121                };
122                ty.into()
123            }
124
125            CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
126                let universe_mapped = universe_map(universe);
127                let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound };
128                Ty::new_placeholder(self.tcx, placeholder_mapped).into()
129            }
130
131            CanonicalVarKind::Region(ui) => self
132                .next_region_var_in_universe(
133                    RegionVariableOrigin::MiscVariable(span),
134                    universe_map(ui),
135                )
136                .into(),
137
138            CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => {
139                let universe_mapped = universe_map(universe);
140                let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound };
141                ty::Region::new_placeholder(self.tcx, placeholder_mapped).into()
142            }
143
144            CanonicalVarKind::Const(ui) => {
145                self.next_const_var_in_universe(span, universe_map(ui)).into()
146            }
147            CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => {
148                let universe_mapped = universe_map(universe);
149                let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
150                ty::Const::new_placeholder(self.tcx, placeholder_mapped).into()
151            }
152        }
153    }
154}