|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | use borrow_check::location::LocationTable;
|
| 12 | +use borrow_check::nll::ToRegionVid; |
12 | 13 | use borrow_check::nll::facts::AllFacts;
|
13 |
| -use borrow_check::nll::universal_regions::UniversalRegions; |
14 | 14 | use borrow_check::nll::type_check::constraint_conversion;
|
15 | 15 | use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
|
| 16 | +use borrow_check::nll::universal_regions::UniversalRegions; |
16 | 17 | use rustc::hir::def_id::DefId;
|
| 18 | +use rustc::infer::outlives::free_region_map::FreeRegionRelations; |
17 | 19 | use rustc::infer::region_constraints::GenericKind;
|
18 | 20 | use rustc::infer::InferCtxt;
|
19 | 21 | use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
|
@@ -93,6 +95,107 @@ impl UniversalRegionRelations<'tcx> {
|
93 | 95 | self.outlives.add(fr_a, fr_b);
|
94 | 96 | self.inverse_outlives.add(fr_b, fr_a);
|
95 | 97 | }
|
| 98 | + |
| 99 | + /// Given two universal regions, returns the postdominating |
| 100 | + /// upper-bound (effectively the least upper bound). |
| 101 | + /// |
| 102 | + /// (See `TransitiveRelation::postdom_upper_bound` for details on |
| 103 | + /// the postdominating upper bound in general.) |
| 104 | + crate fn postdom_upper_bound(&self, fr1: RegionVid, fr2: RegionVid) -> RegionVid { |
| 105 | + assert!(self.universal_regions.is_universal_region(fr1)); |
| 106 | + assert!(self.universal_regions.is_universal_region(fr2)); |
| 107 | + *self |
| 108 | + .inverse_outlives |
| 109 | + .postdom_upper_bound(&fr1, &fr2) |
| 110 | + .unwrap_or(&self.universal_regions.fr_static) |
| 111 | + } |
| 112 | + |
| 113 | + /// Finds an "upper bound" for `fr` that is not local. In other |
| 114 | + /// words, returns the smallest (*) known region `fr1` that (a) |
| 115 | + /// outlives `fr` and (b) is not local. This cannot fail, because |
| 116 | + /// we will always find `'static` at worst. |
| 117 | + /// |
| 118 | + /// (*) If there are multiple competing choices, we pick the "postdominating" |
| 119 | + /// one. See `TransitiveRelation::postdom_upper_bound` for details. |
| 120 | + crate fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid { |
| 121 | + debug!("non_local_upper_bound(fr={:?})", fr); |
| 122 | + self.non_local_bound(&self.inverse_outlives, fr) |
| 123 | + .unwrap_or(self.universal_regions.fr_static) |
| 124 | + } |
| 125 | + |
| 126 | + /// Finds a "lower bound" for `fr` that is not local. In other |
| 127 | + /// words, returns the largest (*) known region `fr1` that (a) is |
| 128 | + /// outlived by `fr` and (b) is not local. This cannot fail, |
| 129 | + /// because we will always find `'static` at worst. |
| 130 | + /// |
| 131 | + /// (*) If there are multiple competing choices, we pick the "postdominating" |
| 132 | + /// one. See `TransitiveRelation::postdom_upper_bound` for details. |
| 133 | + crate fn non_local_lower_bound(&self, fr: RegionVid) -> Option<RegionVid> { |
| 134 | + debug!("non_local_lower_bound(fr={:?})", fr); |
| 135 | + self.non_local_bound(&self.outlives, fr) |
| 136 | + } |
| 137 | + |
| 138 | + /// Helper for `non_local_upper_bound` and |
| 139 | + /// `non_local_lower_bound`. Repeatedly invokes `postdom_parent` |
| 140 | + /// until we find something that is not local. Returns None if we |
| 141 | + /// never do so. |
| 142 | + fn non_local_bound( |
| 143 | + &self, |
| 144 | + relation: &TransitiveRelation<RegionVid>, |
| 145 | + fr0: RegionVid, |
| 146 | + ) -> Option<RegionVid> { |
| 147 | + // This method assumes that `fr0` is one of the universally |
| 148 | + // quantified region variables. |
| 149 | + assert!(self.universal_regions.is_universal_region(fr0)); |
| 150 | + |
| 151 | + let mut external_parents = vec![]; |
| 152 | + let mut queue = vec![&fr0]; |
| 153 | + |
| 154 | + // Keep expanding `fr` into its parents until we reach |
| 155 | + // non-local regions. |
| 156 | + while let Some(fr) = queue.pop() { |
| 157 | + if !self.universal_regions.is_local_free_region(*fr) { |
| 158 | + external_parents.push(fr); |
| 159 | + continue; |
| 160 | + } |
| 161 | + |
| 162 | + queue.extend(relation.parents(fr)); |
| 163 | + } |
| 164 | + |
| 165 | + debug!("non_local_bound: external_parents={:?}", external_parents); |
| 166 | + |
| 167 | + // In case we find more than one, reduce to one for |
| 168 | + // convenience. This is to prevent us from generating more |
| 169 | + // complex constraints, but it will cause spurious errors. |
| 170 | + let post_dom = relation |
| 171 | + .mutual_immediate_postdominator(external_parents) |
| 172 | + .cloned(); |
| 173 | + |
| 174 | + debug!("non_local_bound: post_dom={:?}", post_dom); |
| 175 | + |
| 176 | + post_dom.and_then(|post_dom| { |
| 177 | + // If the mutual immediate postdom is not local, then |
| 178 | + // there is no non-local result we can return. |
| 179 | + if !self.universal_regions.is_local_free_region(post_dom) { |
| 180 | + Some(post_dom) |
| 181 | + } else { |
| 182 | + None |
| 183 | + } |
| 184 | + }) |
| 185 | + } |
| 186 | + |
| 187 | + /// True if fr1 is known to outlive fr2. |
| 188 | + /// |
| 189 | + /// This will only ever be true for universally quantified regions. |
| 190 | + crate fn outlives(&self, fr1: RegionVid, fr2: RegionVid) -> bool { |
| 191 | + self.outlives.contains(&fr1, &fr2) |
| 192 | + } |
| 193 | + |
| 194 | + /// Returns a vector of free regions `x` such that `fr1: x` is |
| 195 | + /// known to hold. |
| 196 | + crate fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<&RegionVid> { |
| 197 | + self.outlives.reachable_from(&fr1) |
| 198 | + } |
96 | 199 | }
|
97 | 200 |
|
98 | 201 | struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
|
@@ -223,3 +326,16 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
|
223 | 326 | }
|
224 | 327 | }
|
225 | 328 | }
|
| 329 | + |
| 330 | +/// This trait is used by the `impl-trait` constraint code to abstract |
| 331 | +/// over the `FreeRegionMap` from lexical regions and |
| 332 | +/// `UniversalRegions` (from NLL)`. |
| 333 | +impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> { |
| 334 | + fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool { |
| 335 | + let shorter = shorter.to_region_vid(); |
| 336 | + assert!(self.universal_regions.is_universal_region(shorter)); |
| 337 | + let longer = longer.to_region_vid(); |
| 338 | + assert!(self.universal_regions.is_universal_region(longer)); |
| 339 | + self.outlives(longer, shorter) |
| 340 | + } |
| 341 | +} |
0 commit comments