]> git.proxmox.com Git - rustc.git/blame - src/librustc/infer/outlives/free_region_map.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc / infer / outlives / free_region_map.rs
CommitLineData
9fa01778 1use crate::ty::{self, Lift, TyCtxt, Region};
ff7c6d11
XL
2use rustc_data_structures::transitive_relation::TransitiveRelation;
3
0bf4aa26 4#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
ff7c6d11
XL
5pub 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
13impl<'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.
53pub 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
59impl<'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 73fn is_free(r: Region<'_>) -> bool {
ff7c6d11
XL
74 match *r {
75 ty::ReEarlyBound(_) | ty::ReFree(_) => true,
76 _ => false
77 }
78}
79
0bf4aa26 80fn is_free_or_static(r: Region<'_>) -> bool {
ff7c6d11
XL
81 match *r {
82 ty::ReStatic => true,
83 _ => is_free(r),
84 }
85}
86
87impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
88 relation
89});
90
91impl<'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}