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::subst::{ParamSpace, Subst, Substs};
16 use middle::ty_fold::TypeFolder;
20 use std::collections::HashMap;
21 use util::ppaux::Repr;
23 // Helper functions related to manipulating region types.
25 pub fn replace_late_bound_regions_in_fn_sig(
28 mapf: |ty::BoundRegion| -> ty::Region)
29 -> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
30 debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
32 let mut map = HashMap::new();
34 let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
35 debug!("region r={}", r.to_string());
37 ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
38 *map.find_or_insert_with(br, |_| mapf(br))
43 ty_fold::super_fold_sig(&mut f, fn_sig)
45 debug!("resulting map: {}", map);
49 pub enum WfConstraint {
50 RegionSubRegionConstraint(Option<ty::t>, ty::Region, ty::Region),
51 RegionSubParamConstraint(Option<ty::t>, ty::Region, ty::ParamTy),
54 struct Wf<'a, 'tcx: 'a> {
55 tcx: &'a ty::ctxt<'tcx>,
56 stack: Vec<(ty::Region, Option<ty::t>)>,
57 out: Vec<WfConstraint>,
60 pub fn region_wf_constraints(
63 outer_region: ty::Region)
67 * This routine computes the well-formedness constraints that must
68 * hold for the type `ty` to appear in a context with lifetime
72 let mut stack = Vec::new();
73 stack.push((outer_region, None));
74 let mut wf = Wf { tcx: tcx,
77 wf.accumulate_from_ty(ty);
81 impl<'a, 'tcx> Wf<'a, 'tcx> {
82 fn accumulate_from_ty(&mut self, ty: ty::t) {
83 debug!("Wf::accumulate_from_ty(ty={})",
86 match ty::get(ty).sty {
97 // No borrowed content reachable here.
100 ty::ty_closure(box ref c) => {
101 self.accumulate_from_closure_ty(ty, c);
104 ty::ty_unboxed_closure(_, region) => {
105 // An "unboxed closure type" is basically
106 // modeled here as equivalent to a struct like
108 // struct TheClosure<'b> {
112 // where the `'b` is the lifetime bound of the
113 // contents (i.e., all contents must outlive 'b).
114 self.push_region_constraint_from_top(region);
117 ty::ty_trait(ref t) => {
118 self.accumulate_from_object_ty(ty, &t.bounds)
121 ty::ty_enum(def_id, ref substs) |
122 ty::ty_struct(def_id, ref substs) => {
123 self.accumulate_from_adt(ty, def_id, substs)
127 ty::ty_ptr(ty::mt { ty: t, .. }) |
130 self.accumulate_from_ty(t)
133 ty::ty_rptr(r_b, mt) => {
134 self.accumulate_from_rptr(ty, r_b, mt.ty);
138 self.push_param_constraint_from_top(p);
141 ty::ty_tup(ref tuptys) => {
142 for &tupty in tuptys.iter() {
143 self.accumulate_from_ty(tupty);
148 // This should not happen, BUT:
150 // Currently we uncover region relationships on
151 // entering the fn check. We should do this after
152 // the fn check, then we can call this case a bug().
157 format!("Unexpected type encountered while doing wf check: {}",
158 ty.repr(self.tcx)).as_slice());
163 fn accumulate_from_rptr(&mut self,
167 // We are walking down a type like this, and current
168 // position is indicated by caret:
173 // At this point, top of stack will be `'a`. We must
174 // require that `'a <= 'b`.
176 self.push_region_constraint_from_top(r_b);
178 // Now we push `'b` onto the stack, because it must
179 // constrain any borrowed content we find within `T`.
181 self.stack.push((r_b, Some(ty)));
182 self.accumulate_from_ty(ty_b);
183 self.stack.pop().unwrap();
186 fn push_region_constraint_from_top(&mut self,
189 * Pushes a constraint that `r_b` must outlive the
190 * top region on the stack.
193 // Indicates that we have found borrowed content with a lifetime
194 // of at least `r_b`. This adds a constraint that `r_b` must
195 // outlive the region `r_a` on top of the stack.
197 // As an example, imagine walking a type like:
202 // when we hit the inner pointer (indicated by caret), `'a` will
203 // be on top of stack and `'b` will be the lifetime of the content
204 // we just found. So we add constraint that `'a <= 'b`.
206 let &(r_a, opt_ty) = self.stack.last().unwrap();
207 self.push_sub_region_constraint(opt_ty, r_a, r_b);
210 fn push_sub_region_constraint(&mut self,
211 opt_ty: Option<ty::t>,
214 /*! Pushes a constraint that `r_a <= r_b`, due to `opt_ty` */
215 self.out.push(RegionSubRegionConstraint(opt_ty, r_a, r_b));
218 fn push_param_constraint_from_top(&mut self,
219 param_ty: ty::ParamTy) {
221 * Pushes a constraint that `param_ty` must outlive the
222 * top region on the stack.
225 let &(region, opt_ty) = self.stack.last().unwrap();
226 self.push_param_constraint(region, opt_ty, param_ty);
229 fn push_param_constraint(&mut self,
231 opt_ty: Option<ty::t>,
232 param_ty: ty::ParamTy) {
233 /*! Pushes a constraint that `region <= param_ty`, due to `opt_ty` */
234 self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty));
237 fn accumulate_from_adt(&mut self,
242 // The generic declarations from the type, appropriately
243 // substituted for the actual substitutions.
245 ty::lookup_item_type(self.tcx, def_id)
247 .subst(self.tcx, substs);
249 // Variance of each type/region parameter.
250 let variances = ty::item_variances(self.tcx, def_id);
252 for &space in ParamSpace::all().iter() {
253 let region_params = substs.regions().get_slice(space);
254 let region_variances = variances.regions.get_slice(space);
255 let region_param_defs = generics.regions.get_slice(space);
256 assert_eq!(region_params.len(), region_variances.len());
257 for (®ion_param, (®ion_variance, region_param_def)) in
258 region_params.iter().zip(
259 region_variances.iter().zip(
260 region_param_defs.iter()))
262 match region_variance {
263 ty::Covariant | ty::Bivariant => {
264 // Ignore covariant or bivariant region
265 // parameters. To understand why, consider a
266 // struct `Foo<'a>`. If `Foo` contains any
267 // references with lifetime `'a`, then `'a` must
268 // be at least contravariant (and possibly
269 // invariant). The only way to have a covariant
270 // result is if `Foo` contains only a field with a
271 // type like `fn() -> &'a T`; i.e., a bare
272 // function that can produce a reference of
273 // lifetime `'a`. In this case, there is no
274 // *actual data* with lifetime `'a` that is
275 // reachable. (Presumably this bare function is
276 // really returning static data.)
279 ty::Contravariant | ty::Invariant => {
280 // If the parameter is contravariant or
281 // invariant, there may indeed be reachable
282 // data with this lifetime. See other case for
284 self.push_region_constraint_from_top(region_param);
288 for ®ion_bound in region_param_def.bounds.iter() {
289 // The type declared a constraint like
293 // which means that `'a <= 'b` (after
294 // substitution). So take the region we
295 // substituted for `'a` (`region_bound`) and make
296 // it a subregion of the region we substituted
297 // `'b` (`region_param`).
298 self.push_sub_region_constraint(
299 Some(ty), region_bound, region_param);
303 let types = substs.types.get_slice(space);
304 let type_variances = variances.types.get_slice(space);
305 let type_param_defs = generics.types.get_slice(space);
306 assert_eq!(types.len(), type_variances.len());
307 for (&type_param_ty, (&variance, type_param_def)) in
309 type_variances.iter().zip(
310 type_param_defs.iter()))
312 debug!("type_param_ty={} variance={}",
313 type_param_ty.repr(self.tcx),
314 variance.repr(self.tcx));
317 ty::Contravariant | ty::Bivariant => {
318 // As above, except that in this it is a
319 // *contravariant* reference that indices that no
320 // actual data of type T is reachable.
323 ty::Covariant | ty::Invariant => {
324 self.accumulate_from_ty(type_param_ty);
328 // Inspect bounds on this type parameter for any
330 for &r in type_param_def.bounds.opt_region_bound.iter() {
331 self.stack.push((r, Some(ty)));
332 self.accumulate_from_ty(type_param_ty);
333 self.stack.pop().unwrap();
339 fn accumulate_from_closure_ty(&mut self,
344 ty::RegionTraitStore(r_b, _) => {
345 self.push_region_constraint_from_top(r_b);
347 ty::UniqTraitStore => { }
350 self.accumulate_from_object_ty(ty, &c.bounds)
353 fn accumulate_from_object_ty(&mut self,
355 bounds: &ty::ExistentialBounds)
357 // Imagine a type like this:
360 // trait Bar<'c> : 'c { }
362 // &'b (Foo+'c+Bar<'d>)
365 // In this case, the following relationships must hold:
370 // The first conditions is due to the normal region pointer
371 // rules, which say that a reference cannot outlive its
374 // The final condition may be a bit surprising. In particular,
375 // you may expect that it would have been `'c <= 'd`, since
376 // usually lifetimes of outer things are conservative
377 // approximations for inner things. However, it works somewhat
378 // differently with trait objects: here the idea is that if the
379 // user specifies a region bound (`'c`, in this case) it is the
380 // "master bound" that *implies* that bounds from other traits are
381 // all met. (Remember that *all bounds* in a type like
382 // `Foo+Bar+Zed` must be met, not just one, hence if we write
383 // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
386 // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
387 // am looking forward to the future here.
389 // The content of this object type must outlive
390 // `bounds.region_bound`:
391 let r_c = bounds.region_bound;
392 self.push_region_constraint_from_top(r_c);
394 // And then, in turn, to be well-formed, the
395 // `region_bound` that user specified must imply the
396 // region bounds required from all of the trait types:
397 let required_region_bounds =
398 ty::required_region_bounds(self.tcx,
400 bounds.builtin_bounds,
402 for &r_d in required_region_bounds.iter() {
403 // Each of these is an instance of the `'c <= 'b`
405 self.out.push(RegionSubRegionConstraint(Some(ty), r_d, r_c));