]> git.proxmox.com Git - rustc.git/blob - src/librustc/infer/outlives/free_region_map.rs
588a00eb503613af0709ba9036371e428c5bd30e
[rustc.git] / src / librustc / infer / outlives / free_region_map.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use ty::{self, Lift, TyCtxt, Region};
12 use rustc_data_structures::transitive_relation::TransitiveRelation;
13
14 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)]
15 pub struct FreeRegionMap<'tcx> {
16 // Stores the relation `a < b`, where `a` and `b` are regions.
17 //
18 // Invariant: only free regions like `'x` or `'static` are stored
19 // in this relation, not scopes.
20 relation: TransitiveRelation<Region<'tcx>>
21 }
22
23 impl<'tcx> FreeRegionMap<'tcx> {
24 pub fn is_empty(&self) -> bool {
25 self.relation.is_empty()
26 }
27
28 // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
29 // (with the exception that `'static: 'x` is not notable)
30 pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
31 debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
32 if is_free_or_static(sub) && is_free(sup) {
33 self.relation.add(sub, sup)
34 }
35 }
36
37 /// Compute the least-upper-bound of two free regions. In some
38 /// cases, this is more conservative than necessary, in order to
39 /// avoid making arbitrary choices. See
40 /// `TransitiveRelation::postdom_upper_bound` for more details.
41 pub fn lub_free_regions<'a, 'gcx>(&self,
42 tcx: TyCtxt<'a, 'gcx, 'tcx>,
43 r_a: Region<'tcx>,
44 r_b: Region<'tcx>)
45 -> Region<'tcx> {
46 debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
47 assert!(is_free(r_a));
48 assert!(is_free(r_b));
49 let result = if r_a == r_b { r_a } else {
50 match self.relation.postdom_upper_bound(&r_a, &r_b) {
51 None => tcx.mk_region(ty::ReStatic),
52 Some(r) => *r,
53 }
54 };
55 debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result);
56 result
57 }
58 }
59
60 /// The NLL region handling code represents free region relations in a
61 /// slightly different way; this trait allows functions to be abstract
62 /// over which version is in use.
63 pub trait FreeRegionRelations<'tcx> {
64 /// Tests whether `r_a <= r_b`. Both must be free regions or
65 /// `'static`.
66 fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
67 }
68
69 impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
70 fn sub_free_regions(&self,
71 r_a: Region<'tcx>,
72 r_b: Region<'tcx>)
73 -> bool {
74 assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
75 if let ty::ReStatic = r_b {
76 true // `'a <= 'static` is just always true, and not stored in the relation explicitly
77 } else {
78 r_a == r_b || self.relation.contains(&r_a, &r_b)
79 }
80 }
81 }
82
83 fn is_free(r: Region<'_>) -> bool {
84 match *r {
85 ty::ReEarlyBound(_) | ty::ReFree(_) => true,
86 _ => false
87 }
88 }
89
90 fn is_free_or_static(r: Region<'_>) -> bool {
91 match *r {
92 ty::ReStatic => true,
93 _ => is_free(r),
94 }
95 }
96
97 impl_stable_hash_for!(struct FreeRegionMap<'tcx> {
98 relation
99 });
100
101 impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
102 type Lifted = FreeRegionMap<'tcx>;
103 fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<FreeRegionMap<'tcx>> {
104 self.relation.maybe_map(|&fr| fr.lift_to_tcx(tcx))
105 .map(|relation| FreeRegionMap { relation })
106 }
107 }