|
| 1 | +use std::fmt; |
| 2 | +use std::hash; |
| 3 | +use std::ops::ControlFlow; |
| 4 | + |
| 5 | +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
| 6 | +use rustc_serialize::{Decodable, Encodable}; |
| 7 | + |
| 8 | +use crate::fold::{FallibleTypeFolder, TypeFoldable}; |
| 9 | +use crate::visit::{TypeVisitable, TypeVisitor}; |
| 10 | +use crate::TyDecoder; |
| 11 | +use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex}; |
| 12 | + |
| 13 | +/// A "canonicalized" type `V` is one where all free inference |
| 14 | +/// variables have been rewritten to "canonical vars". These are |
| 15 | +/// numbered starting from 0 in order of first appearance. |
| 16 | +pub struct Canonical<I: Interner, V> { |
| 17 | + pub value: V, |
| 18 | + pub max_universe: UniverseIndex, |
| 19 | + pub variables: I::CanonicalVars, |
| 20 | +} |
| 21 | + |
| 22 | +impl<I: Interner, V> Canonical<I, V> { |
| 23 | + /// Allows you to map the `value` of a canonical while keeping the |
| 24 | + /// same set of bound variables. |
| 25 | + /// |
| 26 | + /// **WARNING:** This function is very easy to mis-use, hence the |
| 27 | + /// name! In particular, the new value `W` must use all **the |
| 28 | + /// same type/region variables** in **precisely the same order** |
| 29 | + /// as the original! (The ordering is defined by the |
| 30 | + /// `TypeFoldable` implementation of the type in question.) |
| 31 | + /// |
| 32 | + /// An example of a **correct** use of this: |
| 33 | + /// |
| 34 | + /// ```rust,ignore (not real code) |
| 35 | + /// let a: Canonical<I, T> = ...; |
| 36 | + /// let b: Canonical<I, (T,)> = a.unchecked_map(|v| (v, )); |
| 37 | + /// ``` |
| 38 | + /// |
| 39 | + /// An example of an **incorrect** use of this: |
| 40 | + /// |
| 41 | + /// ```rust,ignore (not real code) |
| 42 | + /// let a: Canonical<I, T> = ...; |
| 43 | + /// let ty: Ty<I> = ...; |
| 44 | + /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty)); |
| 45 | + /// ``` |
| 46 | + pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> { |
| 47 | + let Canonical { max_universe, variables, value } = self; |
| 48 | + Canonical { max_universe, variables, value: map_op(value) } |
| 49 | + } |
| 50 | + |
| 51 | + /// Allows you to map the `value` of a canonical while keeping the same set of |
| 52 | + /// bound variables. |
| 53 | + /// |
| 54 | + /// **WARNING:** This function is very easy to mis-use, hence the name! See |
| 55 | + /// the comment of [Canonical::unchecked_map] for more details. |
| 56 | + pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> { |
| 57 | + let Canonical { max_universe, variables, value: _ } = self; |
| 58 | + Canonical { max_universe, variables, value } |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +impl<I: Interner, V: hash::Hash> hash::Hash for Canonical<I, V> { |
| 63 | + fn hash<H: hash::Hasher>(&self, state: &mut H) { |
| 64 | + self.value.hash(state); |
| 65 | + self.max_universe.hash(state); |
| 66 | + self.variables.hash(state); |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V> |
| 71 | +where |
| 72 | + I::CanonicalVars: HashStable<CTX>, |
| 73 | +{ |
| 74 | + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { |
| 75 | + self.value.hash_stable(hcx, hasher); |
| 76 | + self.max_universe.hash_stable(hcx, hasher); |
| 77 | + self.variables.hash_stable(hcx, hasher); |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +impl<I: Interner, V: Eq> Eq for Canonical<I, V> {} |
| 82 | + |
| 83 | +impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> { |
| 84 | + fn eq(&self, other: &Self) -> bool { |
| 85 | + self.value == other.value |
| 86 | + && self.max_universe == other.max_universe |
| 87 | + && self.variables == other.variables |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> { |
| 92 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 93 | + write!( |
| 94 | + f, |
| 95 | + "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", |
| 96 | + self.value, self.max_universe, self.variables |
| 97 | + ) |
| 98 | + } |
| 99 | +} |
| 100 | + |
| 101 | +impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> { |
| 102 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 103 | + f.debug_struct("Canonical") |
| 104 | + .field("value", &self.value) |
| 105 | + .field("max_universe", &self.max_universe) |
| 106 | + .field("variables", &self.variables) |
| 107 | + .finish() |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +impl<I: Interner, V: Clone> Clone for Canonical<I, V> { |
| 112 | + fn clone(&self) -> Self { |
| 113 | + Canonical { |
| 114 | + value: self.value.clone(), |
| 115 | + max_universe: self.max_universe.clone(), |
| 116 | + variables: self.variables.clone(), |
| 117 | + } |
| 118 | + } |
| 119 | +} |
| 120 | + |
| 121 | +impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {} |
| 122 | + |
| 123 | +impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V> |
| 124 | +where |
| 125 | + I::CanonicalVars: TypeFoldable<I>, |
| 126 | +{ |
| 127 | + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { |
| 128 | + Ok(Canonical { |
| 129 | + value: self.value.try_fold_with(folder)?, |
| 130 | + max_universe: self.max_universe.try_fold_with(folder)?, |
| 131 | + variables: self.variables.try_fold_with(folder)?, |
| 132 | + }) |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V> |
| 137 | +where |
| 138 | + I::CanonicalVars: TypeVisitable<I>, |
| 139 | +{ |
| 140 | + fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> ControlFlow<F::BreakTy> { |
| 141 | + self.value.visit_with(folder)?; |
| 142 | + self.max_universe.visit_with(folder)?; |
| 143 | + self.variables.visit_with(folder) |
| 144 | + } |
| 145 | +} |
| 146 | + |
| 147 | +impl<I: Interner, E: TyEncoder<I = I>, V: Encodable<E>> Encodable<E> for Canonical<I, V> |
| 148 | +where |
| 149 | + I::CanonicalVars: Encodable<E>, |
| 150 | +{ |
| 151 | + fn encode(&self, s: &mut E) { |
| 152 | + self.value.encode(s); |
| 153 | + self.max_universe.encode(s); |
| 154 | + self.variables.encode(s); |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +impl<I: Interner, D: TyDecoder<I = I>, V: Decodable<D>> Decodable<D> for Canonical<I, V> |
| 159 | +where |
| 160 | + I::CanonicalVars: Decodable<D>, |
| 161 | +{ |
| 162 | + fn decode(d: &mut D) -> Self { |
| 163 | + Canonical { |
| 164 | + value: Decodable::decode(d), |
| 165 | + max_universe: Decodable::decode(d), |
| 166 | + variables: Decodable::decode(d), |
| 167 | + } |
| 168 | + } |
| 169 | +} |
0 commit comments