1 // Copyright 2012 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.
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.
11 // #![warn(deprecated_mode)]
13 use middle::def_id::DefId;
14 use middle::infer::{InferCtxt, GenericKind};
15 use middle::subst::Substs;
17 use middle::ty::{self, ToPredicate, Ty};
18 use middle::ty::fold::{TypeFoldable, TypeFolder};
21 use syntax::codemap::Span;
23 use util::common::ErrorReported;
24 use util::nodemap::FnvHashSet;
26 // Helper functions related to manipulating region types.
29 pub enum Implication<'tcx> {
30 RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
31 RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
32 Predicate(DefId, ty::Predicate<'tcx>),
35 struct Implicator<'a, 'tcx: 'a> {
36 infcx: &'a InferCtxt<'a,'tcx>,
38 stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
40 out: Vec<Implication<'tcx>>,
41 visited: FnvHashSet<Ty<'tcx>>,
44 /// This routine computes the well-formedness constraints that must hold for the type `ty` to
45 /// appear in a context with lifetime `outer_region`
46 pub fn implications<'a,'tcx>(
47 infcx: &'a InferCtxt<'a,'tcx>,
50 outer_region: ty::Region,
52 -> Vec<Implication<'tcx>>
54 debug!("implications(body_id={}, ty={:?}, outer_region={:?})",
59 let mut stack = Vec::new();
60 stack.push((outer_region, None));
61 let mut wf = Implicator { infcx: infcx,
66 visited: FnvHashSet() };
67 wf.accumulate_from_ty(ty);
68 debug!("implications: out={:?}", wf.out);
72 impl<'a, 'tcx> Implicator<'a, 'tcx> {
73 fn tcx(&self) -> &'a ty::ctxt<'tcx> {
77 fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
78 debug!("accumulate_from_ty(ty={:?})",
81 // When expanding out associated types, we can visit a cyclic
82 // set of types. Issue #23003.
83 if !self.visited.insert(ty) {
96 // No borrowed content reachable here.
99 ty::TyClosure(_, ref substs) => {
100 // FIXME(#27086). We do not accumulate from substs, since they
101 // don't represent reachable data. This means that, in
102 // practice, some of the lifetime parameters might not
103 // be in scope when the body runs, so long as there is
104 // no reachable data with that lifetime. For better or
105 // worse, this is consistent with fn types, however,
106 // which can also encapsulate data in this fashion
107 // (though it's somewhat harder, and typically
108 // requires virtual dispatch).
110 // Note that changing this (in a naive way, at least)
111 // causes regressions for what appears to be perfectly
112 // reasonable code like this:
115 // fn foo<'a>(p: &Data<'a>) {
116 // bar(|q: &mut Parser| q.read_addr())
118 // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
122 // Note that `p` (and `'a`) are not used in the
123 // closure at all, but to meet the requirement that
124 // the closure type `C: 'static` (so it can be coerced
125 // to the object type), we get the requirement that
126 // `'a: 'static` since `'a` appears in the closure
129 // A smarter fix might "prune" unused `func_substs` --
130 // this would avoid breaking simple examples like
131 // this, but would still break others (which might
132 // indeed be invalid, depending on your POV). Pruning
133 // would be a subtle process, since we have to see
134 // what func/type parameters are used and unused,
135 // taking into consideration UFCS and so forth.
137 for &upvar_ty in &substs.upvar_tys {
138 self.accumulate_from_ty(upvar_ty);
142 ty::TyTrait(ref t) => {
143 let required_region_bounds =
144 object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
145 self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
148 ty::TyEnum(def, substs) |
149 ty::TyStruct(def, substs) => {
150 let item_scheme = def.type_scheme(self.tcx());
151 self.accumulate_from_adt(ty, def.did, &item_scheme.generics, substs)
156 ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) |
158 self.accumulate_from_ty(t)
161 ty::TyRef(r_b, mt) => {
162 self.accumulate_from_rptr(ty, *r_b, mt.ty);
166 self.push_param_constraint_from_top(p);
169 ty::TyProjection(ref data) => {
170 // `<T as TraitRef<..>>::Name`
172 self.push_projection_constraint_from_top(data);
175 ty::TyTuple(ref tuptys) => {
176 for &tupty in tuptys {
177 self.accumulate_from_ty(tupty);
182 // This should not happen, BUT:
184 // Currently we uncover region relationships on
185 // entering the fn check. We should do this after
186 // the fn check, then we can call this case a bug().
191 fn accumulate_from_rptr(&mut self,
195 // We are walking down a type like this, and current
196 // position is indicated by caret:
201 // At this point, top of stack will be `'a`. We must
202 // require that `'a <= 'b`.
204 self.push_region_constraint_from_top(r_b);
206 // Now we push `'b` onto the stack, because it must
207 // constrain any borrowed content we find within `T`.
209 self.stack.push((r_b, Some(ty)));
210 self.accumulate_from_ty(ty_b);
211 self.stack.pop().unwrap();
214 /// Pushes a constraint that `r_b` must outlive the top region on the stack.
215 fn push_region_constraint_from_top(&mut self,
218 // Indicates that we have found borrowed content with a lifetime
219 // of at least `r_b`. This adds a constraint that `r_b` must
220 // outlive the region `r_a` on top of the stack.
222 // As an example, imagine walking a type like:
227 // when we hit the inner pointer (indicated by caret), `'a` will
228 // be on top of stack and `'b` will be the lifetime of the content
229 // we just found. So we add constraint that `'a <= 'b`.
231 let &(r_a, opt_ty) = self.stack.last().unwrap();
232 self.push_sub_region_constraint(opt_ty, r_a, r_b);
235 /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
236 fn push_sub_region_constraint(&mut self,
237 opt_ty: Option<Ty<'tcx>>,
240 self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
243 /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
244 fn push_param_constraint_from_top(&mut self,
245 param_ty: ty::ParamTy) {
246 let &(region, opt_ty) = self.stack.last().unwrap();
247 self.push_param_constraint(region, opt_ty, param_ty);
250 /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
251 fn push_projection_constraint_from_top(&mut self,
252 projection_ty: &ty::ProjectionTy<'tcx>) {
253 let &(region, opt_ty) = self.stack.last().unwrap();
254 self.out.push(Implication::RegionSubGeneric(
255 opt_ty, region, GenericKind::Projection(projection_ty.clone())));
258 /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
259 fn push_param_constraint(&mut self,
261 opt_ty: Option<Ty<'tcx>>,
262 param_ty: ty::ParamTy) {
263 self.out.push(Implication::RegionSubGeneric(
264 opt_ty, region, GenericKind::Param(param_ty)));
267 fn accumulate_from_adt(&mut self,
270 _generics: &ty::Generics<'tcx>,
271 substs: &Substs<'tcx>)
274 self.tcx().lookup_predicates(def_id).instantiate(self.tcx(), substs);
275 let predicates = match self.fully_normalize(&predicates) {
276 Ok(predicates) => predicates,
277 Err(ErrorReported) => { return; }
280 for predicate in predicates.predicates.as_slice() {
282 ty::Predicate::Trait(..) => { }
283 ty::Predicate::Equate(..) => { }
284 ty::Predicate::Projection(..) => { }
285 ty::Predicate::RegionOutlives(ref data) => {
286 match self.tcx().no_late_bound_regions(data) {
288 Some(ty::OutlivesPredicate(r_a, r_b)) => {
289 self.push_sub_region_constraint(Some(ty), r_b, r_a);
293 ty::Predicate::TypeOutlives(ref data) => {
294 match self.tcx().no_late_bound_regions(data) {
296 Some(ty::OutlivesPredicate(ty_a, r_b)) => {
297 self.stack.push((r_b, Some(ty)));
298 self.accumulate_from_ty(ty_a);
299 self.stack.pop().unwrap();
303 ty::Predicate::ObjectSafe(_) |
304 ty::Predicate::WellFormed(_) => {
309 let obligations = predicates.predicates
311 .map(|pred| Implication::Predicate(def_id, pred));
312 self.out.extend(obligations);
314 let variances = self.tcx().item_variances(def_id);
315 self.accumulate_from_substs(substs, Some(&variances));
318 fn accumulate_from_substs(&mut self,
319 substs: &Substs<'tcx>,
320 variances: Option<&ty::ItemVariances>)
322 let mut tmp_variances = None;
323 let variances = variances.unwrap_or_else(|| {
324 tmp_variances = Some(ty::ItemVariances {
325 types: substs.types.map(|_| ty::Variance::Invariant),
326 regions: substs.regions().map(|_| ty::Variance::Invariant),
328 tmp_variances.as_ref().unwrap()
331 for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) {
333 ty::Contravariant | ty::Invariant => {
334 // If any data with this lifetime is reachable
335 // within, it must be at least contravariant.
336 self.push_region_constraint_from_top(region)
338 ty::Covariant | ty::Bivariant => { }
342 for (&ty, &variance) in substs.types.iter().zip(&variances.types) {
344 ty::Covariant | ty::Invariant => {
345 // If any data of this type is reachable within,
346 // it must be at least covariant.
347 self.accumulate_from_ty(ty);
349 ty::Contravariant | ty::Bivariant => { }
354 fn accumulate_from_object_ty(&mut self,
356 region_bound: ty::Region,
357 required_region_bounds: Vec<ty::Region>)
359 // Imagine a type like this:
362 // trait Bar<'c> : 'c { }
364 // &'b (Foo+'c+Bar<'d>)
367 // In this case, the following relationships must hold:
372 // The first conditions is due to the normal region pointer
373 // rules, which say that a reference cannot outlive its
376 // The final condition may be a bit surprising. In particular,
377 // you may expect that it would have been `'c <= 'd`, since
378 // usually lifetimes of outer things are conservative
379 // approximations for inner things. However, it works somewhat
380 // differently with trait objects: here the idea is that if the
381 // user specifies a region bound (`'c`, in this case) it is the
382 // "master bound" that *implies* that bounds from other traits are
383 // all met. (Remember that *all bounds* in a type like
384 // `Foo+Bar+Zed` must be met, not just one, hence if we write
385 // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
388 // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
389 // am looking forward to the future here.
391 // The content of this object type must outlive
392 // `bounds.region_bound`:
393 let r_c = region_bound;
394 self.push_region_constraint_from_top(r_c);
396 // And then, in turn, to be well-formed, the
397 // `region_bound` that user specified must imply the
398 // region bounds required from all of the trait types:
399 for &r_d in &required_region_bounds {
400 // Each of these is an instance of the `'c <= 'b`
402 self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
406 fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
407 where T : TypeFoldable<'tcx>
410 traits::fully_normalize(self.infcx,
411 traits::ObligationCause::misc(self.span, self.body_id),
414 Ok(value) => Ok(value),
416 // I don't like reporting these errors here, but I
417 // don't know where else to report them just now. And
418 // I don't really expect errors to arise here
419 // frequently. I guess the best option would be to
420 // propagate them out.
421 traits::report_fulfillment_errors(self.infcx, &errors);
428 /// Given an object type like `SomeTrait+Send`, computes the lifetime
429 /// bounds that must hold on the elided self type. These are derived
430 /// from the declarations of `SomeTrait`, `Send`, and friends -- if
431 /// they declare `trait SomeTrait : 'static`, for example, then
432 /// `'static` would appear in the list. The hard work is done by
433 /// `ty::required_region_bounds`, see that for more information.
434 pub fn object_region_bounds<'tcx>(
435 tcx: &ty::ctxt<'tcx>,
436 principal: &ty::PolyTraitRef<'tcx>,
437 others: ty::BuiltinBounds)
440 // Since we don't actually *know* the self type for an object,
441 // this "open(err)" serves as a kind of dummy standin -- basically
442 // a skolemized type.
443 let open_ty = tcx.mk_infer(ty::FreshTy(0));
445 // Note that we preserve the overall binding levels here.
446 assert!(!open_ty.has_escaping_regions());
447 let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
448 let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs)));
450 let mut predicates = others.to_predicates(tcx, open_ty);
451 predicates.extend(trait_refs.iter().map(|t| t.to_predicate()));
453 tcx.required_region_bounds(open_ty, predicates)