]>
Commit | Line | Data |
---|---|---|
abe05a73 XL |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Code that handles "type-outlives" constraints like `T: 'a`. This | |
12 | //! is based on the `outlives_components` function defined on the tcx, | |
13 | //! but it adds a bit of heuristics on top, in particular to deal with | |
14 | //! associated types and projections. | |
15 | //! | |
16 | //! When we process a given `T: 'a` obligation, we may produce two | |
17 | //! kinds of constraints for the region inferencer: | |
18 | //! | |
19 | //! - Relationships between inference variables and other regions. | |
20 | //! For example, if we have `&'?0 u32: 'a`, then we would produce | |
21 | //! a constraint that `'a <= '?0`. | |
22 | //! - "Verifys" that must be checked after inferencing is done. | |
23 | //! For example, if we know that, for some type parameter `T`, | |
24 | //! `T: 'a + 'b`, and we have a requirement that `T: '?1`, | |
25 | //! then we add a "verify" that checks that `'?1 <= 'a || '?1 <= 'b`. | |
26 | //! - Note the difference with the previous case: here, the region | |
27 | //! variable must be less than something else, so this doesn't | |
28 | //! affect how inference works (it finds the smallest region that | |
29 | //! will do); it's just a post-condition that we have to check. | |
30 | //! | |
31 | //! **The key point is that once this function is done, we have | |
32 | //! reduced all of our "type-region outlives" obligations into relationships | |
33 | //! between individual regions.** | |
34 | //! | |
35 | //! One key input to this function is the set of "region-bound pairs". | |
36 | //! These are basically the relationships between type parameters and | |
37 | //! regions that are in scope at the point where the outlives | |
38 | //! obligation was incurred. **When type-checking a function, | |
39 | //! particularly in the face of closures, this is not known until | |
40 | //! regionck runs!** This is because some of those bounds come | |
41 | //! from things we have yet to infer. | |
42 | //! | |
43 | //! Consider: | |
44 | //! | |
45 | //! ``` | |
46 | //! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)); | |
47 | //! fn foo<T>(x: T) { | |
48 | //! bar(x, |y| { ... }) | |
49 | //! // ^ closure arg | |
50 | //! } | |
51 | //! ``` | |
52 | //! | |
53 | //! Here, the type of `y` may involve inference variables and the | |
54 | //! like, and it may also contain implied bounds that are needed to | |
55 | //! type-check the closure body (e.g., here it informs us that `T` | |
56 | //! outlives the late-bound region `'a`). | |
57 | //! | |
58 | //! Note that by delaying the gathering of implied bounds until all | |
59 | //! inference information is known, we may find relationships between | |
60 | //! bound regions and other regions in the environment. For example, | |
61 | //! when we first check a closure like the one expected as argument | |
62 | //! to `foo`: | |
63 | //! | |
64 | //! ``` | |
65 | //! fn foo<U, F: for<'a> FnMut(&'a U)>(_f: F) {} | |
66 | //! ``` | |
67 | //! | |
68 | //! the type of the closure's first argument would be `&'a ?U`. We | |
69 | //! might later infer `?U` to something like `&'b u32`, which would | |
70 | //! imply that `'b: 'a`. | |
71 | ||
72 | use hir::def_id::DefId; | |
73 | use infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; | |
74 | use traits; | |
75 | use ty::{self, Ty, TyCtxt, TypeFoldable}; | |
76 | use ty::subst::{Subst, Substs}; | |
77 | use ty::outlives::Component; | |
78 | use syntax::ast; | |
79 | ||
80 | impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { | |
81 | /// Registers that the given region obligation must be resolved | |
82 | /// from within the scope of `body_id`. These regions are enqueued | |
83 | /// and later processed by regionck, when full type information is | |
84 | /// available (see `region_obligations` field for more | |
85 | /// information). | |
86 | pub fn register_region_obligation( | |
87 | &self, | |
88 | body_id: ast::NodeId, | |
89 | obligation: RegionObligation<'tcx>, | |
90 | ) { | |
ff7c6d11 XL |
91 | debug!( |
92 | "register_region_obligation(body_id={:?}, obligation={:?})", | |
93 | body_id, | |
94 | obligation | |
95 | ); | |
96 | ||
abe05a73 XL |
97 | self.region_obligations |
98 | .borrow_mut() | |
99 | .push((body_id, obligation)); | |
100 | } | |
101 | ||
0531ce1d XL |
102 | /// Trait queries just want to pass back type obligations "as is" |
103 | pub fn take_registered_region_obligations( | |
104 | &self, | |
105 | ) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> { | |
106 | ::std::mem::replace( | |
107 | &mut *self.region_obligations.borrow_mut(), | |
108 | vec![], | |
109 | ) | |
110 | } | |
111 | ||
abe05a73 XL |
112 | /// Process the region obligations that must be proven (during |
113 | /// `regionck`) for the given `body_id`, given information about | |
114 | /// the region bounds in scope and so forth. This function must be | |
115 | /// invoked for all relevant body-ids before region inference is | |
116 | /// done (or else an assert will fire). | |
117 | /// | |
118 | /// See the `region_obligations` field of `InferCtxt` for some | |
0531ce1d | 119 | /// comments about how this function fits into the overall expected |
abe05a73 XL |
120 | /// flow of the the inferencer. The key point is that it is |
121 | /// invoked after all type-inference variables have been bound -- | |
122 | /// towards the end of regionck. This also ensures that the | |
123 | /// region-bound-pairs are available (see comments above regarding | |
124 | /// closures). | |
125 | /// | |
126 | /// # Parameters | |
127 | /// | |
128 | /// - `region_bound_pairs`: the set of region bounds implied by | |
129 | /// the parameters and where-clauses. In particular, each pair | |
130 | /// `('a, K)` in this list tells us that the bounds in scope | |
131 | /// indicate that `K: 'a`, where `K` is either a generic | |
132 | /// parameter like `T` or a projection like `T::Item`. | |
133 | /// - `implicit_region_bound`: if some, this is a region bound | |
134 | /// that is considered to hold for all type parameters (the | |
135 | /// function body). | |
136 | /// - `param_env` is the parameter environment for the enclosing function. | |
137 | /// - `body_id` is the body-id whose region obligations are being | |
138 | /// processed. | |
139 | /// | |
140 | /// # Returns | |
141 | /// | |
142 | /// This function may have to perform normalizations, and hence it | |
143 | /// returns an `InferOk` with subobligations that must be | |
144 | /// processed. | |
145 | pub fn process_registered_region_obligations( | |
146 | &self, | |
147 | region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)], | |
148 | implicit_region_bound: Option<ty::Region<'tcx>>, | |
149 | param_env: ty::ParamEnv<'tcx>, | |
150 | body_id: ast::NodeId, | |
151 | ) { | |
152 | assert!( | |
153 | !self.in_snapshot.get(), | |
154 | "cannot process registered region obligations in a snapshot" | |
155 | ); | |
156 | ||
ff7c6d11 XL |
157 | debug!("process_registered_region_obligations()"); |
158 | ||
abe05a73 XL |
159 | // pull out the region obligations with the given `body_id` (leaving the rest) |
160 | let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len()); | |
161 | { | |
162 | let mut r_o = self.region_obligations.borrow_mut(); | |
163 | for (_, obligation) in r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) { | |
164 | my_region_obligations.push(obligation); | |
165 | } | |
166 | } | |
167 | ||
168 | let outlives = | |
169 | TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); | |
170 | ||
171 | for RegionObligation { | |
172 | sup_type, | |
173 | sub_region, | |
174 | cause, | |
175 | } in my_region_obligations | |
176 | { | |
ff7c6d11 XL |
177 | debug!( |
178 | "process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}", | |
179 | sup_type, | |
180 | sub_region, | |
181 | cause | |
182 | ); | |
183 | ||
abe05a73 XL |
184 | let origin = SubregionOrigin::from_obligation_cause( |
185 | &cause, | |
186 | || infer::RelateParamBound(cause.span, sup_type), | |
187 | ); | |
188 | ||
189 | outlives.type_must_outlive(origin, sup_type, sub_region); | |
190 | } | |
191 | } | |
192 | ||
193 | /// Processes a single ad-hoc region obligation that was not | |
194 | /// registered in advance. | |
195 | pub fn type_must_outlive( | |
196 | &self, | |
197 | region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)], | |
198 | implicit_region_bound: Option<ty::Region<'tcx>>, | |
199 | param_env: ty::ParamEnv<'tcx>, | |
200 | origin: infer::SubregionOrigin<'tcx>, | |
201 | ty: Ty<'tcx>, | |
202 | region: ty::Region<'tcx>, | |
203 | ) { | |
204 | let outlives = | |
205 | TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); | |
206 | outlives.type_must_outlive(origin, ty, region); | |
207 | } | |
abe05a73 XL |
208 | } |
209 | ||
210 | #[must_use] // you ought to invoke `into_accrued_obligations` when you are done =) | |
211 | struct TypeOutlives<'cx, 'gcx: 'tcx, 'tcx: 'cx> { | |
212 | // See the comments on `process_registered_region_obligations` for the meaning | |
213 | // of these fields. | |
214 | infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, | |
215 | region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], | |
216 | implicit_region_bound: Option<ty::Region<'tcx>>, | |
217 | param_env: ty::ParamEnv<'tcx>, | |
218 | } | |
219 | ||
220 | impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { | |
221 | fn new( | |
222 | infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, | |
223 | region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], | |
224 | implicit_region_bound: Option<ty::Region<'tcx>>, | |
225 | param_env: ty::ParamEnv<'tcx>, | |
226 | ) -> Self { | |
227 | Self { | |
228 | infcx, | |
229 | region_bound_pairs, | |
230 | implicit_region_bound, | |
231 | param_env, | |
232 | } | |
233 | } | |
234 | ||
235 | /// Adds constraints to inference such that `T: 'a` holds (or | |
236 | /// reports an error if it cannot). | |
237 | /// | |
238 | /// # Parameters | |
239 | /// | |
240 | /// - `origin`, the reason we need this constraint | |
241 | /// - `ty`, the type `T` | |
242 | /// - `region`, the region `'a` | |
243 | fn type_must_outlive( | |
244 | &self, | |
245 | origin: infer::SubregionOrigin<'tcx>, | |
246 | ty: Ty<'tcx>, | |
247 | region: ty::Region<'tcx>, | |
248 | ) { | |
249 | let ty = self.infcx.resolve_type_vars_if_possible(&ty); | |
250 | ||
251 | debug!( | |
252 | "type_must_outlive(ty={:?}, region={:?}, origin={:?})", | |
253 | ty, | |
254 | region, | |
255 | origin | |
256 | ); | |
257 | ||
258 | assert!(!ty.has_escaping_regions()); | |
259 | ||
260 | let components = self.tcx().outlives_components(ty); | |
261 | self.components_must_outlive(origin, components, region); | |
262 | } | |
263 | ||
264 | fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> { | |
265 | self.infcx.tcx | |
266 | } | |
267 | ||
268 | fn components_must_outlive( | |
269 | &self, | |
270 | origin: infer::SubregionOrigin<'tcx>, | |
271 | components: Vec<Component<'tcx>>, | |
272 | region: ty::Region<'tcx>, | |
273 | ) { | |
274 | for component in components { | |
275 | let origin = origin.clone(); | |
276 | match component { | |
277 | Component::Region(region1) => { | |
278 | self.infcx.sub_regions(origin, region, region1); | |
279 | } | |
280 | Component::Param(param_ty) => { | |
281 | self.param_ty_must_outlive(origin, region, param_ty); | |
282 | } | |
283 | Component::Projection(projection_ty) => { | |
284 | self.projection_must_outlive(origin, region, projection_ty); | |
285 | } | |
286 | Component::EscapingProjection(subcomponents) => { | |
287 | self.components_must_outlive(origin, subcomponents, region); | |
288 | } | |
289 | Component::UnresolvedInferenceVariable(v) => { | |
290 | // ignore this, we presume it will yield an error | |
291 | // later, since if a type variable is not resolved by | |
292 | // this point it never will be | |
293 | self.infcx.tcx.sess.delay_span_bug( | |
294 | origin.span(), | |
295 | &format!("unresolved inference variable in outlives: {:?}", v), | |
296 | ); | |
297 | } | |
298 | } | |
299 | } | |
300 | } | |
301 | ||
302 | fn param_ty_must_outlive( | |
303 | &self, | |
304 | origin: infer::SubregionOrigin<'tcx>, | |
305 | region: ty::Region<'tcx>, | |
306 | param_ty: ty::ParamTy, | |
307 | ) { | |
308 | debug!( | |
309 | "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", | |
310 | region, | |
311 | param_ty, | |
312 | origin | |
313 | ); | |
314 | ||
315 | let verify_bound = self.param_bound(param_ty); | |
316 | let generic = GenericKind::Param(param_ty); | |
317 | self.infcx | |
318 | .verify_generic_bound(origin, generic, region, verify_bound); | |
319 | } | |
320 | ||
321 | fn projection_must_outlive( | |
322 | &self, | |
323 | origin: infer::SubregionOrigin<'tcx>, | |
324 | region: ty::Region<'tcx>, | |
325 | projection_ty: ty::ProjectionTy<'tcx>, | |
326 | ) { | |
327 | debug!( | |
328 | "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", | |
329 | region, | |
330 | projection_ty, | |
331 | origin | |
332 | ); | |
333 | ||
334 | // This case is thorny for inference. The fundamental problem is | |
335 | // that there are many cases where we have choice, and inference | |
336 | // doesn't like choice (the current region inference in | |
337 | // particular). :) First off, we have to choose between using the | |
338 | // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and | |
339 | // OutlivesProjectionComponent rules, any one of which is | |
340 | // sufficient. If there are no inference variables involved, it's | |
341 | // not hard to pick the right rule, but if there are, we're in a | |
342 | // bit of a catch 22: if we picked which rule we were going to | |
343 | // use, we could add constraints to the region inference graph | |
344 | // that make it apply, but if we don't add those constraints, the | |
345 | // rule might not apply (but another rule might). For now, we err | |
346 | // on the side of adding too few edges into the graph. | |
347 | ||
348 | // Compute the bounds we can derive from the environment or trait | |
349 | // definition. We know that the projection outlives all the | |
350 | // regions in this list. | |
351 | let env_bounds = self.projection_declared_bounds(projection_ty); | |
352 | ||
353 | debug!("projection_must_outlive: env_bounds={:?}", env_bounds); | |
354 | ||
355 | // If we know that the projection outlives 'static, then we're | |
356 | // done here. | |
357 | if env_bounds.contains(&&ty::ReStatic) { | |
358 | debug!("projection_must_outlive: 'static as declared bound"); | |
359 | return; | |
360 | } | |
361 | ||
362 | // If declared bounds list is empty, the only applicable rule is | |
363 | // OutlivesProjectionComponent. If there are inference variables, | |
364 | // then, we can break down the outlives into more primitive | |
365 | // components without adding unnecessary edges. | |
366 | // | |
367 | // If there are *no* inference variables, however, we COULD do | |
368 | // this, but we choose not to, because the error messages are less | |
369 | // good. For example, a requirement like `T::Item: 'r` would be | |
370 | // translated to a requirement that `T: 'r`; when this is reported | |
371 | // to the user, it will thus say "T: 'r must hold so that T::Item: | |
372 | // 'r holds". But that makes it sound like the only way to fix | |
373 | // the problem is to add `T: 'r`, which isn't true. So, if there are no | |
374 | // inference variables, we use a verify constraint instead of adding | |
375 | // edges, which winds up enforcing the same condition. | |
376 | let needs_infer = projection_ty.needs_infer(); | |
377 | if env_bounds.is_empty() && needs_infer { | |
378 | debug!("projection_must_outlive: no declared bounds"); | |
379 | ||
380 | for component_ty in projection_ty.substs.types() { | |
381 | self.type_must_outlive(origin.clone(), component_ty, region); | |
382 | } | |
383 | ||
384 | for r in projection_ty.substs.regions() { | |
385 | self.infcx.sub_regions(origin.clone(), region, r); | |
386 | } | |
387 | ||
388 | return; | |
389 | } | |
390 | ||
391 | // If we find that there is a unique declared bound `'b`, and this bound | |
392 | // appears in the trait reference, then the best action is to require that `'b:'r`, | |
393 | // so do that. This is best no matter what rule we use: | |
394 | // | |
395 | // - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to | |
396 | // the requirement that `'b:'r` | |
397 | // - OutlivesProjectionComponent: this would require `'b:'r` in addition to | |
398 | // other conditions | |
399 | if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { | |
400 | let unique_bound = env_bounds[0]; | |
401 | debug!( | |
402 | "projection_must_outlive: unique declared bound = {:?}", | |
403 | unique_bound | |
404 | ); | |
405 | if projection_ty | |
406 | .substs | |
407 | .regions() | |
408 | .any(|r| env_bounds.contains(&r)) | |
409 | { | |
410 | debug!("projection_must_outlive: unique declared bound appears in trait ref"); | |
411 | self.infcx.sub_regions(origin.clone(), region, unique_bound); | |
412 | return; | |
413 | } | |
414 | } | |
415 | ||
416 | // Fallback to verifying after the fact that there exists a | |
417 | // declared bound, or that all the components appearing in the | |
418 | // projection outlive; in some cases, this may add insufficient | |
419 | // edges into the inference graph, leading to inference failures | |
420 | // even though a satisfactory solution exists. | |
421 | let verify_bound = self.projection_bound(env_bounds, projection_ty); | |
422 | let generic = GenericKind::Projection(projection_ty); | |
423 | self.infcx | |
424 | .verify_generic_bound(origin, generic.clone(), region, verify_bound); | |
425 | } | |
426 | ||
427 | fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { | |
428 | match ty.sty { | |
429 | ty::TyParam(p) => self.param_bound(p), | |
430 | ty::TyProjection(data) => { | |
431 | let declared_bounds = self.projection_declared_bounds(data); | |
432 | self.projection_bound(declared_bounds, data) | |
433 | } | |
434 | _ => self.recursive_type_bound(ty), | |
435 | } | |
436 | } | |
437 | ||
438 | fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { | |
439 | debug!("param_bound(param_ty={:?})", param_ty); | |
440 | ||
441 | let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty)); | |
442 | ||
443 | // Add in the default bound of fn body that applies to all in | |
444 | // scope type parameters: | |
445 | param_bounds.extend(self.implicit_region_bound); | |
446 | ||
447 | VerifyBound::AnyRegion(param_bounds) | |
448 | } | |
449 | ||
450 | fn projection_declared_bounds( | |
451 | &self, | |
452 | projection_ty: ty::ProjectionTy<'tcx>, | |
453 | ) -> Vec<ty::Region<'tcx>> { | |
454 | // First assemble bounds from where clauses and traits. | |
455 | ||
456 | let mut declared_bounds = | |
457 | self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty)); | |
458 | ||
459 | declared_bounds | |
460 | .extend_from_slice(&self.declared_projection_bounds_from_trait(projection_ty)); | |
461 | ||
462 | declared_bounds | |
463 | } | |
464 | ||
465 | fn projection_bound( | |
466 | &self, | |
467 | declared_bounds: Vec<ty::Region<'tcx>>, | |
468 | projection_ty: ty::ProjectionTy<'tcx>, | |
469 | ) -> VerifyBound<'tcx> { | |
470 | debug!( | |
471 | "projection_bound(declared_bounds={:?}, projection_ty={:?})", | |
472 | declared_bounds, | |
473 | projection_ty | |
474 | ); | |
475 | ||
476 | // see the extensive comment in projection_must_outlive | |
477 | let ty = self.infcx | |
478 | .tcx | |
479 | .mk_projection(projection_ty.item_def_id, projection_ty.substs); | |
480 | let recursive_bound = self.recursive_type_bound(ty); | |
481 | ||
482 | VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) | |
483 | } | |
484 | ||
485 | fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { | |
486 | let mut bounds = vec![]; | |
487 | ||
488 | for subty in ty.walk_shallow() { | |
489 | bounds.push(self.type_bound(subty)); | |
490 | } | |
491 | ||
492 | let mut regions = ty.regions(); | |
493 | regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions | |
494 | bounds.push(VerifyBound::AllRegions(regions)); | |
495 | ||
496 | // remove bounds that must hold, since they are not interesting | |
497 | bounds.retain(|b| !b.must_hold()); | |
498 | ||
499 | if bounds.len() == 1 { | |
500 | bounds.pop().unwrap() | |
501 | } else { | |
502 | VerifyBound::AllBounds(bounds) | |
503 | } | |
504 | } | |
505 | ||
506 | fn declared_generic_bounds_from_env( | |
507 | &self, | |
508 | generic: GenericKind<'tcx>, | |
509 | ) -> Vec<ty::Region<'tcx>> { | |
510 | let tcx = self.tcx(); | |
511 | ||
512 | // To start, collect bounds from user environment. Note that | |
513 | // parameter environments are already elaborated, so we don't | |
514 | // have to worry about that. Comparing using `==` is a bit | |
515 | // dubious for projections, but it will work for simple cases | |
516 | // like `T` and `T::Item`. It may not work as well for things | |
517 | // like `<T as Foo<'a>>::Item`. | |
518 | let generic_ty = generic.to_ty(tcx); | |
519 | let c_b = self.param_env.caller_bounds; | |
520 | let mut param_bounds = self.collect_outlives_from_predicate_list(generic_ty, c_b); | |
521 | ||
522 | // Next, collect regions we scraped from the well-formedness | |
523 | // constraints in the fn signature. To do that, we walk the list | |
524 | // of known relations from the fn ctxt. | |
525 | // | |
526 | // This is crucial because otherwise code like this fails: | |
527 | // | |
528 | // fn foo<'a, A>(x: &'a A) { x.bar() } | |
529 | // | |
530 | // The problem is that the type of `x` is `&'a A`. To be | |
531 | // well-formed, then, A must be lower-generic by `'a`, but we | |
532 | // don't know that this holds from first principles. | |
533 | for &(r, p) in self.region_bound_pairs { | |
534 | debug!("generic={:?} p={:?}", generic, p); | |
535 | if generic == p { | |
536 | param_bounds.push(r); | |
537 | } | |
538 | } | |
539 | ||
540 | param_bounds | |
541 | } | |
542 | ||
543 | /// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds | |
544 | /// declared in the trait definition. For example, if the trait were | |
545 | /// | |
546 | /// ```rust | |
547 | /// trait Foo<'a> { | |
548 | /// type Bar: 'a; | |
549 | /// } | |
550 | /// ``` | |
551 | /// | |
552 | /// then this function would return `'x`. This is subject to the | |
553 | /// limitations around higher-ranked bounds described in | |
554 | /// `region_bounds_declared_on_associated_item`. | |
555 | fn declared_projection_bounds_from_trait( | |
556 | &self, | |
557 | projection_ty: ty::ProjectionTy<'tcx>, | |
558 | ) -> Vec<ty::Region<'tcx>> { | |
559 | debug!("projection_bounds(projection_ty={:?})", projection_ty); | |
560 | let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id); | |
561 | for r in &mut bounds { | |
562 | *r = r.subst(self.tcx(), projection_ty.substs); | |
563 | } | |
564 | bounds | |
565 | } | |
566 | ||
567 | /// Given the def-id of an associated item, returns any region | |
568 | /// bounds attached to that associated item from the trait definition. | |
569 | /// | |
570 | /// For example: | |
571 | /// | |
572 | /// ```rust | |
573 | /// trait Foo<'a> { | |
574 | /// type Bar: 'a; | |
575 | /// } | |
576 | /// ``` | |
577 | /// | |
578 | /// If we were given the def-id of `Foo::Bar`, we would return | |
579 | /// `'a`. You could then apply the substitutions from the | |
580 | /// projection to convert this into your namespace. This also | |
581 | /// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on | |
582 | /// the trait. In fact, it works by searching for just such a | |
583 | /// where-clause. | |
584 | /// | |
585 | /// It will not, however, work for higher-ranked bounds like: | |
586 | /// | |
587 | /// ```rust | |
588 | /// trait Foo<'a, 'b> | |
589 | /// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x | |
590 | /// { | |
591 | /// type Bar; | |
592 | /// } | |
593 | /// ``` | |
594 | /// | |
595 | /// This is for simplicity, and because we are not really smart | |
596 | /// enough to cope with such bounds anywhere. | |
597 | fn region_bounds_declared_on_associated_item( | |
598 | &self, | |
599 | assoc_item_def_id: DefId, | |
600 | ) -> Vec<ty::Region<'tcx>> { | |
601 | let tcx = self.tcx(); | |
602 | let assoc_item = tcx.associated_item(assoc_item_def_id); | |
603 | let trait_def_id = assoc_item.container.assert_trait(); | |
604 | let trait_predicates = tcx.predicates_of(trait_def_id); | |
605 | let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id); | |
606 | let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); | |
607 | self.collect_outlives_from_predicate_list( | |
608 | identity_proj, | |
609 | traits::elaborate_predicates(tcx, trait_predicates.predicates), | |
610 | ) | |
611 | } | |
612 | ||
613 | /// Searches through a predicate list for a predicate `T: 'a`. | |
614 | /// | |
615 | /// Careful: does not elaborate predicates, and just uses `==` | |
616 | /// when comparing `ty` for equality, so `ty` must be something | |
617 | /// that does not involve inference variables and where you | |
618 | /// otherwise want a precise match. | |
619 | fn collect_outlives_from_predicate_list<I, P>( | |
620 | &self, | |
621 | ty: Ty<'tcx>, | |
622 | predicates: I, | |
623 | ) -> Vec<ty::Region<'tcx>> | |
624 | where | |
625 | I: IntoIterator<Item = P>, | |
626 | P: AsRef<ty::Predicate<'tcx>>, | |
627 | { | |
628 | predicates | |
629 | .into_iter() | |
630 | .filter_map(|p| p.as_ref().to_opt_type_outlives()) | |
ff7c6d11 | 631 | .filter_map(|p| p.no_late_bound_regions()) |
abe05a73 XL |
632 | .filter(|p| p.0 == ty) |
633 | .map(|p| p.1) | |
634 | .collect() | |
635 | } | |
636 | } |