//! **Canonicalization** is the key to constructing a query in the //! middle of type inference. Ordinarily, it is not possible to store //! types from type inference in query keys, because they contain //! references to inference variables whose lifetimes are too short //! and so forth. Canonicalizing a value T1 using `canonicalize_query` //! produces two things: //! //! - a value T2 where each unbound inference variable has been //! replaced with a **canonical variable**; //! - a map M (of type `CanonicalVarValues`) from those canonical //! variables back to the original. //! //! We can then do queries using T2. These will give back constraints //! on the canonical variables which can be translated, using the map //! M, into constraints in our source context. This process of //! translating the results back is done by the //! `instantiate_query_result` method. //! //! For a more detailed look at what is happening here, check //! out the [chapter in the rustc dev guide][c]. //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use crate::infer::MemberConstraint; use crate::mir::ConstraintCategory; use crate::ty::GenericArg; use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; use rustc_macros::HashStable; use smallvec::SmallVec; use std::ops::Index; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct Canonical<'tcx, V> { pub value: V, pub max_universe: ty::UniverseIndex, pub variables: CanonicalVarInfos<'tcx>, } pub type CanonicalVarInfos<'tcx> = &'tcx List>; impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { fn try_fold_with>>( self, folder: &mut F, ) -> Result { ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v)) } } /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to /// `canonical_value.substitute` to substitute them into the canonical /// value at the right places. /// /// When you canonicalize a value `V`, you get back one of these /// vectors with the original values that were replaced by canonical /// variables. You will need to supply it later to instantiate the /// canonicalized query response. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalVarValues<'tcx> { pub var_values: ty::GenericArgsRef<'tcx>, } impl CanonicalVarValues<'_> { pub fn is_identity(&self) -> bool { self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() { ty::GenericArgKind::Lifetime(r) => { matches!(*r, ty::ReLateBound(ty::INNERMOST, br) if br.var.as_usize() == bv) } ty::GenericArgKind::Type(ty) => { matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv) } ty::GenericArgKind::Const(ct) => { matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv) } }) } pub fn is_identity_modulo_regions(&self) -> bool { let mut var = ty::BoundVar::from_u32(0); for arg in self.var_values { match arg.unpack() { ty::GenericArgKind::Lifetime(r) => { if let ty::ReLateBound(ty::INNERMOST, br) = *r && var == br.var { var = var + 1; } else { // It's ok if this region var isn't unique } }, ty::GenericArgKind::Type(ty) => { if let ty::Bound(ty::INNERMOST, bt) = *ty.kind() && var == bt.var { var = var + 1; } else { return false; } } ty::GenericArgKind::Const(ct) => { if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind() && var == bc { var = var + 1; } else { return false; } } } } true } } /// When we canonicalize a value to form a query, we wind up replacing /// various parts of it with canonical variables. This struct stores /// those replaced bits to remember for when we process the query /// result. #[derive(Clone, Debug)] pub struct OriginalQueryValues<'tcx> { /// Map from the universes that appear in the query to the universes in the /// caller context. For all queries except `evaluate_goal` (used by Chalk), /// we only ever put ROOT values into the query, so this map is very /// simple. pub universe_map: SmallVec<[ty::UniverseIndex; 4]>, /// This is equivalent to `CanonicalVarValues`, but using a /// `SmallVec` yields a significant performance win. pub var_values: SmallVec<[GenericArg<'tcx>; 8]>, } impl<'tcx> Default for OriginalQueryValues<'tcx> { fn default() -> Self { let mut universe_map = SmallVec::default(); universe_map.push(ty::UniverseIndex::ROOT); Self { universe_map, var_values: SmallVec::default() } } } /// Information about a canonical variable that is included with the /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub struct CanonicalVarInfo<'tcx> { pub kind: CanonicalVarKind<'tcx>, } impl<'tcx> CanonicalVarInfo<'tcx> { pub fn universe(&self) -> ty::UniverseIndex { self.kind.universe() } #[must_use] pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarInfo<'tcx> { CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) } } pub fn is_existential(&self) -> bool { match self.kind { CanonicalVarKind::Ty(_) => true, CanonicalVarKind::PlaceholderTy(_) => false, CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, CanonicalVarKind::Const(..) => true, CanonicalVarKind::PlaceholderConst(_, _) => false, } } pub fn is_region(&self) -> bool { match self.kind { CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) | CanonicalVarKind::Const(_, _) | CanonicalVarKind::PlaceholderConst(_, _) => false, } } pub fn expect_placeholder_index(self) -> usize { match self.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"), CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.bound.var.as_usize(), CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.bound.var.as_usize(), CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.bound.as_usize(), } } } /// Describes the "kind" of the canonical variable. This is a "kind" /// in the type-theory sense of the term -- i.e., a "meta" type system /// that analyzes type-like values. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub enum CanonicalVarKind<'tcx> { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), /// A "placeholder" that represents "any type". PlaceholderTy(ty::PlaceholderType), /// Region variable `'?R`. Region(ty::UniverseIndex), /// A "placeholder" that represents "any region". Created when you /// are solving a goal like `for<'a> T: Foo<'a>` to represent the /// bound region `'a`. PlaceholderRegion(ty::PlaceholderRegion), /// Some kind of const inference variable. Const(ty::UniverseIndex, Ty<'tcx>), /// A "placeholder" that represents "any const". PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>), } impl<'tcx> CanonicalVarKind<'tcx> { pub fn universe(self) -> ty::UniverseIndex { match self { CanonicalVarKind::Ty(kind) => match kind { CanonicalTyVarKind::General(ui) => ui, CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT, }, CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe, CanonicalVarKind::Region(ui) => ui, CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe, CanonicalVarKind::Const(ui, _) => ui, CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe, } } /// Replaces the universe of this canonical variable with `ui`. /// /// In case this is a float or int variable, this causes an ICE if /// the updated universe is not the root. pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> { match self { CanonicalVarKind::Ty(kind) => match kind { CanonicalTyVarKind::General(_) => { CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) } CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => { assert_eq!(ui, ty::UniverseIndex::ROOT); CanonicalVarKind::Ty(kind) } }, CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder }) } CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), CanonicalVarKind::PlaceholderRegion(placeholder) => { CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe: ui, ..placeholder }) } CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), CanonicalVarKind::PlaceholderConst(placeholder, ty) => { CanonicalVarKind::PlaceholderConst( ty::Placeholder { universe: ui, ..placeholder }, ty, ) } } } } /// Rust actually has more than one category of type variables; /// notably, the type variables we create for literals (e.g., 22 or /// 22.) can only be instantiated with integral/float types (e.g., /// usize or f32). In order to faithfully reproduce a type, we need to /// know what set of types a given type variable can be unified with. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable, HashStable)] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. General(ty::UniverseIndex), /// Integral type variable `?I` (that can only be unified with integral types). Int, /// Floating-point type variable `?F` (that can only be unified with float types). Float, } /// After we execute a query with a canonicalized key, we get back a /// `Canonical>`. You can use /// `instantiate_query_result` to access the data in this result. #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>, pub certainty: Certainty, /// List of opaque types which we tried to compare to another type. /// Inside the query we don't know yet whether the opaque type actually /// should get its hidden type inferred. So we bubble the opaque type /// and the type it was compared against upwards and let the query caller /// handle it. pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, pub value: R, } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, pub member_constraints: Vec>, } impl QueryRegionConstraints<'_> { /// Represents an empty (trivially true) set of region /// constraints. pub fn is_empty(&self) -> bool { self.outlives.is_empty() && self.member_constraints.is_empty() } } pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>; /// Indicates whether or not we were able to prove the query to be /// true. #[derive(Copy, Clone, Debug, HashStable)] pub enum Certainty { /// The query is known to be true, presuming that you apply the /// given `var_values` and the region-constraints are satisfied. Proven, /// The query is not known to be true, but also not known to be /// false. The `var_values` represent *either* values that must /// hold in order for the query to be true, or helpful tips that /// *might* make it true. Currently rustc's trait solver cannot /// distinguish the two (e.g., due to our preference for where /// clauses over impls). /// /// After some unification and things have been done, it makes /// sense to try and prove again -- of course, at that point, the /// canonical form will be different, making this a distinct /// query. Ambiguous, } impl Certainty { pub fn is_proven(&self) -> bool { match self { Certainty::Proven => true, Certainty::Ambiguous => false, } } } impl<'tcx, R> QueryResponse<'tcx, R> { pub fn is_proven(&self) -> bool { self.certainty.is_proven() } } impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { pub fn is_proven(&self) -> bool { self.value.is_proven() } pub fn is_ambiguous(&self) -> bool { !self.is_proven() } } impl<'tcx, V> Canonical<'tcx, V> { /// Allows you to map the `value` of a canonical while keeping the /// same set of bound variables. /// /// **WARNING:** This function is very easy to mis-use, hence the /// name! In particular, the new value `W` must use all **the /// same type/region variables** in **precisely the same order** /// as the original! (The ordering is defined by the /// `TypeFoldable` implementation of the type in question.) /// /// An example of a **correct** use of this: /// /// ```rust,ignore (not real code) /// let a: Canonical<'_, T> = ...; /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); /// ``` /// /// An example of an **incorrect** use of this: /// /// ```rust,ignore (not real code) /// let a: Canonical<'tcx, T> = ...; /// let ty: Ty<'tcx> = ...; /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); /// ``` pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> { let Canonical { max_universe, variables, value } = self; Canonical { max_universe, variables, value: map_op(value) } } /// Allows you to map the `value` of a canonical while keeping the same set of /// bound variables. /// /// **WARNING:** This function is very easy to mis-use, hence the name! See /// the comment of [Canonical::unchecked_map] for more details. pub fn unchecked_rebind(self, value: W) -> Canonical<'tcx, W> { let Canonical { max_universe, variables, value: _ } = self; Canonical { max_universe, variables, value } } } pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate, Region<'tcx>>, ConstraintCategory<'tcx>); TrivialTypeTraversalAndLiftImpls! { crate::infer::canonical::Certainty, crate::infer::canonical::CanonicalTyVarKind, } impl<'tcx> CanonicalVarValues<'tcx> { // Given a list of canonical variables, construct a set of values which are // the identity response. pub fn make_identity( tcx: TyCtxt<'tcx>, infos: CanonicalVarInfos<'tcx>, ) -> CanonicalVarValues<'tcx> { CanonicalVarValues { var_values: tcx.mk_args_from_iter(infos.iter().enumerate().map( |(i, info)| -> ty::GenericArg<'tcx> { match info.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into()) .into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { let br = ty::BoundRegion { var: ty::BoundVar::from_usize(i), kind: ty::BrAnon(None), }; ty::Region::new_late_bound(tcx, ty::INNERMOST, br).into() } CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound( tcx, ty::INNERMOST, ty::BoundVar::from_usize(i), ty, ) .into(), } }, )), } } /// Creates dummy var values which should not be used in a /// canonical response. pub fn dummy() -> CanonicalVarValues<'tcx> { CanonicalVarValues { var_values: ty::List::empty() } } #[inline] pub fn len(&self) -> usize { self.var_values.len() } } impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { type Item = GenericArg<'tcx>; type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>; fn into_iter(self) -> Self::IntoIter { self.var_values.iter() } } impl<'tcx> Index for CanonicalVarValues<'tcx> { type Output = GenericArg<'tcx>; fn index(&self, value: BoundVar) -> &GenericArg<'tcx> { &self.var_values[value.as_usize()] } }