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:
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.
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.
19 //! For a more detailed look at what is happening here, check
20 //! out the [chapter in the rustc dev guide][c].
22 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
24 use rustc_data_structures
::fx
::FxHashMap
;
25 use rustc_data_structures
::sync
::Lock
;
26 use rustc_macros
::HashStable
;
27 use rustc_type_ir
::Canonical
as IrCanonical
;
28 use rustc_type_ir
::CanonicalVarInfo
as IrCanonicalVarInfo
;
29 pub use rustc_type_ir
::{CanonicalTyVarKind, CanonicalVarKind}
;
30 use smallvec
::SmallVec
;
31 use std
::collections
::hash_map
::Entry
;
34 use crate::infer
::MemberConstraint
;
35 use crate::mir
::ConstraintCategory
;
36 use crate::ty
::GenericArg
;
37 use crate::ty
::{self, BoundVar, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt}
;
39 pub type Canonical
<'tcx
, V
> = IrCanonical
<TyCtxt
<'tcx
>, V
>;
41 pub type CanonicalVarInfo
<'tcx
> = IrCanonicalVarInfo
<TyCtxt
<'tcx
>>;
43 pub type CanonicalVarInfos
<'tcx
> = &'tcx List
<CanonicalVarInfo
<'tcx
>>;
45 impl<'tcx
> ty
::TypeFoldable
<TyCtxt
<'tcx
>> for CanonicalVarInfos
<'tcx
> {
46 fn try_fold_with
<F
: ty
::FallibleTypeFolder
<TyCtxt
<'tcx
>>>(
49 ) -> Result
<Self, F
::Error
> {
50 ty
::util
::fold_list(self, folder
, |tcx
, v
| tcx
.mk_canonical_var_infos(v
))
54 /// A set of values corresponding to the canonical variables from some
55 /// `Canonical`. You can give these values to
56 /// `canonical_value.substitute` to substitute them into the canonical
57 /// value at the right places.
59 /// When you canonicalize a value `V`, you get back one of these
60 /// vectors with the original values that were replaced by canonical
61 /// variables. You will need to supply it later to instantiate the
62 /// canonicalized query response.
63 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
64 #[derive(HashStable, TypeFoldable, TypeVisitable)]
65 pub struct CanonicalVarValues
<'tcx
> {
66 pub var_values
: ty
::GenericArgsRef
<'tcx
>,
69 impl CanonicalVarValues
<'_
> {
70 pub fn is_identity(&self) -> bool
{
71 self.var_values
.iter().enumerate().all(|(bv
, arg
)| match arg
.unpack() {
72 ty
::GenericArgKind
::Lifetime(r
) => {
73 matches
!(*r
, ty
::ReBound(ty
::INNERMOST
, br
) if br
.var
.as_usize() == bv
)
75 ty
::GenericArgKind
::Type(ty
) => {
76 matches
!(*ty
.kind(), ty
::Bound(ty
::INNERMOST
, bt
) if bt
.var
.as_usize() == bv
)
78 ty
::GenericArgKind
::Const(ct
) => {
79 matches
!(ct
.kind(), ty
::ConstKind
::Bound(ty
::INNERMOST
, bc
) if bc
.as_usize() == bv
)
84 pub fn is_identity_modulo_regions(&self) -> bool
{
85 let mut var
= ty
::BoundVar
::from_u32(0);
86 for arg
in self.var_values
{
88 ty
::GenericArgKind
::Lifetime(r
) => {
89 if let ty
::ReBound(ty
::INNERMOST
, br
) = *r
94 // It's ok if this region var isn't unique
97 ty
::GenericArgKind
::Type(ty
) => {
98 if let ty
::Bound(ty
::INNERMOST
, bt
) = *ty
.kind()
106 ty
::GenericArgKind
::Const(ct
) => {
107 if let ty
::ConstKind
::Bound(ty
::INNERMOST
, bc
) = ct
.kind()
122 /// When we canonicalize a value to form a query, we wind up replacing
123 /// various parts of it with canonical variables. This struct stores
124 /// those replaced bits to remember for when we process the query
126 #[derive(Clone, Debug)]
127 pub struct OriginalQueryValues
<'tcx
> {
128 /// Map from the universes that appear in the query to the universes in the
129 /// caller context. For all queries except `evaluate_goal` (used by Chalk),
130 /// we only ever put ROOT values into the query, so this map is very
132 pub universe_map
: SmallVec
<[ty
::UniverseIndex
; 4]>,
134 /// This is equivalent to `CanonicalVarValues`, but using a
135 /// `SmallVec` yields a significant performance win.
136 pub var_values
: SmallVec
<[GenericArg
<'tcx
>; 8]>,
139 impl<'tcx
> Default
for OriginalQueryValues
<'tcx
> {
140 fn default() -> Self {
141 let mut universe_map
= SmallVec
::default();
142 universe_map
.push(ty
::UniverseIndex
::ROOT
);
144 Self { universe_map, var_values: SmallVec::default() }
148 /// After we execute a query with a canonicalized key, we get back a
149 /// `Canonical<QueryResponse<..>>`. You can use
150 /// `instantiate_query_result` to access the data in this result.
151 #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
152 pub struct QueryResponse
<'tcx
, R
> {
153 pub var_values
: CanonicalVarValues
<'tcx
>,
154 pub region_constraints
: QueryRegionConstraints
<'tcx
>,
155 pub certainty
: Certainty
,
156 /// List of opaque types which we tried to compare to another type.
157 /// Inside the query we don't know yet whether the opaque type actually
158 /// should get its hidden type inferred. So we bubble the opaque type
159 /// and the type it was compared against upwards and let the query caller
161 pub opaque_types
: Vec
<(ty
::OpaqueTypeKey
<'tcx
>, Ty
<'tcx
>)>,
165 #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
166 #[derive(HashStable, TypeFoldable, TypeVisitable)]
167 pub struct QueryRegionConstraints
<'tcx
> {
168 pub outlives
: Vec
<QueryOutlivesConstraint
<'tcx
>>,
169 pub member_constraints
: Vec
<MemberConstraint
<'tcx
>>,
172 impl QueryRegionConstraints
<'_
> {
173 /// Represents an empty (trivially true) set of region
175 pub fn is_empty(&self) -> bool
{
176 self.outlives
.is_empty() && self.member_constraints
.is_empty()
180 pub type CanonicalQueryResponse
<'tcx
, T
> = &'tcx Canonical
<'tcx
, QueryResponse
<'tcx
, T
>>;
182 /// Indicates whether or not we were able to prove the query to be
184 #[derive(Copy, Clone, Debug, HashStable)]
186 /// The query is known to be true, presuming that you apply the
187 /// given `var_values` and the region-constraints are satisfied.
190 /// The query is not known to be true, but also not known to be
191 /// false. The `var_values` represent *either* values that must
192 /// hold in order for the query to be true, or helpful tips that
193 /// *might* make it true. Currently rustc's trait solver cannot
194 /// distinguish the two (e.g., due to our preference for where
195 /// clauses over impls).
197 /// After some unification and things have been done, it makes
198 /// sense to try and prove again -- of course, at that point, the
199 /// canonical form will be different, making this a distinct
205 pub fn is_proven(&self) -> bool
{
207 Certainty
::Proven
=> true,
208 Certainty
::Ambiguous
=> false,
213 impl<'tcx
, R
> QueryResponse
<'tcx
, R
> {
214 pub fn is_proven(&self) -> bool
{
215 self.certainty
.is_proven()
219 pub type QueryOutlivesConstraint
<'tcx
> =
220 (ty
::OutlivesPredicate
<GenericArg
<'tcx
>, Region
<'tcx
>>, ConstraintCategory
<'tcx
>);
222 TrivialTypeTraversalImpls
! {
223 crate::infer
::canonical
::Certainty
,
226 impl<'tcx
> CanonicalVarValues
<'tcx
> {
227 // Given a list of canonical variables, construct a set of values which are
228 // the identity response.
229 pub fn make_identity(
231 infos
: CanonicalVarInfos
<'tcx
>,
232 ) -> CanonicalVarValues
<'tcx
> {
234 var_values
: tcx
.mk_args_from_iter(infos
.iter().enumerate().map(
235 |(i
, info
)| -> ty
::GenericArg
<'tcx
> {
237 CanonicalVarKind
::Ty(_
) | CanonicalVarKind
::PlaceholderTy(_
) => {
238 Ty
::new_bound(tcx
, ty
::INNERMOST
, ty
::BoundVar
::from_usize(i
).into())
241 CanonicalVarKind
::Region(_
) | CanonicalVarKind
::PlaceholderRegion(_
) => {
242 let br
= ty
::BoundRegion
{
243 var
: ty
::BoundVar
::from_usize(i
),
246 ty
::Region
::new_bound(tcx
, ty
::INNERMOST
, br
).into()
248 CanonicalVarKind
::Effect
=> ty
::Const
::new_bound(
251 ty
::BoundVar
::from_usize(i
),
255 CanonicalVarKind
::Const(_
, ty
)
256 | CanonicalVarKind
::PlaceholderConst(_
, ty
) => ty
::Const
::new_bound(
259 ty
::BoundVar
::from_usize(i
),
269 /// Creates dummy var values which should not be used in a
270 /// canonical response.
271 pub fn dummy() -> CanonicalVarValues
<'tcx
> {
272 CanonicalVarValues { var_values: ty::List::empty() }
276 pub fn len(&self) -> usize {
277 self.var_values
.len()
281 impl<'a
, 'tcx
> IntoIterator
for &'a CanonicalVarValues
<'tcx
> {
282 type Item
= GenericArg
<'tcx
>;
283 type IntoIter
= ::std
::iter
::Copied
<::std
::slice
::Iter
<'a
, GenericArg
<'tcx
>>>;
285 fn into_iter(self) -> Self::IntoIter
{
286 self.var_values
.iter()
290 impl<'tcx
> Index
<BoundVar
> for CanonicalVarValues
<'tcx
> {
291 type Output
= GenericArg
<'tcx
>;
293 fn index(&self, value
: BoundVar
) -> &GenericArg
<'tcx
> {
294 &self.var_values
[value
.as_usize()]
299 pub struct CanonicalParamEnvCache
<'tcx
> {
303 (Canonical
<'tcx
, ty
::ParamEnv
<'tcx
>>, &'tcx
[GenericArg
<'tcx
>]),
308 impl<'tcx
> CanonicalParamEnvCache
<'tcx
> {
309 /// Gets the cached canonical form of `key` or executes
310 /// `canonicalize_op` and caches the result if not present.
312 /// `canonicalize_op` is intentionally not allowed to be a closure to
313 /// statically prevent it from capturing `InferCtxt` and resolving
314 /// inference variables, which invalidates the cache.
315 pub fn get_or_insert(
318 key
: ty
::ParamEnv
<'tcx
>,
319 state
: &mut OriginalQueryValues
<'tcx
>,
323 &mut OriginalQueryValues
<'tcx
>,
324 ) -> Canonical
<'tcx
, ty
::ParamEnv
<'tcx
>>,
325 ) -> Canonical
<'tcx
, ty
::ParamEnv
<'tcx
>> {
326 if !key
.has_type_flags(
327 TypeFlags
::HAS_INFER
| TypeFlags
::HAS_PLACEHOLDER
| TypeFlags
::HAS_FREE_REGIONS
,
330 max_universe
: ty
::UniverseIndex
::ROOT
,
331 variables
: List
::empty(),
336 assert_eq
!(state
.var_values
.len(), 0);
337 assert_eq
!(state
.universe_map
.len(), 1);
338 debug_assert_eq
!(&*state
.universe_map
, &[ty
::UniverseIndex
::ROOT
]);
340 match self.map
.borrow().entry(key
) {
341 Entry
::Occupied(e
) => {
342 let (canonical
, var_values
) = e
.get();
343 state
.var_values
.extend_from_slice(var_values
);
346 Entry
::Vacant(e
) => {
347 let canonical
= canonicalize_op(tcx
, key
, state
);
348 let OriginalQueryValues { var_values, universe_map }
= state
;
349 assert_eq
!(universe_map
.len(), 1);
350 e
.insert((canonical
, tcx
.arena
.alloc_slice(var_values
)));