1 use crate::ty::{self, Lift, Region, TyCtxt};
2 use rustc_data_structures::transitive_relation::TransitiveRelation;
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.
8 // Invariant: only free regions like `'x` or `'static` are stored
9 // in this relation, not scopes.
10 relation: TransitiveRelation<Region<'tcx>>,
13 impl<'tcx> FreeRegionMap<'tcx> {
14 pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
15 self.relation.elements()
18 pub fn is_empty(&self) -> bool {
19 self.relation.is_empty()
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)
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(
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 {
47 match self.relation.postdom_upper_bound(&r_a, &r_b) {
48 None => tcx.mk_region(ty::ReStatic),
52 debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
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
63 fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
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
72 r_a == r_b || self.relation.contains(&r_a, &r_b)
77 fn is_free(r: Region<'_>) -> bool {
79 ty::ReEarlyBound(_) | ty::ReFree(_) => true,
84 fn is_free_or_static(r: Region<'_>) -> bool {
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 })