]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::hir; |
2 | use crate::hir::def_id::DefId; | |
3 | use crate::infer::InferCtxt; | |
4 | use crate::ty::subst::Substs; | |
5 | use crate::traits; | |
6 | use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; | |
e9174d1e | 7 | use std::iter::once; |
3157f602 | 8 | use syntax_pos::Span; |
9fa01778 | 9 | use crate::middle::lang_items; |
e9174d1e SL |
10 | |
11 | /// Returns the set of obligations needed to make `ty` well-formed. | |
12 | /// If `ty` contains unresolved inference variables, this may include | |
13 | /// further WF obligations. However, if `ty` IS an unresolved | |
14 | /// inference variable, returns `None`, because we are not able to | |
15 | /// make any progress at all. This is to prevent "livelock" where we | |
16 | /// say "$0 is WF if $0 is WF". | |
a7813a04 | 17 | pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
7cac9316 | 18 | param_env: ty::ParamEnv<'tcx>, |
9fa01778 | 19 | body_id: hir::HirId, |
a7813a04 XL |
20 | ty: Ty<'tcx>, |
21 | span: Span) | |
22 | -> Option<Vec<traits::PredicateObligation<'tcx>>> | |
e9174d1e | 23 | { |
041b39d2 XL |
24 | let mut wf = WfPredicates { infcx, |
25 | param_env, | |
26 | body_id, | |
27 | span, | |
9cc50fc6 | 28 | out: vec![] }; |
e9174d1e SL |
29 | if wf.compute(ty) { |
30 | debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); | |
31 | let result = wf.normalize(); | |
32 | debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); | |
33 | Some(result) | |
34 | } else { | |
35 | None // no progress made, return None | |
36 | } | |
37 | } | |
38 | ||
39 | /// Returns the obligations that make this trait reference | |
40 | /// well-formed. For example, if there is a trait `Set` defined like | |
41 | /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF | |
42 | /// if `Bar: Eq`. | |
a7813a04 | 43 | pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
7cac9316 | 44 | param_env: ty::ParamEnv<'tcx>, |
9fa01778 | 45 | body_id: hir::HirId, |
a7813a04 XL |
46 | trait_ref: &ty::TraitRef<'tcx>, |
47 | span: Span) | |
48 | -> Vec<traits::PredicateObligation<'tcx>> | |
e9174d1e | 49 | { |
7cac9316 | 50 | let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; |
3b2f2976 | 51 | wf.compute_trait_ref(trait_ref, Elaborate::All); |
e9174d1e SL |
52 | wf.normalize() |
53 | } | |
54 | ||
a7813a04 | 55 | pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, |
7cac9316 | 56 | param_env: ty::ParamEnv<'tcx>, |
9fa01778 | 57 | body_id: hir::HirId, |
a7813a04 XL |
58 | predicate: &ty::Predicate<'tcx>, |
59 | span: Span) | |
60 | -> Vec<traits::PredicateObligation<'tcx>> | |
e9174d1e | 61 | { |
7cac9316 | 62 | let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; |
e9174d1e SL |
63 | |
64 | // (*) ok to skip binders, because wf code is prepared for it | |
65 | match *predicate { | |
66 | ty::Predicate::Trait(ref t) => { | |
3b2f2976 | 67 | wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) |
e9174d1e | 68 | } |
e9174d1e SL |
69 | ty::Predicate::RegionOutlives(..) => { |
70 | } | |
71 | ty::Predicate::TypeOutlives(ref t) => { | |
72 | wf.compute(t.skip_binder().0); | |
73 | } | |
74 | ty::Predicate::Projection(ref t) => { | |
75 | let t = t.skip_binder(); // (*) | |
76 | wf.compute_projection(t.projection_ty); | |
77 | wf.compute(t.ty); | |
78 | } | |
79 | ty::Predicate::WellFormed(t) => { | |
80 | wf.compute(t); | |
81 | } | |
82 | ty::Predicate::ObjectSafe(_) => { | |
83 | } | |
a7813a04 XL |
84 | ty::Predicate::ClosureKind(..) => { |
85 | } | |
cc61c64b XL |
86 | ty::Predicate::Subtype(ref data) => { |
87 | wf.compute(data.skip_binder().a); // (*) | |
88 | wf.compute(data.skip_binder().b); // (*) | |
89 | } | |
ea8adc8c XL |
90 | ty::Predicate::ConstEvaluatable(def_id, substs) => { |
91 | let obligations = wf.nominal_obligations(def_id, substs); | |
92 | wf.out.extend(obligations); | |
93 | ||
94 | for ty in substs.types() { | |
95 | wf.compute(ty); | |
96 | } | |
97 | } | |
e9174d1e SL |
98 | } |
99 | ||
100 | wf.normalize() | |
101 | } | |
102 | ||
a7813a04 XL |
103 | struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
104 | infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, | |
7cac9316 | 105 | param_env: ty::ParamEnv<'tcx>, |
9fa01778 | 106 | body_id: hir::HirId, |
e9174d1e SL |
107 | span: Span, |
108 | out: Vec<traits::PredicateObligation<'tcx>>, | |
e9174d1e SL |
109 | } |
110 | ||
3b2f2976 XL |
111 | /// Controls whether we "elaborate" supertraits and so forth on the WF |
112 | /// predicates. This is a kind of hack to address #43784. The | |
113 | /// underlying problem in that issue was a trait structure like: | |
114 | /// | |
115 | /// ``` | |
116 | /// trait Foo: Copy { } | |
117 | /// trait Bar: Foo { } | |
118 | /// impl<T: Bar> Foo for T { } | |
119 | /// impl<T> Bar for T { } | |
120 | /// ``` | |
121 | /// | |
122 | /// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but | |
123 | /// we decide that this is true because `T: Bar` is in the | |
124 | /// where-clauses (and we can elaborate that to include `T: | |
125 | /// Copy`). This wouldn't be a problem, except that when we check the | |
126 | /// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` | |
127 | /// impl. And so nowhere did we check that `T: Copy` holds! | |
128 | /// | |
129 | /// To resolve this, we elaborate the WF requirements that must be | |
130 | /// proven when checking impls. This means that (e.g.) the `impl Bar | |
131 | /// for T` will be forced to prove not only that `T: Foo` but also `T: | |
132 | /// Copy` (which it won't be able to do, because there is no `Copy` | |
133 | /// impl for `T`). | |
134 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | |
135 | enum Elaborate { | |
136 | All, | |
137 | None, | |
138 | } | |
139 | ||
a7813a04 | 140 | impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { |
e9174d1e | 141 | fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { |
9cc50fc6 | 142 | traits::ObligationCause::new(self.span, self.body_id, code) |
e9174d1e SL |
143 | } |
144 | ||
145 | fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> { | |
146 | let cause = self.cause(traits::MiscObligation); | |
147 | let infcx = &mut self.infcx; | |
7cac9316 | 148 | let param_env = self.param_env; |
e9174d1e | 149 | self.out.iter() |
a1dfa0c6 | 150 | .inspect(|pred| assert!(!pred.has_escaping_bound_vars())) |
e9174d1e SL |
151 | .flat_map(|pred| { |
152 | let mut selcx = traits::SelectionContext::new(infcx); | |
7cac9316 | 153 | let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred); |
e9174d1e SL |
154 | once(pred.value).chain(pred.obligations) |
155 | }) | |
156 | .collect() | |
157 | } | |
158 | ||
e9174d1e SL |
159 | /// Pushes the obligations required for `trait_ref` to be WF into |
160 | /// `self.out`. | |
3b2f2976 | 161 | fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { |
e9174d1e | 162 | let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); |
e9174d1e SL |
163 | |
164 | let cause = self.cause(traits::MiscObligation); | |
7cac9316 | 165 | let param_env = self.param_env; |
3b2f2976 XL |
166 | |
167 | if let Elaborate::All = elaborate { | |
168 | let predicates = obligations.iter() | |
169 | .map(|obligation| obligation.predicate.clone()) | |
170 | .collect(); | |
171 | let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates); | |
172 | let implied_obligations = implied_obligations.map(|pred| { | |
173 | traits::Obligation::new(cause.clone(), param_env, pred) | |
174 | }); | |
175 | self.out.extend(implied_obligations); | |
176 | } | |
177 | ||
178 | self.out.extend(obligations); | |
179 | ||
e9174d1e | 180 | self.out.extend( |
9e0c209e | 181 | trait_ref.substs.types() |
a1dfa0c6 | 182 | .filter(|ty| !ty.has_escaping_bound_vars()) |
e9174d1e | 183 | .map(|ty| traits::Obligation::new(cause.clone(), |
7cac9316 | 184 | param_env, |
e9174d1e SL |
185 | ty::Predicate::WellFormed(ty)))); |
186 | } | |
187 | ||
188 | /// Pushes the obligations required for `trait_ref::Item` to be WF | |
189 | /// into `self.out`. | |
190 | fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { | |
191 | // A projection is well-formed if (a) the trait ref itself is | |
a7813a04 | 192 | // WF and (b) the trait-ref holds. (It may also be |
e9174d1e | 193 | // normalizable and be WF that way.) |
041b39d2 | 194 | let trait_ref = data.trait_ref(self.infcx.tcx); |
3b2f2976 | 195 | self.compute_trait_ref(&trait_ref, Elaborate::None); |
e9174d1e | 196 | |
a1dfa0c6 | 197 | if !data.has_escaping_bound_vars() { |
041b39d2 | 198 | let predicate = trait_ref.to_predicate(); |
e9174d1e | 199 | let cause = self.cause(traits::ProjectionWf(data)); |
7cac9316 | 200 | self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); |
e9174d1e SL |
201 | } |
202 | } | |
203 | ||
0731742a | 204 | /// Pushes the obligations required for an array length to be WF |
ea8adc8c | 205 | /// into `self.out`. |
0731742a XL |
206 | fn compute_array_len(&mut self, constant: ty::LazyConst<'tcx>) { |
207 | if let ty::LazyConst::Unevaluated(def_id, substs) = constant { | |
8faf50e0 XL |
208 | let obligations = self.nominal_obligations(def_id, substs); |
209 | self.out.extend(obligations); | |
210 | ||
211 | let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); | |
212 | let cause = self.cause(traits::MiscObligation); | |
213 | self.out.push(traits::Obligation::new(cause, | |
0bf4aa26 XL |
214 | self.param_env, |
215 | predicate)); | |
ea8adc8c XL |
216 | } |
217 | } | |
218 | ||
9e0c209e | 219 | fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { |
a1dfa0c6 | 220 | if !subty.has_escaping_bound_vars() { |
a7813a04 | 221 | let cause = self.cause(cause); |
476ff2be SL |
222 | let trait_ref = ty::TraitRef { |
223 | def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), | |
224 | substs: self.infcx.tcx.mk_substs_trait(subty, &[]), | |
225 | }; | |
7cac9316 | 226 | self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); |
a7813a04 XL |
227 | } |
228 | } | |
229 | ||
9fa01778 | 230 | /// Pushes new obligations into `out`. Returns `true` if it was able |
e9174d1e SL |
231 | /// to generate all the predicates needed to validate that `ty0` |
232 | /// is WF. Returns false if `ty0` is an unresolved type variable, | |
233 | /// in which case we are not able to simplify at all. | |
234 | fn compute(&mut self, ty0: Ty<'tcx>) -> bool { | |
235 | let mut subtys = ty0.walk(); | |
7cac9316 | 236 | let param_env = self.param_env; |
e9174d1e SL |
237 | while let Some(ty) = subtys.next() { |
238 | match ty.sty { | |
b7449926 XL |
239 | ty::Bool | |
240 | ty::Char | | |
241 | ty::Int(..) | | |
242 | ty::Uint(..) | | |
243 | ty::Float(..) | | |
244 | ty::Error | | |
245 | ty::Str | | |
246 | ty::GeneratorWitness(..) | | |
247 | ty::Never | | |
248 | ty::Param(_) | | |
a1dfa0c6 XL |
249 | ty::Bound(..) | |
250 | ty::Placeholder(..) | | |
b7449926 | 251 | ty::Foreign(..) => { |
e9174d1e SL |
252 | // WfScalar, WfParameter, etc |
253 | } | |
254 | ||
b7449926 | 255 | ty::Slice(subty) => { |
ea8adc8c XL |
256 | self.require_sized(subty, traits::SliceOrArrayElem); |
257 | } | |
258 | ||
b7449926 | 259 | ty::Array(subty, len) => { |
9e0c209e | 260 | self.require_sized(subty, traits::SliceOrArrayElem); |
0731742a | 261 | self.compute_array_len(*len); |
a7813a04 XL |
262 | } |
263 | ||
b7449926 | 264 | ty::Tuple(ref tys) => { |
a7813a04 XL |
265 | if let Some((_last, rest)) = tys.split_last() { |
266 | for elem in rest { | |
9e0c209e | 267 | self.require_sized(elem, traits::TupleElem); |
e9174d1e | 268 | } |
9cc50fc6 | 269 | } |
e9174d1e SL |
270 | } |
271 | ||
b7449926 | 272 | ty::RawPtr(_) => { |
e9174d1e SL |
273 | // simple cases that are WF if their type args are WF |
274 | } | |
275 | ||
b7449926 | 276 | ty::Projection(data) => { |
e9174d1e SL |
277 | subtys.skip_current_subtree(); // subtree handled by compute_projection |
278 | self.compute_projection(data); | |
279 | } | |
280 | ||
0bf4aa26 XL |
281 | ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), |
282 | ||
b7449926 | 283 | ty::Adt(def, substs) => { |
e9174d1e SL |
284 | // WfNominalType |
285 | let obligations = self.nominal_obligations(def.did, substs); | |
286 | self.out.extend(obligations); | |
287 | } | |
288 | ||
0731742a XL |
289 | ty::FnDef(did, substs) => { |
290 | let obligations = self.nominal_obligations(did, substs); | |
291 | self.out.extend(obligations); | |
292 | } | |
293 | ||
b7449926 | 294 | ty::Ref(r, rty, _) => { |
e9174d1e | 295 | // WfReference |
a1dfa0c6 | 296 | if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { |
e9174d1e SL |
297 | let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); |
298 | self.out.push( | |
299 | traits::Obligation::new( | |
300 | cause, | |
7cac9316 | 301 | param_env, |
e9174d1e | 302 | ty::Predicate::TypeOutlives( |
83c7162d | 303 | ty::Binder::dummy( |
94b46f34 | 304 | ty::OutlivesPredicate(rty, r))))); |
e9174d1e SL |
305 | } |
306 | } | |
307 | ||
b7449926 | 308 | ty::Generator(..) => { |
ff7c6d11 XL |
309 | // Walk ALL the types in the generator: this will |
310 | // include the upvar types as well as the yield | |
311 | // type. Note that this is mildly distinct from | |
312 | // the closure case, where we have to be careful | |
313 | // about the signature of the closure. We don't | |
314 | // have the problem of implied bounds here since | |
315 | // generators don't take arguments. | |
316 | } | |
317 | ||
b7449926 | 318 | ty::Closure(def_id, substs) => { |
ff7c6d11 XL |
319 | // Only check the upvar types for WF, not the rest |
320 | // of the types within. This is needed because we | |
321 | // capture the signature and it may not be WF | |
322 | // without the implied bounds. Consider a closure | |
323 | // like `|x: &'a T|` -- it may be that `T: 'a` is | |
324 | // not known to hold in the creator's context (and | |
325 | // indeed the closure may not be invoked by its | |
326 | // creator, but rather turned to someone who *can* | |
327 | // verify that). | |
328 | // | |
329 | // The special treatment of closures here really | |
330 | // ought not to be necessary either; the problem | |
331 | // is related to #25860 -- there is no way for us | |
332 | // to express a fn type complete with the implied | |
333 | // bounds that it is assuming. I think in reality | |
334 | // the WF rules around fn are a bit messed up, and | |
335 | // that is the rot problem: `fn(&'a T)` should | |
336 | // probably always be WF, because it should be | |
337 | // shorthand for something like `where(T: 'a) { | |
338 | // fn(&'a T) }`, as discussed in #25860. | |
9cc50fc6 | 339 | // |
ff7c6d11 XL |
340 | // Note that we are also skipping the generic |
341 | // types. This is consistent with the `outlives` | |
342 | // code, but anyway doesn't matter: within the fn | |
343 | // body where they are created, the generics will | |
344 | // always be WF, and outside of that fn body we | |
345 | // are not directly inspecting closure types | |
346 | // anyway, except via auto trait matching (which | |
347 | // only inspects the upvar types). | |
348 | subtys.skip_current_subtree(); // subtree handled by compute_projection | |
349 | for upvar_ty in substs.upvar_tys(def_id, self.infcx.tcx) { | |
350 | self.compute(upvar_ty); | |
351 | } | |
e9174d1e SL |
352 | } |
353 | ||
0731742a | 354 | ty::FnPtr(_) => { |
54a0048b | 355 | // let the loop iterate into the argument/return |
9cc50fc6 | 356 | // types appearing in the fn signature |
e9174d1e SL |
357 | } |
358 | ||
b7449926 | 359 | ty::Opaque(did, substs) => { |
5bcae85e SL |
360 | // all of the requirements on type parameters |
361 | // should've been checked by the instantiation | |
362 | // of whatever returned this exact `impl Trait`. | |
8faf50e0 XL |
363 | |
364 | // for named existential types we still need to check them | |
365 | if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() { | |
366 | let obligations = self.nominal_obligations(did, substs); | |
367 | self.out.extend(obligations); | |
368 | } | |
5bcae85e SL |
369 | } |
370 | ||
b7449926 | 371 | ty::Dynamic(data, r) => { |
e9174d1e SL |
372 | // WfObject |
373 | // | |
374 | // Here, we defer WF checking due to higher-ranked | |
375 | // regions. This is perhaps not ideal. | |
476ff2be | 376 | self.from_object_ty(ty, data, r); |
e9174d1e SL |
377 | |
378 | // FIXME(#27579) RFC also considers adding trait | |
379 | // obligations that don't refer to Self and | |
380 | // checking those | |
381 | ||
382 | let cause = self.cause(traits::MiscObligation); | |
a7813a04 | 383 | let component_traits = |
0731742a | 384 | data.auto_traits().chain(data.principal_def_id()); |
a7813a04 | 385 | self.out.extend( |
476ff2be | 386 | component_traits.map(|did| traits::Obligation::new( |
a7813a04 | 387 | cause.clone(), |
7cac9316 | 388 | param_env, |
9e0c209e | 389 | ty::Predicate::ObjectSafe(did) |
476ff2be | 390 | )) |
a7813a04 | 391 | ); |
e9174d1e SL |
392 | } |
393 | ||
394 | // Inference variables are the complicated case, since we don't | |
395 | // know what type they are. We do two things: | |
396 | // | |
397 | // 1. Check if they have been resolved, and if so proceed with | |
398 | // THAT type. | |
399 | // 2. If not, check whether this is the type that we | |
400 | // started with (ty0). In that case, we've made no | |
401 | // progress at all, so return false. Otherwise, | |
402 | // we've at least simplified things (i.e., we went | |
403 | // from `Vec<$0>: WF` to `$0: WF`, so we can | |
404 | // register a pending obligation and keep | |
405 | // moving. (Goal is that an "inductive hypothesis" | |
406 | // is satisfied to ensure termination.) | |
b7449926 | 407 | ty::Infer(_) => { |
e9174d1e | 408 | let ty = self.infcx.shallow_resolve(ty); |
b7449926 | 409 | if let ty::Infer(_) = ty.sty { // not yet resolved... |
e9174d1e SL |
410 | if ty == ty0 { // ...this is the type we started from! no progress. |
411 | return false; | |
412 | } | |
413 | ||
414 | let cause = self.cause(traits::MiscObligation); | |
415 | self.out.push( // ...not the type we started from, so we made progress. | |
7cac9316 XL |
416 | traits::Obligation::new(cause, |
417 | self.param_env, | |
418 | ty::Predicate::WellFormed(ty))); | |
e9174d1e SL |
419 | } else { |
420 | // Yes, resolved, proceed with the | |
421 | // result. Should never return false because | |
b7449926 | 422 | // `ty` is not a Infer. |
e9174d1e SL |
423 | assert!(self.compute(ty)); |
424 | } | |
425 | } | |
426 | } | |
427 | } | |
428 | ||
429 | // if we made it through that loop above, we made progress! | |
430 | return true; | |
431 | } | |
432 | ||
433 | fn nominal_obligations(&mut self, | |
434 | def_id: DefId, | |
435 | substs: &Substs<'tcx>) | |
436 | -> Vec<traits::PredicateObligation<'tcx>> | |
437 | { | |
438 | let predicates = | |
7cac9316 | 439 | self.infcx.tcx.predicates_of(def_id) |
e9174d1e SL |
440 | .instantiate(self.infcx.tcx, substs); |
441 | let cause = self.cause(traits::ItemObligation(def_id)); | |
442 | predicates.predicates | |
443 | .into_iter() | |
7cac9316 XL |
444 | .map(|pred| traits::Obligation::new(cause.clone(), |
445 | self.param_env, | |
446 | pred)) | |
a1dfa0c6 | 447 | .filter(|pred| !pred.has_escaping_bound_vars()) |
e9174d1e SL |
448 | .collect() |
449 | } | |
450 | ||
476ff2be | 451 | fn from_object_ty(&mut self, ty: Ty<'tcx>, |
b7449926 | 452 | data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, |
7cac9316 | 453 | region: ty::Region<'tcx>) { |
e9174d1e SL |
454 | // Imagine a type like this: |
455 | // | |
456 | // trait Foo { } | |
457 | // trait Bar<'c> : 'c { } | |
458 | // | |
459 | // &'b (Foo+'c+Bar<'d>) | |
460 | // ^ | |
461 | // | |
462 | // In this case, the following relationships must hold: | |
463 | // | |
464 | // 'b <= 'c | |
465 | // 'd <= 'c | |
466 | // | |
467 | // The first conditions is due to the normal region pointer | |
468 | // rules, which say that a reference cannot outlive its | |
469 | // referent. | |
470 | // | |
471 | // The final condition may be a bit surprising. In particular, | |
472 | // you may expect that it would have been `'c <= 'd`, since | |
473 | // usually lifetimes of outer things are conservative | |
474 | // approximations for inner things. However, it works somewhat | |
475 | // differently with trait objects: here the idea is that if the | |
476 | // user specifies a region bound (`'c`, in this case) it is the | |
477 | // "master bound" that *implies* that bounds from other traits are | |
478 | // all met. (Remember that *all bounds* in a type like | |
479 | // `Foo+Bar+Zed` must be met, not just one, hence if we write | |
480 | // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and | |
481 | // 'y.) | |
482 | // | |
483 | // Note: in fact we only permit builtin traits, not `Bar<'d>`, I | |
484 | // am looking forward to the future here. | |
485 | ||
a1dfa0c6 | 486 | if !data.has_escaping_bound_vars() { |
e9174d1e | 487 | let implicit_bounds = |
476ff2be | 488 | object_region_bounds(self.infcx.tcx, data); |
e9174d1e | 489 | |
476ff2be | 490 | let explicit_bound = region; |
e9174d1e | 491 | |
0bf4aa26 | 492 | self.out.reserve(implicit_bounds.len()); |
e9174d1e | 493 | for implicit_bound in implicit_bounds { |
c30ab7b3 | 494 | let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); |
83c7162d XL |
495 | let outlives = ty::Binder::dummy( |
496 | ty::OutlivesPredicate(explicit_bound, implicit_bound)); | |
7cac9316 XL |
497 | self.out.push(traits::Obligation::new(cause, |
498 | self.param_env, | |
499 | outlives.to_predicate())); | |
e9174d1e SL |
500 | } |
501 | } | |
502 | } | |
503 | } | |
504 | ||
9fa01778 | 505 | /// Given an object type like `SomeTrait + Send`, computes the lifetime |
e9174d1e SL |
506 | /// bounds that must hold on the elided self type. These are derived |
507 | /// from the declarations of `SomeTrait`, `Send`, and friends -- if | |
508 | /// they declare `trait SomeTrait : 'static`, for example, then | |
509 | /// `'static` would appear in the list. The hard work is done by | |
510 | /// `ty::required_region_bounds`, see that for more information. | |
a7813a04 XL |
511 | pub fn object_region_bounds<'a, 'gcx, 'tcx>( |
512 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
b7449926 | 513 | existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>) |
7cac9316 | 514 | -> Vec<ty::Region<'tcx>> |
e9174d1e SL |
515 | { |
516 | // Since we don't actually *know* the self type for an object, | |
517 | // this "open(err)" serves as a kind of dummy standin -- basically | |
0bf4aa26 | 518 | // a placeholder type. |
e9174d1e SL |
519 | let open_ty = tcx.mk_infer(ty::FreshTy(0)); |
520 | ||
476ff2be SL |
521 | let predicates = existential_predicates.iter().filter_map(|predicate| { |
522 | if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() { | |
523 | None | |
524 | } else { | |
525 | Some(predicate.with_self_ty(tcx, open_ty)) | |
526 | } | |
527 | }).collect(); | |
e9174d1e SL |
528 | |
529 | tcx.required_region_bounds(open_ty, predicates) | |
530 | } |