]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2012-2013 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 | ||
54a0048b SL |
11 | use hir::def_id::DefId; |
12 | use infer::InferCtxt; | |
a7813a04 | 13 | use ty::outlives::Component; |
54a0048b SL |
14 | use ty::subst::Substs; |
15 | use traits; | |
16 | use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; | |
e9174d1e | 17 | use std::iter::once; |
e9174d1e | 18 | use syntax::ast; |
3157f602 | 19 | use syntax_pos::Span; |
e9174d1e SL |
20 | use util::common::ErrorReported; |
21 | ||
22 | /// Returns the set of obligations needed to make `ty` well-formed. | |
23 | /// If `ty` contains unresolved inference variables, this may include | |
24 | /// further WF obligations. However, if `ty` IS an unresolved | |
25 | /// inference variable, returns `None`, because we are not able to | |
26 | /// make any progress at all. This is to prevent "livelock" where we | |
27 | /// say "$0 is WF if $0 is WF". | |
a7813a04 XL |
28 | pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
29 | body_id: ast::NodeId, | |
30 | ty: Ty<'tcx>, | |
31 | span: Span) | |
32 | -> Option<Vec<traits::PredicateObligation<'tcx>>> | |
e9174d1e SL |
33 | { |
34 | let mut wf = WfPredicates { infcx: infcx, | |
35 | body_id: body_id, | |
36 | span: span, | |
9cc50fc6 | 37 | out: vec![] }; |
e9174d1e SL |
38 | if wf.compute(ty) { |
39 | debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); | |
40 | let result = wf.normalize(); | |
41 | debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); | |
42 | Some(result) | |
43 | } else { | |
44 | None // no progress made, return None | |
45 | } | |
46 | } | |
47 | ||
48 | /// Returns the obligations that make this trait reference | |
49 | /// well-formed. For example, if there is a trait `Set` defined like | |
50 | /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF | |
51 | /// if `Bar: Eq`. | |
a7813a04 XL |
52 | pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
53 | body_id: ast::NodeId, | |
54 | trait_ref: &ty::TraitRef<'tcx>, | |
55 | span: Span) | |
56 | -> Vec<traits::PredicateObligation<'tcx>> | |
e9174d1e | 57 | { |
9cc50fc6 | 58 | let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; |
e9174d1e SL |
59 | wf.compute_trait_ref(trait_ref); |
60 | wf.normalize() | |
61 | } | |
62 | ||
a7813a04 XL |
63 | pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
64 | body_id: ast::NodeId, | |
65 | predicate: &ty::Predicate<'tcx>, | |
66 | span: Span) | |
67 | -> Vec<traits::PredicateObligation<'tcx>> | |
e9174d1e | 68 | { |
9cc50fc6 | 69 | let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] }; |
e9174d1e SL |
70 | |
71 | // (*) ok to skip binders, because wf code is prepared for it | |
72 | match *predicate { | |
73 | ty::Predicate::Trait(ref t) => { | |
74 | wf.compute_trait_ref(&t.skip_binder().trait_ref); // (*) | |
75 | } | |
76 | ty::Predicate::Equate(ref t) => { | |
77 | wf.compute(t.skip_binder().0); | |
78 | wf.compute(t.skip_binder().1); | |
79 | } | |
80 | ty::Predicate::RegionOutlives(..) => { | |
81 | } | |
82 | ty::Predicate::TypeOutlives(ref t) => { | |
83 | wf.compute(t.skip_binder().0); | |
84 | } | |
85 | ty::Predicate::Projection(ref t) => { | |
86 | let t = t.skip_binder(); // (*) | |
87 | wf.compute_projection(t.projection_ty); | |
88 | wf.compute(t.ty); | |
89 | } | |
90 | ty::Predicate::WellFormed(t) => { | |
91 | wf.compute(t); | |
92 | } | |
93 | ty::Predicate::ObjectSafe(_) => { | |
94 | } | |
a7813a04 XL |
95 | ty::Predicate::ClosureKind(..) => { |
96 | } | |
e9174d1e SL |
97 | } |
98 | ||
99 | wf.normalize() | |
100 | } | |
101 | ||
102 | /// Implied bounds are region relationships that we deduce | |
103 | /// automatically. The idea is that (e.g.) a caller must check that a | |
104 | /// function's argument types are well-formed immediately before | |
105 | /// calling that fn, and hence the *callee* can assume that its | |
106 | /// argument types are well-formed. This may imply certain relationships | |
107 | /// between generic parameters. For example: | |
108 | /// | |
109 | /// fn foo<'a,T>(x: &'a T) | |
110 | /// | |
111 | /// can only be called with a `'a` and `T` such that `&'a T` is WF. | |
112 | /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. | |
113 | #[derive(Debug)] | |
114 | pub enum ImpliedBound<'tcx> { | |
9e0c209e SL |
115 | RegionSubRegion(&'tcx ty::Region, &'tcx ty::Region), |
116 | RegionSubParam(&'tcx ty::Region, ty::ParamTy), | |
117 | RegionSubProjection(&'tcx ty::Region, ty::ProjectionTy<'tcx>), | |
e9174d1e SL |
118 | } |
119 | ||
120 | /// Compute the implied bounds that a callee/impl can assume based on | |
121 | /// the fact that caller/projector has ensured that `ty` is WF. See | |
122 | /// the `ImpliedBound` type for more details. | |
a7813a04 XL |
123 | pub fn implied_bounds<'a, 'gcx, 'tcx>( |
124 | infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, | |
e9174d1e SL |
125 | body_id: ast::NodeId, |
126 | ty: Ty<'tcx>, | |
127 | span: Span) | |
128 | -> Vec<ImpliedBound<'tcx>> | |
129 | { | |
130 | // Sometimes when we ask what it takes for T: WF, we get back that | |
131 | // U: WF is required; in that case, we push U onto this stack and | |
132 | // process it next. Currently (at least) these resulting | |
133 | // predicates are always guaranteed to be a subset of the original | |
134 | // type, so we need not fear non-termination. | |
135 | let mut wf_types = vec![ty]; | |
136 | ||
137 | let mut implied_bounds = vec![]; | |
138 | ||
139 | while let Some(ty) = wf_types.pop() { | |
140 | // Compute the obligations for `ty` to be well-formed. If `ty` is | |
141 | // an unresolved inference variable, just substituted an empty set | |
142 | // -- because the return type here is going to be things we *add* | |
143 | // to the environment, it's always ok for this set to be smaller | |
144 | // than the ultimate set. (Note: normally there won't be | |
145 | // unresolved inference variables here anyway, but there might be | |
146 | // during typeck under some circumstances.) | |
9cc50fc6 | 147 | let obligations = obligations(infcx, body_id, ty, span).unwrap_or(vec![]); |
e9174d1e SL |
148 | |
149 | // From the full set of obligations, just filter down to the | |
150 | // region relationships. | |
151 | implied_bounds.extend( | |
152 | obligations | |
153 | .into_iter() | |
154 | .flat_map(|obligation| { | |
155 | assert!(!obligation.has_escaping_regions()); | |
156 | match obligation.predicate { | |
157 | ty::Predicate::Trait(..) | | |
158 | ty::Predicate::Equate(..) | | |
159 | ty::Predicate::Projection(..) | | |
a7813a04 | 160 | ty::Predicate::ClosureKind(..) | |
e9174d1e SL |
161 | ty::Predicate::ObjectSafe(..) => |
162 | vec![], | |
163 | ||
164 | ty::Predicate::WellFormed(subty) => { | |
165 | wf_types.push(subty); | |
166 | vec![] | |
167 | } | |
168 | ||
169 | ty::Predicate::RegionOutlives(ref data) => | |
170 | match infcx.tcx.no_late_bound_regions(data) { | |
171 | None => | |
172 | vec![], | |
173 | Some(ty::OutlivesPredicate(r_a, r_b)) => | |
174 | vec![ImpliedBound::RegionSubRegion(r_b, r_a)], | |
175 | }, | |
176 | ||
177 | ty::Predicate::TypeOutlives(ref data) => | |
178 | match infcx.tcx.no_late_bound_regions(data) { | |
179 | None => vec![], | |
180 | Some(ty::OutlivesPredicate(ty_a, r_b)) => { | |
a7813a04 | 181 | let components = infcx.outlives_components(ty_a); |
e9174d1e SL |
182 | implied_bounds_from_components(r_b, components) |
183 | } | |
184 | }, | |
185 | }})); | |
186 | } | |
187 | ||
188 | implied_bounds | |
189 | } | |
190 | ||
191 | /// When we have an implied bound that `T: 'a`, we can further break | |
192 | /// this down to determine what relationships would have to hold for | |
193 | /// `T: 'a` to hold. We get to assume that the caller has validated | |
194 | /// those relationships. | |
9e0c209e | 195 | fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region, |
e9174d1e SL |
196 | sup_components: Vec<Component<'tcx>>) |
197 | -> Vec<ImpliedBound<'tcx>> | |
198 | { | |
199 | sup_components | |
200 | .into_iter() | |
201 | .flat_map(|component| { | |
202 | match component { | |
203 | Component::Region(r) => | |
204 | vec!(ImpliedBound::RegionSubRegion(sub_region, r)), | |
205 | Component::Param(p) => | |
206 | vec!(ImpliedBound::RegionSubParam(sub_region, p)), | |
207 | Component::Projection(p) => | |
208 | vec!(ImpliedBound::RegionSubProjection(sub_region, p)), | |
209 | Component::EscapingProjection(_) => | |
210 | // If the projection has escaping regions, don't | |
211 | // try to infer any implied bounds even for its | |
212 | // free components. This is conservative, because | |
213 | // the caller will still have to prove that those | |
214 | // free components outlive `sub_region`. But the | |
215 | // idea is that the WAY that the caller proves | |
216 | // that may change in the future and we want to | |
217 | // give ourselves room to get smarter here. | |
218 | vec!(), | |
219 | Component::UnresolvedInferenceVariable(..) => | |
220 | vec!(), | |
e9174d1e SL |
221 | } |
222 | }) | |
223 | .collect() | |
224 | } | |
225 | ||
a7813a04 XL |
226 | struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
227 | infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, | |
e9174d1e SL |
228 | body_id: ast::NodeId, |
229 | span: Span, | |
230 | out: Vec<traits::PredicateObligation<'tcx>>, | |
e9174d1e SL |
231 | } |
232 | ||
a7813a04 | 233 | impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { |
e9174d1e | 234 | fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { |
9cc50fc6 | 235 | traits::ObligationCause::new(self.span, self.body_id, code) |
e9174d1e SL |
236 | } |
237 | ||
238 | fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> { | |
239 | let cause = self.cause(traits::MiscObligation); | |
240 | let infcx = &mut self.infcx; | |
241 | self.out.iter() | |
242 | .inspect(|pred| assert!(!pred.has_escaping_regions())) | |
243 | .flat_map(|pred| { | |
244 | let mut selcx = traits::SelectionContext::new(infcx); | |
245 | let pred = traits::normalize(&mut selcx, cause.clone(), pred); | |
246 | once(pred.value).chain(pred.obligations) | |
247 | }) | |
248 | .collect() | |
249 | } | |
250 | ||
e9174d1e SL |
251 | /// Pushes the obligations required for `trait_ref` to be WF into |
252 | /// `self.out`. | |
253 | fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { | |
254 | let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); | |
255 | self.out.extend(obligations); | |
256 | ||
257 | let cause = self.cause(traits::MiscObligation); | |
258 | self.out.extend( | |
9e0c209e | 259 | trait_ref.substs.types() |
e9174d1e SL |
260 | .filter(|ty| !ty.has_escaping_regions()) |
261 | .map(|ty| traits::Obligation::new(cause.clone(), | |
262 | ty::Predicate::WellFormed(ty)))); | |
263 | } | |
264 | ||
265 | /// Pushes the obligations required for `trait_ref::Item` to be WF | |
266 | /// into `self.out`. | |
267 | fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { | |
268 | // A projection is well-formed if (a) the trait ref itself is | |
a7813a04 | 269 | // WF and (b) the trait-ref holds. (It may also be |
e9174d1e SL |
270 | // normalizable and be WF that way.) |
271 | ||
272 | self.compute_trait_ref(&data.trait_ref); | |
273 | ||
274 | if !data.has_escaping_regions() { | |
275 | let predicate = data.trait_ref.to_predicate(); | |
276 | let cause = self.cause(traits::ProjectionWf(data)); | |
277 | self.out.push(traits::Obligation::new(cause, predicate)); | |
278 | } | |
279 | } | |
280 | ||
9e0c209e | 281 | fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { |
a7813a04 XL |
282 | if !subty.has_escaping_regions() { |
283 | let cause = self.cause(cause); | |
284 | match self.infcx.tcx.trait_ref_for_builtin_bound(ty::BoundSized, subty) { | |
285 | Ok(trait_ref) => { | |
a7813a04 XL |
286 | self.out.push( |
287 | traits::Obligation::new(cause, | |
9e0c209e | 288 | trait_ref.to_predicate())); |
a7813a04 XL |
289 | } |
290 | Err(ErrorReported) => { } | |
291 | } | |
292 | } | |
293 | } | |
294 | ||
e9174d1e SL |
295 | /// Push new obligations into `out`. Returns true if it was able |
296 | /// to generate all the predicates needed to validate that `ty0` | |
297 | /// is WF. Returns false if `ty0` is an unresolved type variable, | |
298 | /// in which case we are not able to simplify at all. | |
299 | fn compute(&mut self, ty0: Ty<'tcx>) -> bool { | |
a7813a04 | 300 | let tcx = self.infcx.tcx; |
e9174d1e SL |
301 | let mut subtys = ty0.walk(); |
302 | while let Some(ty) = subtys.next() { | |
303 | match ty.sty { | |
304 | ty::TyBool | | |
305 | ty::TyChar | | |
306 | ty::TyInt(..) | | |
307 | ty::TyUint(..) | | |
308 | ty::TyFloat(..) | | |
309 | ty::TyError | | |
310 | ty::TyStr | | |
5bcae85e | 311 | ty::TyNever | |
e9174d1e SL |
312 | ty::TyParam(_) => { |
313 | // WfScalar, WfParameter, etc | |
314 | } | |
315 | ||
316 | ty::TySlice(subty) | | |
317 | ty::TyArray(subty, _) => { | |
9e0c209e | 318 | self.require_sized(subty, traits::SliceOrArrayElem); |
a7813a04 XL |
319 | } |
320 | ||
321 | ty::TyTuple(ref tys) => { | |
322 | if let Some((_last, rest)) = tys.split_last() { | |
323 | for elem in rest { | |
9e0c209e | 324 | self.require_sized(elem, traits::TupleElem); |
e9174d1e | 325 | } |
9cc50fc6 | 326 | } |
e9174d1e SL |
327 | } |
328 | ||
329 | ty::TyBox(_) | | |
e9174d1e SL |
330 | ty::TyRawPtr(_) => { |
331 | // simple cases that are WF if their type args are WF | |
332 | } | |
333 | ||
334 | ty::TyProjection(data) => { | |
335 | subtys.skip_current_subtree(); // subtree handled by compute_projection | |
336 | self.compute_projection(data); | |
337 | } | |
338 | ||
9e0c209e | 339 | ty::TyAdt(def, substs) => { |
e9174d1e SL |
340 | // WfNominalType |
341 | let obligations = self.nominal_obligations(def.did, substs); | |
342 | self.out.extend(obligations); | |
343 | } | |
344 | ||
345 | ty::TyRef(r, mt) => { | |
346 | // WfReference | |
347 | if !r.has_escaping_regions() && !mt.ty.has_escaping_regions() { | |
348 | let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); | |
349 | self.out.push( | |
350 | traits::Obligation::new( | |
351 | cause, | |
352 | ty::Predicate::TypeOutlives( | |
353 | ty::Binder( | |
9e0c209e | 354 | ty::OutlivesPredicate(mt.ty, r))))); |
e9174d1e SL |
355 | } |
356 | } | |
357 | ||
358 | ty::TyClosure(..) => { | |
359 | // the types in a closure are always the types of | |
360 | // local variables (or possibly references to local | |
9cc50fc6 SL |
361 | // variables), we'll walk those. |
362 | // | |
363 | // (Though, local variables are probably not | |
364 | // needed, as they are separately checked w/r/t | |
365 | // WFedness.) | |
e9174d1e SL |
366 | } |
367 | ||
54a0048b SL |
368 | ty::TyFnDef(..) | ty::TyFnPtr(_) => { |
369 | // let the loop iterate into the argument/return | |
9cc50fc6 | 370 | // types appearing in the fn signature |
e9174d1e SL |
371 | } |
372 | ||
5bcae85e SL |
373 | ty::TyAnon(..) => { |
374 | // all of the requirements on type parameters | |
375 | // should've been checked by the instantiation | |
376 | // of whatever returned this exact `impl Trait`. | |
377 | } | |
378 | ||
e9174d1e SL |
379 | ty::TyTrait(ref data) => { |
380 | // WfObject | |
381 | // | |
382 | // Here, we defer WF checking due to higher-ranked | |
383 | // regions. This is perhaps not ideal. | |
384 | self.from_object_ty(ty, data); | |
385 | ||
386 | // FIXME(#27579) RFC also considers adding trait | |
387 | // obligations that don't refer to Self and | |
388 | // checking those | |
389 | ||
390 | let cause = self.cause(traits::MiscObligation); | |
a7813a04 | 391 | |
a7813a04 | 392 | let component_traits = |
9e0c209e | 393 | data.builtin_bounds.iter().flat_map(|bound| { |
a7813a04 | 394 | tcx.lang_items.from_builtin_kind(bound).ok() |
9e0c209e SL |
395 | }) |
396 | .chain(Some(data.principal.def_id())); | |
a7813a04 XL |
397 | self.out.extend( |
398 | component_traits.map(|did| { traits::Obligation::new( | |
399 | cause.clone(), | |
9e0c209e | 400 | ty::Predicate::ObjectSafe(did) |
a7813a04 XL |
401 | )}) |
402 | ); | |
e9174d1e SL |
403 | } |
404 | ||
405 | // Inference variables are the complicated case, since we don't | |
406 | // know what type they are. We do two things: | |
407 | // | |
408 | // 1. Check if they have been resolved, and if so proceed with | |
409 | // THAT type. | |
410 | // 2. If not, check whether this is the type that we | |
411 | // started with (ty0). In that case, we've made no | |
412 | // progress at all, so return false. Otherwise, | |
413 | // we've at least simplified things (i.e., we went | |
414 | // from `Vec<$0>: WF` to `$0: WF`, so we can | |
415 | // register a pending obligation and keep | |
416 | // moving. (Goal is that an "inductive hypothesis" | |
417 | // is satisfied to ensure termination.) | |
418 | ty::TyInfer(_) => { | |
419 | let ty = self.infcx.shallow_resolve(ty); | |
420 | if let ty::TyInfer(_) = ty.sty { // not yet resolved... | |
421 | if ty == ty0 { // ...this is the type we started from! no progress. | |
422 | return false; | |
423 | } | |
424 | ||
425 | let cause = self.cause(traits::MiscObligation); | |
426 | self.out.push( // ...not the type we started from, so we made progress. | |
427 | traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); | |
428 | } else { | |
429 | // Yes, resolved, proceed with the | |
430 | // result. Should never return false because | |
431 | // `ty` is not a TyInfer. | |
432 | assert!(self.compute(ty)); | |
433 | } | |
434 | } | |
435 | } | |
436 | } | |
437 | ||
438 | // if we made it through that loop above, we made progress! | |
439 | return true; | |
440 | } | |
441 | ||
442 | fn nominal_obligations(&mut self, | |
443 | def_id: DefId, | |
444 | substs: &Substs<'tcx>) | |
445 | -> Vec<traits::PredicateObligation<'tcx>> | |
446 | { | |
447 | let predicates = | |
448 | self.infcx.tcx.lookup_predicates(def_id) | |
449 | .instantiate(self.infcx.tcx, substs); | |
450 | let cause = self.cause(traits::ItemObligation(def_id)); | |
451 | predicates.predicates | |
452 | .into_iter() | |
453 | .map(|pred| traits::Obligation::new(cause.clone(), pred)) | |
454 | .filter(|pred| !pred.has_escaping_regions()) | |
455 | .collect() | |
456 | } | |
457 | ||
9e0c209e | 458 | fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitObject<'tcx>) { |
e9174d1e SL |
459 | // Imagine a type like this: |
460 | // | |
461 | // trait Foo { } | |
462 | // trait Bar<'c> : 'c { } | |
463 | // | |
464 | // &'b (Foo+'c+Bar<'d>) | |
465 | // ^ | |
466 | // | |
467 | // In this case, the following relationships must hold: | |
468 | // | |
469 | // 'b <= 'c | |
470 | // 'd <= 'c | |
471 | // | |
472 | // The first conditions is due to the normal region pointer | |
473 | // rules, which say that a reference cannot outlive its | |
474 | // referent. | |
475 | // | |
476 | // The final condition may be a bit surprising. In particular, | |
477 | // you may expect that it would have been `'c <= 'd`, since | |
478 | // usually lifetimes of outer things are conservative | |
479 | // approximations for inner things. However, it works somewhat | |
480 | // differently with trait objects: here the idea is that if the | |
481 | // user specifies a region bound (`'c`, in this case) it is the | |
482 | // "master bound" that *implies* that bounds from other traits are | |
483 | // all met. (Remember that *all bounds* in a type like | |
484 | // `Foo+Bar+Zed` must be met, not just one, hence if we write | |
485 | // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and | |
486 | // 'y.) | |
487 | // | |
488 | // Note: in fact we only permit builtin traits, not `Bar<'d>`, I | |
489 | // am looking forward to the future here. | |
490 | ||
491 | if !data.has_escaping_regions() { | |
492 | let implicit_bounds = | |
493 | object_region_bounds(self.infcx.tcx, | |
9e0c209e SL |
494 | data.principal, |
495 | data.builtin_bounds); | |
e9174d1e | 496 | |
9e0c209e | 497 | let explicit_bound = data.region_bound; |
e9174d1e SL |
498 | |
499 | for implicit_bound in implicit_bounds { | |
500 | let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); | |
501 | let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); | |
502 | self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); | |
503 | } | |
504 | } | |
505 | } | |
506 | } | |
507 | ||
508 | /// Given an object type like `SomeTrait+Send`, computes the lifetime | |
509 | /// bounds that must hold on the elided self type. These are derived | |
510 | /// from the declarations of `SomeTrait`, `Send`, and friends -- if | |
511 | /// they declare `trait SomeTrait : 'static`, for example, then | |
512 | /// `'static` would appear in the list. The hard work is done by | |
513 | /// `ty::required_region_bounds`, see that for more information. | |
a7813a04 XL |
514 | pub fn object_region_bounds<'a, 'gcx, 'tcx>( |
515 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
9e0c209e | 516 | principal: ty::PolyExistentialTraitRef<'tcx>, |
e9174d1e | 517 | others: ty::BuiltinBounds) |
9e0c209e | 518 | -> Vec<&'tcx ty::Region> |
e9174d1e SL |
519 | { |
520 | // Since we don't actually *know* the self type for an object, | |
521 | // this "open(err)" serves as a kind of dummy standin -- basically | |
522 | // a skolemized type. | |
523 | let open_ty = tcx.mk_infer(ty::FreshTy(0)); | |
524 | ||
e9174d1e | 525 | let mut predicates = others.to_predicates(tcx, open_ty); |
9e0c209e | 526 | predicates.push(principal.with_self_ty(tcx, open_ty).to_predicate()); |
e9174d1e SL |
527 | |
528 | tcx.required_region_bounds(open_ty, predicates) | |
529 | } |