hir_ty/next_solver/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
24use crate::next_solver::{
25    ArgOutlivesPredicate, Canonical, CanonicalVarValues, Const, DbInterner, GenericArg,
26    OpaqueTypeKey, PlaceholderConst, PlaceholderRegion, PlaceholderTy, Region, Ty, TyKind,
27    infer::InferCtxt,
28};
29use instantiate::CanonicalExt;
30use macros::{TypeFoldable, TypeVisitable};
31use rustc_index::IndexVec;
32use rustc_type_ir::inherent::IntoKind;
33use rustc_type_ir::{CanonicalVarKind, InferTy, TypeFoldable, UniverseIndex, inherent::Ty as _};
34
35pub mod canonicalizer;
36pub mod instantiate;
37
38impl<'db> InferCtxt<'db> {
39    /// Creates an instantiation S for the canonical value with fresh inference
40    /// variables and placeholders then applies it to the canonical value.
41    /// Returns both the instantiated result *and* the instantiation S.
42    ///
43    /// This can be invoked as part of constructing an
44    /// inference context at the start of a query (see
45    /// `InferCtxtBuilder::build_with_canonical`). It basically
46    /// brings the canonical value "into scope" within your new infcx.
47    ///
48    /// At the end of processing, the instantiation S (once
49    /// canonicalized) then represents the values that you computed
50    /// for each of the canonical inputs to your query.
51    pub fn instantiate_canonical<T>(
52        &self,
53        canonical: &Canonical<'db, T>,
54    ) -> (T, CanonicalVarValues<'db>)
55    where
56        T: TypeFoldable<DbInterner<'db>>,
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<UniverseIndex, _> = std::iter::once(self.universe())
68            .chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
69            .collect();
70
71        let var_values = CanonicalVarValues::instantiate(
72            self.interner,
73            canonical.variables,
74            |var_values, info| self.instantiate_canonical_var(info, var_values, |ui| universes[ui]),
75        );
76        let result = canonical.instantiate(self.interner, &var_values);
77        (result, var_values)
78    }
79
80    /// Given the "info" about a canonical variable, creates a fresh
81    /// variable for it. If this is an existentially quantified
82    /// variable, then you'll get a new inference variable; if it is a
83    /// universally quantified variable, you get a placeholder.
84    ///
85    /// FIXME(-Znext-solver): This is public because it's used by the
86    /// new trait solver which has a different canonicalization routine.
87    /// We should somehow deduplicate all of this.
88    pub fn instantiate_canonical_var(
89        &self,
90        cv_info: CanonicalVarKind<DbInterner<'db>>,
91        previous_var_values: &[GenericArg<'db>],
92        universe_map: impl Fn(UniverseIndex) -> UniverseIndex,
93    ) -> GenericArg<'db> {
94        match cv_info {
95            CanonicalVarKind::Ty { ui, sub_root } => {
96                let vid = self.next_ty_var_id_in_universe(universe_map(ui));
97                // If this inference variable is related to an earlier variable
98                // via subtyping, we need to add that info to the inference context.
99                if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
100                    if let TyKind::Infer(InferTy::TyVar(sub_root)) = prev.expect_ty().kind() {
101                        self.sub_unify_ty_vids_raw(vid, sub_root);
102                    } else {
103                        unreachable!()
104                    }
105                }
106                Ty::new_var(self.interner, vid).into()
107            }
108
109            CanonicalVarKind::Int => self.next_int_var().into(),
110
111            CanonicalVarKind::Float => self.next_float_var().into(),
112
113            CanonicalVarKind::PlaceholderTy(PlaceholderTy { universe, bound }) => {
114                let universe_mapped = universe_map(universe);
115                let placeholder_mapped = PlaceholderTy { universe: universe_mapped, bound };
116                Ty::new_placeholder(self.interner, placeholder_mapped).into()
117            }
118
119            CanonicalVarKind::Region(ui) => {
120                self.next_region_var_in_universe(universe_map(ui)).into()
121            }
122
123            CanonicalVarKind::PlaceholderRegion(PlaceholderRegion { universe, bound }) => {
124                let universe_mapped = universe_map(universe);
125                let placeholder_mapped: crate::next_solver::Placeholder<
126                    crate::next_solver::BoundRegion,
127                > = PlaceholderRegion { universe: universe_mapped, bound };
128                Region::new_placeholder(self.interner, placeholder_mapped).into()
129            }
130
131            CanonicalVarKind::Const(ui) => self.next_const_var_in_universe(universe_map(ui)).into(),
132            CanonicalVarKind::PlaceholderConst(PlaceholderConst { universe, bound }) => {
133                let universe_mapped = universe_map(universe);
134                let placeholder_mapped = PlaceholderConst { universe: universe_mapped, bound };
135                Const::new_placeholder(self.interner, placeholder_mapped).into()
136            }
137        }
138    }
139}
140
141/// After we execute a query with a canonicalized key, we get back a
142/// `Canonical<QueryResponse<..>>`. You can use
143/// `instantiate_query_result` to access the data in this result.
144#[derive(Clone, Debug, TypeVisitable, TypeFoldable)]
145pub struct QueryResponse<'db, R> {
146    pub var_values: CanonicalVarValues<'db>,
147    pub region_constraints: QueryRegionConstraints<'db>,
148    pub opaque_types: Vec<(OpaqueTypeKey<'db>, Ty<'db>)>,
149    pub value: R,
150}
151
152#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
153pub struct QueryRegionConstraints<'db> {
154    pub outlives: Vec<QueryOutlivesConstraint<'db>>,
155    pub assumptions: Vec<ArgOutlivesPredicate<'db>>,
156}
157
158pub type QueryOutlivesConstraint<'tcx> = ArgOutlivesPredicate<'tcx>;