]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use rustc_data_structures::fx::FxHashMap; |
2 | use rustc_hir as hir; | |
3 | use rustc_hir::def_id::DefId; | |
4 | use rustc_hir::itemlikevisit::ItemLikeVisitor; | |
ba9703b0 XL |
5 | use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; |
6 | use rustc_middle::ty::{self, Ty, TyCtxt}; | |
dfeec247 | 7 | use rustc_span::Span; |
94b46f34 | 8 | |
8faf50e0 | 9 | use super::explicit::ExplicitPredicatesMap; |
94b46f34 | 10 | use super::utils::*; |
83c7162d XL |
11 | |
12 | /// Infer predicates for the items in the crate. | |
13 | /// | |
9fa01778 | 14 | /// `global_inferred_outlives`: this is initially the empty map that |
83c7162d XL |
15 | /// was generated by walking the items in the crate. This will |
16 | /// now be filled with inferred predicates. | |
17 | pub fn infer_predicates<'tcx>( | |
dc9dc135 | 18 | tcx: TyCtxt<'tcx>, |
8faf50e0 | 19 | explicit_map: &mut ExplicitPredicatesMap<'tcx>, |
83c7162d XL |
20 | ) -> FxHashMap<DefId, RequiredPredicates<'tcx>> { |
21 | debug!("infer_predicates"); | |
22 | ||
23 | let mut predicates_added = true; | |
24 | ||
25 | let mut global_inferred_outlives = FxHashMap::default(); | |
26 | ||
27 | // If new predicates were added then we need to re-calculate | |
28 | // all crates since there could be new implied predicates. | |
29 | while predicates_added { | |
30 | predicates_added = false; | |
31 | ||
32 | let mut visitor = InferVisitor { | |
74b04a01 | 33 | tcx, |
83c7162d XL |
34 | global_inferred_outlives: &mut global_inferred_outlives, |
35 | predicates_added: &mut predicates_added, | |
74b04a01 | 36 | explicit_map, |
83c7162d XL |
37 | }; |
38 | ||
39 | // Visit all the crates and infer predicates | |
c295e0f8 | 40 | tcx.hir().visit_all_item_likes(&mut visitor); |
83c7162d XL |
41 | } |
42 | ||
43 | global_inferred_outlives | |
44 | } | |
45 | ||
dc9dc135 XL |
46 | pub struct InferVisitor<'cx, 'tcx> { |
47 | tcx: TyCtxt<'tcx>, | |
83c7162d XL |
48 | global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>, |
49 | predicates_added: &'cx mut bool, | |
8faf50e0 | 50 | explicit_map: &'cx mut ExplicitPredicatesMap<'tcx>, |
83c7162d XL |
51 | } |
52 | ||
83c7162d | 53 | impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { |
dfeec247 | 54 | fn visit_item(&mut self, item: &hir::Item<'_>) { |
6a06907d | 55 | let item_did = item.def_id; |
83c7162d XL |
56 | |
57 | debug!("InferVisitor::visit_item(item={:?})", item_did); | |
58 | ||
83c7162d | 59 | let mut item_required_predicates = RequiredPredicates::default(); |
e74abb32 | 60 | match item.kind { |
8faf50e0 | 61 | hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) => { |
f9f354fc | 62 | let adt_def = self.tcx.adt_def(item_did.to_def_id()); |
83c7162d XL |
63 | |
64 | // Iterate over all fields in item_did | |
65 | for field_def in adt_def.all_fields() { | |
66 | // Calculating the predicate requirements necessary | |
67 | // for item_did. | |
68 | // | |
b7449926 | 69 | // For field of type &'a T (reference) or Adt |
83c7162d XL |
70 | // (struct/enum/union) there will be outlive |
71 | // requirements for adt_def. | |
72 | let field_ty = self.tcx.type_of(field_def.did); | |
e74abb32 | 73 | let field_span = self.tcx.def_span(field_def.did); |
83c7162d XL |
74 | insert_required_predicates_to_be_wf( |
75 | self.tcx, | |
76 | field_ty, | |
e74abb32 | 77 | field_span, |
83c7162d XL |
78 | self.global_inferred_outlives, |
79 | &mut item_required_predicates, | |
8faf50e0 | 80 | &mut self.explicit_map, |
83c7162d XL |
81 | ); |
82 | } | |
83 | } | |
84 | ||
85 | _ => {} | |
86 | }; | |
87 | ||
88 | // If new predicates were added (`local_predicate_map` has more | |
89 | // predicates than the `global_inferred_outlives`), the new predicates | |
90 | // might result in implied predicates for their parent types. | |
91 | // Therefore mark `predicates_added` as true and which will ensure | |
92 | // we walk the crates again and re-calculate predicates for all | |
93 | // items. | |
dfeec247 | 94 | let item_predicates_len: usize = |
5869c6ff | 95 | self.global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len()); |
83c7162d XL |
96 | if item_required_predicates.len() > item_predicates_len { |
97 | *self.predicates_added = true; | |
f9f354fc | 98 | self.global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates); |
83c7162d XL |
99 | } |
100 | } | |
101 | ||
dfeec247 | 102 | fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {} |
83c7162d | 103 | |
dfeec247 | 104 | fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {} |
fc512014 XL |
105 | |
106 | fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {} | |
83c7162d XL |
107 | } |
108 | ||
109 | fn insert_required_predicates_to_be_wf<'tcx>( | |
dc9dc135 | 110 | tcx: TyCtxt<'tcx>, |
83c7162d | 111 | field_ty: Ty<'tcx>, |
e74abb32 | 112 | field_span: Span, |
83c7162d XL |
113 | global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>, |
114 | required_predicates: &mut RequiredPredicates<'tcx>, | |
8faf50e0 | 115 | explicit_map: &mut ExplicitPredicatesMap<'tcx>, |
83c7162d | 116 | ) { |
94222f64 XL |
117 | // We must not look into the default substs of consts |
118 | // as computing those depends on the results of `predicates_of`. | |
119 | // | |
120 | // Luckily the only types contained in default substs are type | |
121 | // parameters which don't matter here. | |
122 | // | |
123 | // FIXME(adt_const_params): Once complex const parameter types | |
124 | // are allowed, this might be incorrect. I think that we will still be | |
125 | // fine, as all outlives relations of the const param types should also | |
126 | // be part of the adt containing it, but we should still both update the | |
127 | // documentation and add some tests for this. | |
128 | for arg in field_ty.walk_ignoring_default_const_substs() { | |
ba9703b0 XL |
129 | let ty = match arg.unpack() { |
130 | GenericArgKind::Type(ty) => ty, | |
131 | ||
132 | // No predicates from lifetimes or constants, except potentially | |
133 | // constants' types, but `walk` will get to them as well. | |
134 | GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, | |
135 | }; | |
136 | ||
1b1a35ee | 137 | match *ty.kind() { |
83c7162d XL |
138 | // The field is of type &'a T which means that we will have |
139 | // a predicate requirement of T: 'a (T outlives 'a). | |
140 | // | |
141 | // We also want to calculate potential predicates for the T | |
b7449926 XL |
142 | ty::Ref(region, rty, _) => { |
143 | debug!("Ref"); | |
e74abb32 | 144 | insert_outlives_predicate(tcx, rty.into(), region, field_span, required_predicates); |
83c7162d XL |
145 | } |
146 | ||
b7449926 | 147 | // For each Adt (struct/enum/union) type `Foo<'a, T>`, we |
83c7162d XL |
148 | // can load the current set of inferred and explicit |
149 | // predicates from `global_inferred_outlives` and filter the | |
150 | // ones that are TypeOutlives. | |
b7449926 | 151 | ty::Adt(def, substs) => { |
83c7162d XL |
152 | // First check the inferred predicates |
153 | // | |
154 | // Example 1: | |
155 | // | |
156 | // struct Foo<'a, T> { | |
157 | // field1: Bar<'a, T> | |
158 | // } | |
159 | // | |
160 | // struct Bar<'b, U> { | |
161 | // field2: &'b U | |
162 | // } | |
163 | // | |
164 | // Here, when processing the type of `field1`, we would | |
165 | // request the set of implicit predicates computed for `Bar` | |
166 | // thus far. This will initially come back empty, but in next | |
167 | // round we will get `U: 'b`. We then apply the substitution | |
168 | // `['b => 'a, U => T]` and thus get the requirement that `T: | |
169 | // 'a` holds for `Foo`. | |
b7449926 | 170 | debug!("Adt"); |
83c7162d | 171 | if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) { |
e74abb32 | 172 | for (unsubstituted_predicate, &span) in unsubstituted_predicates { |
83c7162d XL |
173 | // `unsubstituted_predicate` is `U: 'b` in the |
174 | // example above. So apply the substitution to | |
175 | // get `T: 'a` (or `predicate`): | |
176 | let predicate = unsubstituted_predicate.subst(tcx, substs); | |
177 | insert_outlives_predicate( | |
178 | tcx, | |
179 | predicate.0, | |
180 | predicate.1, | |
e74abb32 | 181 | span, |
83c7162d XL |
182 | required_predicates, |
183 | ); | |
184 | } | |
185 | } | |
186 | ||
187 | // Check if the type has any explicit predicates that need | |
188 | // to be added to `required_predicates` | |
189 | // let _: () = substs.region_at(0); | |
94b46f34 XL |
190 | check_explicit_predicates( |
191 | tcx, | |
e1599b0c | 192 | def.did, |
94b46f34 XL |
193 | substs, |
194 | required_predicates, | |
195 | explicit_map, | |
e1599b0c | 196 | None, |
94b46f34 | 197 | ); |
83c7162d XL |
198 | } |
199 | ||
b7449926 | 200 | ty::Dynamic(obj, ..) => { |
94b46f34 XL |
201 | // This corresponds to `dyn Trait<..>`. In this case, we should |
202 | // use the explicit predicates as well. | |
203 | ||
b7449926 | 204 | debug!("Dynamic"); |
94b46f34 XL |
205 | debug!("field_ty = {}", &field_ty); |
206 | debug!("ty in field = {}", &ty); | |
0731742a XL |
207 | if let Some(ex_trait_ref) = obj.principal() { |
208 | // Here, we are passing the type `usize` as a | |
209 | // placeholder value with the function | |
210 | // `with_self_ty`, since there is no concrete type | |
211 | // `Self` for a `dyn Trait` at this | |
212 | // stage. Therefore when checking explicit | |
213 | // predicates in `check_explicit_predicates` we | |
214 | // need to ignore checking the explicit_map for | |
215 | // Self type. | |
dfeec247 XL |
216 | let substs = |
217 | ex_trait_ref.with_self_ty(tcx, tcx.types.usize).skip_binder().substs; | |
0731742a XL |
218 | check_explicit_predicates( |
219 | tcx, | |
e1599b0c | 220 | ex_trait_ref.skip_binder().def_id, |
0731742a XL |
221 | substs, |
222 | required_predicates, | |
223 | explicit_map, | |
e1599b0c | 224 | Some(tcx.types.self_param), |
0731742a XL |
225 | ); |
226 | } | |
83c7162d XL |
227 | } |
228 | ||
b7449926 | 229 | ty::Projection(obj) => { |
94b46f34 | 230 | // This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the |
83c7162d | 231 | // explicit predicates as well. |
b7449926 | 232 | debug!("Projection"); |
83c7162d XL |
233 | check_explicit_predicates( |
234 | tcx, | |
e1599b0c | 235 | tcx.associated_item(obj.item_def_id).container.id(), |
83c7162d XL |
236 | obj.substs, |
237 | required_predicates, | |
238 | explicit_map, | |
e1599b0c | 239 | None, |
83c7162d XL |
240 | ); |
241 | } | |
242 | ||
243 | _ => {} | |
244 | } | |
245 | } | |
246 | } | |
247 | ||
248 | /// We also have to check the explicit predicates | |
249 | /// declared on the type. | |
250 | /// | |
251 | /// struct Foo<'a, T> { | |
252 | /// field1: Bar<T> | |
253 | /// } | |
254 | /// | |
255 | /// struct Bar<U> where U: 'static, U: Foo { | |
256 | /// ... | |
257 | /// } | |
258 | /// | |
259 | /// Here, we should fetch the explicit predicates, which | |
260 | /// will give us `U: 'static` and `U: Foo`. The latter we | |
261 | /// can ignore, but we will want to process `U: 'static`, | |
262 | /// applying the substitution as above. | |
94b46f34 | 263 | pub fn check_explicit_predicates<'tcx>( |
dc9dc135 | 264 | tcx: TyCtxt<'tcx>, |
e1599b0c | 265 | def_id: DefId, |
e74abb32 | 266 | substs: &[GenericArg<'tcx>], |
83c7162d | 267 | required_predicates: &mut RequiredPredicates<'tcx>, |
8faf50e0 | 268 | explicit_map: &mut ExplicitPredicatesMap<'tcx>, |
e1599b0c | 269 | ignored_self_ty: Option<Ty<'tcx>>, |
83c7162d | 270 | ) { |
13cf67c4 XL |
271 | debug!( |
272 | "check_explicit_predicates(def_id={:?}, \ | |
273 | substs={:?}, \ | |
274 | explicit_map={:?}, \ | |
275 | required_predicates={:?}, \ | |
e1599b0c | 276 | ignored_self_ty={:?})", |
dfeec247 | 277 | def_id, substs, explicit_map, required_predicates, ignored_self_ty, |
13cf67c4 | 278 | ); |
e1599b0c | 279 | let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id); |
94b46f34 | 280 | |
e74abb32 | 281 | for (outlives_predicate, &span) in explicit_predicates { |
8faf50e0 | 282 | debug!("outlives_predicate = {:?}", &outlives_predicate); |
83c7162d | 283 | |
8faf50e0 XL |
284 | // Careful: If we are inferring the effects of a `dyn Trait<..>` |
285 | // type, then when we look up the predicates for `Trait`, | |
286 | // we may find some that reference `Self`. e.g., perhaps the | |
287 | // definition of `Trait` was: | |
288 | // | |
289 | // ``` | |
290 | // trait Trait<'a, T> where Self: 'a { .. } | |
291 | // ``` | |
292 | // | |
293 | // we want to ignore such predicates here, because | |
294 | // there is no type parameter for them to affect. Consider | |
295 | // a struct containing `dyn Trait`: | |
296 | // | |
297 | // ``` | |
298 | // struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> } | |
299 | // ``` | |
300 | // | |
301 | // The `where Self: 'a` predicate refers to the *existential, hidden type* | |
302 | // that is represented by the `dyn Trait`, not to the `X` type parameter | |
303 | // (or any other generic parameter) declared on `MyStruct`. | |
304 | // | |
305 | // Note that we do this check for self **before** applying `substs`. In the | |
306 | // case that `substs` come from a `dyn Trait` type, our caller will have | |
13cf67c4 | 307 | // included `Self = usize` as the value for `Self`. If we were |
8faf50e0 | 308 | // to apply the substs, and not filter this predicate, we might then falsely |
0731742a | 309 | // conclude that e.g., `X: 'x` was a reasonable inferred requirement. |
13cf67c4 | 310 | // |
94222f64 | 311 | // Another similar case is where we have an inferred |
13cf67c4 XL |
312 | // requirement like `<Self as Trait>::Foo: 'b`. We presently |
313 | // ignore such requirements as well (cc #54467)-- though | |
314 | // conceivably it might be better if we could extract the `Foo | |
315 | // = X` binding from the object type (there must be such a | |
316 | // binding) and thus infer an outlives requirement that `X: | |
317 | // 'b`. | |
e1599b0c | 318 | if let Some(self_ty) = ignored_self_ty { |
e74abb32 | 319 | if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { |
94222f64 | 320 | if ty.walk(tcx).any(|arg| arg == self_ty.into()) { |
13cf67c4 XL |
321 | debug!("skipping self ty = {:?}", &ty); |
322 | continue; | |
323 | } | |
8faf50e0 | 324 | } |
83c7162d | 325 | } |
8faf50e0 XL |
326 | |
327 | let predicate = outlives_predicate.subst(tcx, substs); | |
328 | debug!("predicate = {:?}", &predicate); | |
74b04a01 | 329 | insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates); |
83c7162d XL |
330 | } |
331 | } |