]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::ty::{self, Lift, TyCtxt, Region}; |
ff7c6d11 XL |
2 | use rustc_data_structures::transitive_relation::TransitiveRelation; |
3 | ||
0bf4aa26 | 4 | #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] |
ff7c6d11 XL |
5 | pub struct FreeRegionMap<'tcx> { |
6 | // Stores the relation `a < b`, where `a` and `b` are regions. | |
7 | // | |
8 | // Invariant: only free regions like `'x` or `'static` are stored | |
9 | // in this relation, not scopes. | |
10 | relation: TransitiveRelation<Region<'tcx>> | |
11 | } | |
12 | ||
13 | impl<'tcx> FreeRegionMap<'tcx> { | |
ff7c6d11 XL |
14 | pub fn is_empty(&self) -> bool { |
15 | self.relation.is_empty() | |
16 | } | |
17 | ||
18 | // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`. | |
19 | // (with the exception that `'static: 'x` is not notable) | |
20 | pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { | |
21 | debug!("relate_regions(sub={:?}, sup={:?})", sub, sup); | |
22 | if is_free_or_static(sub) && is_free(sup) { | |
23 | self.relation.add(sub, sup) | |
24 | } | |
25 | } | |
26 | ||
9fa01778 | 27 | /// Computes the least-upper-bound of two free regions. In some |
ff7c6d11 XL |
28 | /// cases, this is more conservative than necessary, in order to |
29 | /// avoid making arbitrary choices. See | |
30 | /// `TransitiveRelation::postdom_upper_bound` for more details. | |
31 | pub fn lub_free_regions<'a, 'gcx>(&self, | |
32 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
33 | r_a: Region<'tcx>, | |
34 | r_b: Region<'tcx>) | |
35 | -> Region<'tcx> { | |
36 | debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b); | |
37 | assert!(is_free(r_a)); | |
38 | assert!(is_free(r_b)); | |
39 | let result = if r_a == r_b { r_a } else { | |
40 | match self.relation.postdom_upper_bound(&r_a, &r_b) { | |
41 | None => tcx.mk_region(ty::ReStatic), | |
42 | Some(r) => *r, | |
43 | } | |
44 | }; | |
45 | debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); | |
46 | result | |
47 | } | |
48 | } | |
49 | ||
50 | /// The NLL region handling code represents free region relations in a | |
51 | /// slightly different way; this trait allows functions to be abstract | |
52 | /// over which version is in use. | |
53 | pub trait FreeRegionRelations<'tcx> { | |
54 | /// Tests whether `r_a <= r_b`. Both must be free regions or | |
55 | /// `'static`. | |
56 | fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool; | |
57 | } | |
58 | ||
59 | impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> { | |
60 | fn sub_free_regions(&self, | |
61 | r_a: Region<'tcx>, | |
62 | r_b: Region<'tcx>) | |
63 | -> bool { | |
64 | assert!(is_free_or_static(r_a) && is_free_or_static(r_b)); | |
65 | if let ty::ReStatic = r_b { | |
66 | true // `'a <= 'static` is just always true, and not stored in the relation explicitly | |
67 | } else { | |
68 | r_a == r_b || self.relation.contains(&r_a, &r_b) | |
69 | } | |
70 | } | |
71 | } | |
72 | ||
0bf4aa26 | 73 | fn is_free(r: Region<'_>) -> bool { |
ff7c6d11 XL |
74 | match *r { |
75 | ty::ReEarlyBound(_) | ty::ReFree(_) => true, | |
76 | _ => false | |
77 | } | |
78 | } | |
79 | ||
0bf4aa26 | 80 | fn is_free_or_static(r: Region<'_>) -> bool { |
ff7c6d11 XL |
81 | match *r { |
82 | ty::ReStatic => true, | |
83 | _ => is_free(r), | |
84 | } | |
85 | } | |
86 | ||
87 | impl_stable_hash_for!(struct FreeRegionMap<'tcx> { | |
88 | relation | |
89 | }); | |
90 | ||
91 | impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> { | |
92 | type Lifted = FreeRegionMap<'tcx>; | |
93 | fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<FreeRegionMap<'tcx>> { | |
94 | self.relation.maybe_map(|&fr| fr.lift_to_tcx(tcx)) | |
95 | .map(|relation| FreeRegionMap { relation }) | |
96 | } | |
97 | } |