]>
Commit | Line | Data |
---|---|---|
a2a8927a | 1 | use crate::mir::Mutability; |
dfeec247 XL |
2 | use crate::ty::{self, Ty, TyCtxt}; |
3 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
4 | use rustc_hir::def_id::DefId; | |
c295e0f8 | 5 | use rustc_query_system::ich::StableHashingContext; |
ea8adc8c XL |
6 | use std::fmt::Debug; |
7 | use std::hash::Hash; | |
8 | use std::mem; | |
1a4d82fc | 9 | |
ea8adc8c | 10 | use self::SimplifiedTypeGen::*; |
1a4d82fc | 11 | |
ea8adc8c XL |
12 | pub type SimplifiedType = SimplifiedTypeGen<DefId>; |
13 | ||
14 | /// See `simplify_type` | |
15 | /// | |
16 | /// Note that we keep this type generic over the type of identifier it uses | |
17 | /// because we sometimes need to use SimplifiedTypeGen values as stable sorting | |
18 | /// keys (in which case we use a DefPathHash as id-type) but in the general case | |
19 | /// the non-stable but fast to construct DefId-version is the better choice. | |
3dfed10e | 20 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] |
ea8adc8c | 21 | pub enum SimplifiedTypeGen<D> |
dfeec247 | 22 | where |
a2a8927a | 23 | D: Copy + Debug + Eq, |
ea8adc8c | 24 | { |
1a4d82fc JJ |
25 | BoolSimplifiedType, |
26 | CharSimplifiedType, | |
5869c6ff XL |
27 | IntSimplifiedType(ty::IntTy), |
28 | UintSimplifiedType(ty::UintTy), | |
29 | FloatSimplifiedType(ty::FloatTy), | |
ea8adc8c | 30 | AdtSimplifiedType(D), |
a2a8927a | 31 | ForeignSimplifiedType(D), |
1a4d82fc | 32 | StrSimplifiedType, |
c30ab7b3 | 33 | ArraySimplifiedType, |
a2a8927a XL |
34 | SliceSimplifiedType, |
35 | RefSimplifiedType(Mutability), | |
36 | PtrSimplifiedType(Mutability), | |
5bcae85e | 37 | NeverSimplifiedType, |
c34b1796 | 38 | TupleSimplifiedType(usize), |
0731742a XL |
39 | /// A trait object, all of whose components are markers |
40 | /// (e.g., `dyn Send + Sync`). | |
41 | MarkerTraitObjectSimplifiedType, | |
ea8adc8c XL |
42 | TraitSimplifiedType(D), |
43 | ClosureSimplifiedType(D), | |
44 | GeneratorSimplifiedType(D), | |
2c00a5a8 | 45 | GeneratorWitnessSimplifiedType(usize), |
b7449926 | 46 | OpaqueSimplifiedType(D), |
c34b1796 | 47 | FunctionSimplifiedType(usize), |
1a4d82fc JJ |
48 | ParameterSimplifiedType, |
49 | } | |
50 | ||
a2a8927a XL |
51 | #[derive(PartialEq, Eq, Debug, Clone, Copy)] |
52 | pub enum SimplifyParams { | |
53 | Yes, | |
54 | No, | |
55 | } | |
56 | ||
57 | #[derive(PartialEq, Eq, Debug, Clone, Copy)] | |
58 | pub enum StripReferences { | |
59 | Yes, | |
60 | No, | |
61 | } | |
62 | ||
63 | /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists. | |
64 | /// | |
65 | /// The idea is to get something simple that we can use to quickly decide if two types could unify, | |
66 | /// for example during method lookup. | |
67 | /// | |
68 | /// A special case here are parameters and projections. Projections can be normalized to | |
69 | /// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though | |
70 | /// their outermost layer is different while parameters like `T` of impls are later replaced | |
71 | /// with an inference variable, which then also allows unification with other types. | |
72 | /// | |
73 | /// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections², | |
74 | /// the reasoning for this can be seen at the places doing this. | |
1a4d82fc | 75 | /// |
a2a8927a XL |
76 | /// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best |
77 | /// way to skip some unhelpful suggestions. | |
78 | /// | |
79 | /// ¹ meaning that if two outermost layers are different, then the whole types are also different. | |
80 | /// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during | |
81 | /// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even | |
82 | /// though `_` can be inferred to a concrete type later at which point a concrete impl | |
83 | /// could actually apply. After experimenting for about an hour I wasn't able to cause any issues | |
84 | /// this way so I am not going to change this until we actually find an issue as I am really | |
85 | /// interesting in getting an actual test for this. | |
dc9dc135 XL |
86 | pub fn simplify_type( |
87 | tcx: TyCtxt<'_>, | |
88 | ty: Ty<'_>, | |
a2a8927a XL |
89 | can_simplify_params: SimplifyParams, |
90 | strip_references: StripReferences, | |
dc9dc135 | 91 | ) -> Option<SimplifiedType> { |
1b1a35ee | 92 | match *ty.kind() { |
b7449926 XL |
93 | ty::Bool => Some(BoolSimplifiedType), |
94 | ty::Char => Some(CharSimplifiedType), | |
95 | ty::Int(int_type) => Some(IntSimplifiedType(int_type)), | |
96 | ty::Uint(uint_type) => Some(UintSimplifiedType(uint_type)), | |
97 | ty::Float(float_type) => Some(FloatSimplifiedType(float_type)), | |
98 | ty::Adt(def, _) => Some(AdtSimplifiedType(def.did)), | |
99 | ty::Str => Some(StrSimplifiedType), | |
a2a8927a XL |
100 | ty::Array(..) => Some(ArraySimplifiedType), |
101 | ty::Slice(..) => Some(SliceSimplifiedType), | |
102 | ty::RawPtr(ptr) => Some(PtrSimplifiedType(ptr.mutbl)), | |
dfeec247 XL |
103 | ty::Dynamic(ref trait_info, ..) => match trait_info.principal_def_id() { |
104 | Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { | |
105 | Some(TraitSimplifiedType(principal_def_id)) | |
0731742a | 106 | } |
dfeec247 XL |
107 | _ => Some(MarkerTraitObjectSimplifiedType), |
108 | }, | |
a2a8927a XL |
109 | ty::Ref(_, ty, mutbl) => { |
110 | if strip_references == StripReferences::Yes { | |
111 | // For diagnostics, when recommending similar impls we want to | |
112 | // recommend impls even when there is a reference mismatch, | |
113 | // so we treat &T and T equivalently in that case. | |
114 | simplify_type(tcx, ty, can_simplify_params, strip_references) | |
115 | } else { | |
116 | Some(RefSimplifiedType(mutbl)) | |
117 | } | |
1a4d82fc | 118 | } |
dfeec247 XL |
119 | ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)), |
120 | ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)), | |
b7449926 | 121 | ty::GeneratorWitness(ref tys) => { |
2c00a5a8 XL |
122 | Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len())) |
123 | } | |
b7449926 | 124 | ty::Never => Some(NeverSimplifiedType), |
dfeec247 XL |
125 | ty::Tuple(ref tys) => Some(TupleSimplifiedType(tys.len())), |
126 | ty::FnPtr(ref f) => Some(FunctionSimplifiedType(f.skip_binder().inputs().len())), | |
b7449926 | 127 | ty::Projection(_) | ty::Param(_) => { |
a2a8927a | 128 | if can_simplify_params == SimplifyParams::Yes { |
e9174d1e SL |
129 | // In normalized types, projections don't unify with |
130 | // anything. when lazy normalization happens, this | |
131 | // will change. It would still be nice to have a way | |
132 | // to deal with known-not-to-unify-with-anything | |
0731742a | 133 | // projections (e.g., the likes of <__S as Encoder>::Error). |
1a4d82fc JJ |
134 | Some(ParameterSimplifiedType) |
135 | } else { | |
136 | None | |
137 | } | |
138 | } | |
dfeec247 XL |
139 | ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)), |
140 | ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), | |
f035d41b | 141 | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, |
1a4d82fc JJ |
142 | } |
143 | } | |
ea8adc8c | 144 | |
e74abb32 | 145 | impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> { |
a2a8927a XL |
146 | pub fn def(self) -> Option<D> { |
147 | match self { | |
148 | AdtSimplifiedType(d) | |
149 | | ForeignSimplifiedType(d) | |
150 | | TraitSimplifiedType(d) | |
151 | | ClosureSimplifiedType(d) | |
152 | | GeneratorSimplifiedType(d) | |
153 | | OpaqueSimplifiedType(d) => Some(d), | |
154 | _ => None, | |
155 | } | |
156 | } | |
157 | ||
ea8adc8c | 158 | pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U> |
dfeec247 XL |
159 | where |
160 | F: Fn(D) -> U, | |
161 | U: Copy + Debug + Ord + Eq, | |
ea8adc8c XL |
162 | { |
163 | match self { | |
164 | BoolSimplifiedType => BoolSimplifiedType, | |
165 | CharSimplifiedType => CharSimplifiedType, | |
166 | IntSimplifiedType(t) => IntSimplifiedType(t), | |
167 | UintSimplifiedType(t) => UintSimplifiedType(t), | |
168 | FloatSimplifiedType(t) => FloatSimplifiedType(t), | |
169 | AdtSimplifiedType(d) => AdtSimplifiedType(map(d)), | |
a2a8927a | 170 | ForeignSimplifiedType(d) => ForeignSimplifiedType(map(d)), |
ea8adc8c XL |
171 | StrSimplifiedType => StrSimplifiedType, |
172 | ArraySimplifiedType => ArraySimplifiedType, | |
a2a8927a XL |
173 | SliceSimplifiedType => SliceSimplifiedType, |
174 | RefSimplifiedType(m) => RefSimplifiedType(m), | |
175 | PtrSimplifiedType(m) => PtrSimplifiedType(m), | |
ea8adc8c | 176 | NeverSimplifiedType => NeverSimplifiedType, |
0731742a | 177 | MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType, |
ea8adc8c XL |
178 | TupleSimplifiedType(n) => TupleSimplifiedType(n), |
179 | TraitSimplifiedType(d) => TraitSimplifiedType(map(d)), | |
180 | ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)), | |
181 | GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)), | |
2c00a5a8 | 182 | GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n), |
b7449926 | 183 | OpaqueSimplifiedType(d) => OpaqueSimplifiedType(map(d)), |
ea8adc8c XL |
184 | FunctionSimplifiedType(n) => FunctionSimplifiedType(n), |
185 | ParameterSimplifiedType => ParameterSimplifiedType, | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
dc9dc135 XL |
190 | impl<'a, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D> |
191 | where | |
e74abb32 | 192 | D: Copy + Debug + Ord + Eq + HashStable<StableHashingContext<'a>>, |
ea8adc8c | 193 | { |
e74abb32 | 194 | fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { |
ea8adc8c XL |
195 | mem::discriminant(self).hash_stable(hcx, hasher); |
196 | match *self { | |
dfeec247 XL |
197 | BoolSimplifiedType |
198 | | CharSimplifiedType | |
199 | | StrSimplifiedType | |
200 | | ArraySimplifiedType | |
a2a8927a | 201 | | SliceSimplifiedType |
dfeec247 XL |
202 | | NeverSimplifiedType |
203 | | ParameterSimplifiedType | |
204 | | MarkerTraitObjectSimplifiedType => { | |
ea8adc8c XL |
205 | // nothing to do |
206 | } | |
a2a8927a | 207 | RefSimplifiedType(m) | PtrSimplifiedType(m) => m.hash_stable(hcx, hasher), |
ea8adc8c XL |
208 | IntSimplifiedType(t) => t.hash_stable(hcx, hasher), |
209 | UintSimplifiedType(t) => t.hash_stable(hcx, hasher), | |
210 | FloatSimplifiedType(t) => t.hash_stable(hcx, hasher), | |
211 | AdtSimplifiedType(d) => d.hash_stable(hcx, hasher), | |
212 | TupleSimplifiedType(n) => n.hash_stable(hcx, hasher), | |
213 | TraitSimplifiedType(d) => d.hash_stable(hcx, hasher), | |
214 | ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher), | |
215 | GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher), | |
2c00a5a8 | 216 | GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher), |
b7449926 | 217 | OpaqueSimplifiedType(d) => d.hash_stable(hcx, hasher), |
ea8adc8c | 218 | FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher), |
abe05a73 | 219 | ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher), |
ea8adc8c XL |
220 | } |
221 | } | |
222 | } |