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)];
16 use middle::typeck::isr_alist;
17 use util::common::indenter;
18 use util::ppaux::region_to_str;
21 use extra::list::Cons;
23 // Helper functions related to manipulating region types.
25 pub fn replace_bound_regions_in_fn_sig(
28 opt_self_ty: Option<ty::t>,
30 mapf: &fn(ty::bound_region) -> ty::Region)
31 -> (isr_alist, Option<ty::t>, ty::FnSig)
33 let mut all_tys = ty::tys_in_fn_sig(fn_sig);
35 for &self_ty in opt_self_ty.iter() {
36 all_tys.push(self_ty);
39 for &t in opt_self_ty.iter() { all_tys.push(t) }
41 debug!("replace_bound_regions_in_fn_sig(self_ty=%?, fn_sig=%s, \
43 opt_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
44 ppaux::fn_sig_to_str(tcx, fn_sig),
45 all_tys.map(|t| ppaux::ty_to_str(tcx, *t)));
48 let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| {
52 let new_fn_sig = ty::fold_sig(fn_sig, |t| {
53 replace_bound_regions(tcx, isr, t)
55 let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, *t));
57 debug!("result of replace_bound_regions_in_fn_sig: \
60 new_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
61 ppaux::fn_sig_to_str(tcx, &new_fn_sig));
63 return (isr, new_self_ty, new_fn_sig);
65 // Takes `isr`, a (possibly empty) mapping from in-scope region
66 // names ("isr"s) to their corresponding regions; `tys`, a list of
67 // types, and `to_r`, a closure that takes a bound_region and
68 // returns a region. Returns an updated version of `isr`,
69 // extended with the in-scope region names from all of the bound
70 // regions appearing in the types in the `tys` list (if they're
71 // not in `isr` already), with each of those in-scope region names
72 // mapped to a region that's the result of applying `to_r` to
74 fn create_bound_region_mapping(
78 to_r: &fn(ty::bound_region) -> ty::Region) -> isr_alist {
80 // Takes `isr` (described above), `to_r` (described above),
81 // and `r`, a region. If `r` is anything other than a bound
82 // region, or if it's a bound region that already appears in
83 // `isr`, then we return `isr` unchanged. If `r` is a bound
84 // region that doesn't already appear in `isr`, we return an
85 // updated isr_alist that now contains a mapping from `r` to
86 // the result of calling `to_r` on it.
87 fn append_isr(isr: isr_alist,
88 to_r: &fn(ty::bound_region) -> ty::Region,
89 r: ty::Region) -> isr_alist {
91 ty::re_empty | ty::re_free(*) | ty::re_static | ty::re_scope(_) |
98 None => @Cons((br, to_r(br)), isr)
104 // For each type `ty` in `tys`...
105 do tys.iter().fold(isr) |isr, ty| {
108 // Using fold_regions is inefficient, because it
109 // constructs new types, but it avoids code duplication in
110 // terms of locating all the regions within the various
111 // kinds of types. This had already caused me several
112 // bugs so I decided to switch over.
113 do ty::fold_regions(tcx, *ty) |r, in_fn| {
114 if !in_fn { isr = append_isr(isr, |br| to_r(br), r); }
122 // Takes `isr`, a mapping from in-scope region names ("isr"s) to
123 // their corresponding regions; and `ty`, a type. Returns an
124 // updated version of `ty`, in which bound regions in `ty` have
125 // been replaced with the corresponding bindings in `isr`.
126 fn replace_bound_regions(
129 ty: ty::t) -> ty::t {
131 do ty::fold_regions(tcx, ty) |r, in_fn| {
133 // As long as we are not within a fn() type, `&T` is
134 // mapped to the free region anon_r. But within a fn
135 // type, it remains bound.
136 ty::re_bound(ty::br_anon(_)) if in_fn => r,
138 ty::re_bound(br) => {
140 // In most cases, all named, bound regions will be
141 // mapped to some free region.
144 // But in the case of a fn() type, there may be
145 // named regions within that remain bound:
149 fmt!("Bound region not found in \
150 in_scope_regions list: %s",
151 region_to_str(tcx, "", false, r)));
156 // Free regions like these just stay the same:
168 pub fn relate_nested_regions(
170 opt_region: Option<ty::Region>,
172 relate_op: &fn(ty::Region, ty::Region))
176 * This rather specialized function walks each region `r` that appear
177 * in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl`
178 * here is the region of any enclosing `&'r T` pointer. If there is
179 * no enclosing pointer, and `opt_region` is Some, then `opt_region.get()`
180 * is used instead. Otherwise, no callback occurs at all).
182 * Here are some examples to give you an intution:
184 * - `relate_nested_regions(Some('r1), &'r2 uint)` invokes
185 * - `relate_op('r1, 'r2)`
186 * - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes
187 * - `relate_op('r1, 'r2)`
188 * - `relate_op('r2, 'r3)`
189 * - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes
190 * - `relate_op('r2, 'r3)`
191 * - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes
192 * - `relate_op('r2, 'r3)`
193 * - `relate_op('r2, 'r4)`
194 * - `relate_op('r3, 'r4)`
196 * This function is used in various pieces of code because we enforce the
197 * constraint that a region pointer cannot outlive the things it points at.
198 * Hence, in the second example above, `'r2` must be a subregion of `'r3`.
201 let mut the_stack = ~[];
202 for &r in opt_region.iter() { the_stack.push(r); }
203 walk_ty(tcx, &mut the_stack, ty, relate_op);
205 fn walk_ty(tcx: ty::ctxt,
206 the_stack: &mut ~[ty::Region],
208 relate_op: &fn(ty::Region, ty::Region))
210 match ty::get(ty).sty {
211 ty::ty_rptr(r, ref mt) |
212 ty::ty_evec(ref mt, ty::vstore_slice(r)) => {
213 relate(*the_stack, r, |x,y| relate_op(x,y));
215 walk_ty(tcx, the_stack, mt.ty, |x,y| relate_op(x,y));
219 ty::fold_regions_and_ty(
222 |r| { relate( *the_stack, r, |x,y| relate_op(x,y)); r },
223 |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t },
224 |t| { walk_ty(tcx, the_stack, t, |x,y| relate_op(x,y)); t });
229 fn relate(the_stack: &[ty::Region],
231 relate_op: &fn(ty::Region, ty::Region))
233 for &r in the_stack.iter() {
234 if !r.is_bound() && !r_sub.is_bound() {
241 pub fn relate_free_regions(
243 self_ty: Option<ty::t>,
247 * This function populates the region map's `free_region_map`.
248 * It walks over the transformed self type and argument types
249 * for each function just before we check the body of that
250 * function, looking for types where you have a borrowed
251 * pointer to other borrowed data (e.g., `&'a &'b [uint]`.
252 * We do not allow borrowed pointers to outlive the things they
253 * point at, so we can assume that `'a <= 'b`.
255 * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
258 debug!("relate_free_regions >>");
260 let mut all_tys = ~[];
261 for arg in fn_sig.inputs.iter() {
264 for &t in self_ty.iter() {
268 for &t in all_tys.iter() {
269 debug!("relate_free_regions(t=%s)", ppaux::ty_to_str(tcx, t));
270 relate_nested_regions(tcx, None, t, |a, b| {
272 (&ty::re_free(free_a), &ty::re_free(free_b)) => {
273 tcx.region_maps.relate_free_regions(free_a, free_b);
280 debug!("<< relate_free_regions");