]> git.proxmox.com Git - rustc.git/blame - src/librustc/infer/outlives/free_region_map.rs
New upstream version 1.41.1+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
60c5eb7d 4#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default, HashStable)]
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> {
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.
58pub 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
64impl<'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 78fn is_free(r: Region<'_>) -> bool {
ff7c6d11
XL
79 match *r {
80 ty::ReEarlyBound(_) | ty::ReFree(_) => true,
81 _ => false
82 }
83}
84
0bf4aa26 85fn 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
92impl<'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}