]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/free_region_map.rs
Rollup merge of #68288 - RalfJung:fmt, r=oli-obk
[rust.git] / src / librustc / ty / free_region_map.rs
1 use crate::ty::{self, Lift, Region, TyCtxt};
2 use rustc_data_structures::transitive_relation::TransitiveRelation;
3
4 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
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> {
14     pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
15         self.relation.elements()
16     }
17
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
31     /// Computes the least-upper-bound of two free regions. In some
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.
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> {
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 {
45             r_a
46         } else {
47             match self.relation.postdom_upper_bound(&r_a, &r_b) {
48                 None => tcx.mk_region(ty::ReStatic),
49                 Some(r) => *r,
50             }
51         };
52         debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
53         result
54     }
55 }
56
57 /// The NLL region handling code represents free region relations in a
58 /// slightly different way; this trait allows functions to be abstract
59 /// over which version is in use.
60 pub trait FreeRegionRelations<'tcx> {
61     /// Tests whether `r_a <= r_b`. Both must be free regions or
62     /// `'static`.
63     fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
64 }
65
66 impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
67     fn sub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
68         assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
69         if let ty::ReStatic = r_b {
70             true // `'a <= 'static` is just always true, and not stored in the relation explicitly
71         } else {
72             r_a == r_b || self.relation.contains(&r_a, &r_b)
73         }
74     }
75 }
76
77 fn is_free(r: Region<'_>) -> bool {
78     match *r {
79         ty::ReEarlyBound(_) | ty::ReFree(_) => true,
80         _ => false,
81     }
82 }
83
84 fn is_free_or_static(r: Region<'_>) -> bool {
85     match *r {
86         ty::ReStatic => true,
87         _ => is_free(r),
88     }
89 }
90
91 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
92     type Lifted = FreeRegionMap<'tcx>;
93     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
94         self.relation.maybe_map(|&fr| tcx.lift(&fr)).map(|relation| FreeRegionMap { relation })
95     }
96 }