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