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.
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
11 // #![warn(deprecated_mode)]
12
13 use middle::ty;
14 use middle::ty_fold;
15 use middle::ty_fold::TypeFolder;
16
17 use collections::HashMap;
18 use util::ppaux::Repr;
19 use util::ppaux;
20
21 // Helper functions related to manipulating region types.
22
23 pub fn replace_late_bound_regions_in_fn_sig(
24 tcx: &ty::ctxt,
25 fn_sig: &ty::FnSig,
26 mapf: |ty::BoundRegion| -> ty::Region)
27 -> (HashMap<ty::BoundRegion,ty::Region>, ty::FnSig) {
28 debug!("replace_late_bound_regions_in_fn_sig({})", fn_sig.repr(tcx));
29
30 let mut map = HashMap::new();
31 let fn_sig = {
32 let mut f = ty_fold::RegionFolder::regions(tcx, |r| {
33 debug!("region r={}", r.to_str());
34 match r {
35 ty::ReLateBound(s, br) if s == fn_sig.binder_id => {
36 *map.find_or_insert_with(br, |_| mapf(br))
37 }
38 _ => r
39 }
40 });
41 ty_fold::super_fold_sig(&mut f, fn_sig)
42 };
43 debug!("resulting map: {}", map);
44 (map, fn_sig)
45 }
46
47 pub fn relate_nested_regions(tcx: &ty::ctxt,
48 opt_region: Option<ty::Region>,
49 ty: ty::t,
50 relate_op: |ty::Region, ty::Region|) {
51 /*!
52 * This rather specialized function walks each region `r` that appear
53 * in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl`
54 * here is the region of any enclosing `&'r T` pointer. If there is
55 * no enclosing pointer, and `opt_region` is Some, then `opt_region.get()`
56 * is used instead. Otherwise, no callback occurs at all).
57 *
58 * Here are some examples to give you an intution:
59 *
60 * - `relate_nested_regions(Some('r1), &'r2 uint)` invokes
61 * - `relate_op('r1, 'r2)`
62 * - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes
63 * - `relate_op('r1, 'r2)`
64 * - `relate_op('r2, 'r3)`
65 * - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes
66 * - `relate_op('r2, 'r3)`
67 * - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes
68 * - `relate_op('r2, 'r3)`
69 * - `relate_op('r2, 'r4)`
70 * - `relate_op('r3, 'r4)`
71 *
72 * This function is used in various pieces of code because we enforce the
73 * constraint that a region pointer cannot outlive the things it points at.
74 * Hence, in the second example above, `'r2` must be a subregion of `'r3`.
75 */
76
77 let mut rr = RegionRelator { tcx: tcx,
78 stack: Vec::new(),
79 relate_op: relate_op };
80 match opt_region {
81 Some(o_r) => { rr.stack.push(o_r); }
82 None => {}
83 }
84 rr.fold_ty(ty);
85
86 struct RegionRelator<'a> {
87 tcx: &'a ty::ctxt,
88 stack: Vec<ty::Region>,
89 relate_op: |ty::Region, ty::Region|: 'a,
90 }
91
92 // FIXME(#10151) -- Define more precisely when a region is
93 // considered "nested". Consider taking variance into account as
94 // well.
95
96 impl<'a> TypeFolder for RegionRelator<'a> {
97 fn tcx<'a>(&'a self) -> &'a ty::ctxt {
98 self.tcx
99 }
100
101 fn fold_ty(&mut self, ty: ty::t) -> ty::t {
102 match ty::get(ty).sty {
103 ty::ty_rptr(r, ty::mt {ty, ..}) => {
104 self.relate(r);
105 self.stack.push(r);
106 ty_fold::super_fold_ty(self, ty);
107 self.stack.pop().unwrap();
108 }
109
110 _ => {
111 ty_fold::super_fold_ty(self, ty);
112 }
113 }
114
115 ty
116 }
117
118 fn fold_region(&mut self, r: ty::Region) -> ty::Region {
119 self.relate(r);
120 r
121 }
122 }
123
124 impl<'a> RegionRelator<'a> {
125 fn relate(&mut self, r_sub: ty::Region) {
126 for &r in self.stack.iter() {
127 if !r.is_bound() && !r_sub.is_bound() {
128 (self.relate_op)(r, r_sub);
129 }
130 }
131 }
132 }
133 }
134
135 pub fn relate_free_regions(tcx: &ty::ctxt, fn_sig: &ty::FnSig) {
136 /*!
137 * This function populates the region map's `free_region_map`.
138 * It walks over the transformed self type and argument types
139 * for each function just before we check the body of that
140 * function, looking for types where you have a borrowed
141 * pointer to other borrowed data (e.g., `&'a &'b [uint]`.
142 * We do not allow references to outlive the things they
143 * point at, so we can assume that `'a <= 'b`.
144 *
145 * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
146 */
147
148 debug!("relate_free_regions >>");
149
150 let mut all_tys = Vec::new();
151 for arg in fn_sig.inputs.iter() {
152 all_tys.push(*arg);
153 }
154
155 for &t in all_tys.iter() {
156 debug!("relate_free_regions(t={})", ppaux::ty_to_str(tcx, t));
157 relate_nested_regions(tcx, None, t, |a, b| {
158 match (&a, &b) {
159 (&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
160 tcx.region_maps.relate_free_regions(free_a, free_b);
161 }
162 _ => {}
163 }
164 })
165 }
166
167 debug!("<< relate_free_regions");
168 }
librustc/middle/typeck/check/regionmanip.rs:86:4-86:4 -struct- definition:
struct RegionRelator<'a> {
tcx: &'a ty::ctxt,
stack: Vec<ty::Region>,
references:- 377: let mut rr = RegionRelator { tcx: tcx,
78: stack: Vec::new(),
--
124: impl<'a> RegionRelator<'a> {
125: fn relate(&mut self, r_sub: ty::Region) {
librustc/middle/typeck/check/regionmanip.rs:46:1-46:1 -fn- definition:
pub fn relate_nested_regions(tcx: &ty::ctxt,
opt_region: Option<ty::Region>,
ty: ty::t,
references:- 2156: debug!("relate_free_regions(t={})", ppaux::ty_to_str(tcx, t));
157: relate_nested_regions(tcx, None, t, |a, b| {
158: match (&a, &b) {
librustc/middle/typeck/check/regionck.rs:
1007: relate_nested_regions(tcx, Some(minimum_lifetime), ty, |r_sub, r_sup| {
1008: debug!("relate_nested_regions(r_sub={}, r_sup={})",
librustc/middle/typeck/check/regionmanip.rs:22:1-22:1 -fn- definition:
pub fn replace_late_bound_regions_in_fn_sig(
tcx: &ty::ctxt,
fn_sig: &ty::FnSig,
references:- 6librustc/middle/typeck/check/method.rs:
1219: // signature with region variables
1220: let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(
1221: tcx, &fn_sig,
librustc/middle/typeck/infer/mod.rs:
794: let (map, fn_sig) =
795: replace_late_bound_regions_in_fn_sig(self.tcx, fsig, |br| {
796: let rvar = self.next_region_var(
librustc/middle/typeck/check/mod.rs:
1930: // signature with region variables
1931: let (_, fn_sig) = replace_late_bound_regions_in_fn_sig(fcx.tcx(), fn_sig, |br| {
1932: fcx.infcx().next_region_var(infer::LateBoundRegion(call_expr.span, br))
--
2278: let (_, sig) =
2279: replace_late_bound_regions_in_fn_sig(
2280: tcx, &cenv.sig,
librustc/middle/typeck/infer/sub.rs:
176: let (skol_map, b_sig) = {
177: replace_late_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, b, |br| {
178: let skol = self.get_ref().infcx.region_vars.new_skolemized(br);