summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/infer/canonical.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/infer/canonical.rs')
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs363
1 files changed, 363 insertions, 0 deletions
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
new file mode 100644
index 000000000..200de9079
--- /dev/null
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -0,0 +1,363 @@
+//! **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::ty::subst::GenericArg;
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
+use rustc_index::vec::IndexVec;
+use rustc_macros::HashStable;
+use smallvec::SmallVec;
+use std::iter;
+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 max_universe: ty::UniverseIndex,
+ pub variables: CanonicalVarInfos<'tcx>,
+ pub value: V,
+}
+
+pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
+
+/// 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(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct CanonicalVarValues<'tcx> {
+ pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
+}
+
+/// 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)]
+pub struct CanonicalVarInfo<'tcx> {
+ pub kind: CanonicalVarKind<'tcx>,
+}
+
+impl<'tcx> CanonicalVarInfo<'tcx> {
+ pub fn universe(&self) -> ty::UniverseIndex {
+ self.kind.universe()
+ }
+
+ 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,
+ }
+ }
+}
+
+/// 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)]
+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,
+ }
+ }
+}
+
+/// 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<QueryResponse<..>>`. 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<'tcx>, Ty<'tcx>)>,
+ pub value: R,
+}
+
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct QueryRegionConstraints<'tcx> {
+ pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
+ pub member_constraints: Vec<MemberConstraint<'tcx>>,
+}
+
+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 Canonicalized<'tcx, V> = Canonical<'tcx, V>;
+
+pub type CanonicalizedQueryResponse<'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, R> Canonical<'tcx, ty::ParamEnvAnd<'tcx, R>> {
+ #[inline]
+ pub fn without_const(mut self) -> Self {
+ self.value = self.value.without_const();
+ self
+ }
+}
+
+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<W>(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) }
+ }
+}
+
+pub type QueryOutlivesConstraint<'tcx> =
+ ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
+
+TrivialTypeTraversalAndLiftImpls! {
+ for <'tcx> {
+ crate::infer::canonical::Certainty,
+ crate::infer::canonical::CanonicalVarInfo<'tcx>,
+ crate::infer::canonical::CanonicalVarKind<'tcx>,
+ }
+}
+
+TrivialTypeTraversalImpls! {
+ for <'tcx> {
+ crate::infer::canonical::CanonicalVarInfos<'tcx>,
+ }
+}
+
+impl<'tcx> CanonicalVarValues<'tcx> {
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.var_values.len()
+ }
+
+ /// Makes an identity substitution from this one: each bound var
+ /// is matched to the same bound var, preserving the original kinds.
+ /// For example, if we have:
+ /// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
+ /// we'll return a substitution `subst` with:
+ /// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
+ pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
+ use crate::ty::subst::GenericArgKind;
+
+ CanonicalVarValues {
+ var_values: iter::zip(&self.var_values, 0..)
+ .map(|(kind, i)| match kind.unpack() {
+ GenericArgKind::Type(..) => {
+ tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
+ }
+ GenericArgKind::Lifetime(..) => {
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
+ tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
+ }
+ GenericArgKind::Const(ct) => tcx
+ .mk_const(ty::ConstS {
+ ty: ct.ty(),
+ kind: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
+ })
+ .into(),
+ })
+ .collect(),
+ }
+ }
+}
+
+impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
+ type Item = GenericArg<'tcx>;
+ type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.var_values.iter().cloned()
+ }
+}
+
+impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
+ type Output = GenericArg<'tcx>;
+
+ fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
+ &self.var_values[value]
+ }
+}