about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2023-03-03 06:25:52 +0300
committerAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2023-03-03 14:10:25 +0300
commit9d74bff829174c4a707ee2ab17ac6e01490d9a6a (patch)
treef85af9a80e86e72987b53df08e71a6daeee617af
parent09524bfd5ace53bfecddd669a5d90e5495eaa3de (diff)
downloadrust-9d74bff829174c4a707ee2ab17ac6e01490d9a6a.tar.gz
rust-9d74bff829174c4a707ee2ab17ac6e01490d9a6a.zip
smarter algorithm for finding an equal region
Smarter and simpler!
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs76
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs25
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs4
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.stderr12
4 files changed, 11 insertions, 106 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index eadd9bd7dfe..e526ccd71ca 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1098,51 +1098,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let tcx = infcx.tcx;
 
         let ty = tcx.fold_regions(ty, |r, _depth| {
-            let region_vid = self.to_region_vid(r);
+            let r_vid = self.to_region_vid(r);
+            let r_scc = self.constraint_sccs.scc(r_vid);
 
             // The challenge if this. We have some region variable `r`
             // whose value is a set of CFG points and universal
             // regions. We want to find if that set is *equivalent* to
             // any of the named regions found in the closure.
-            //
-            // To do so, we compute the
-            // `non_local_universal_upper_bound`. This will be a
-            // non-local, universal region that is greater than `r`.
-            // However, it might not be *contained* within `r`, so
-            // then we further check whether this bound is contained
-            // in `r`. If so, we can say that `r` is equivalent to the
-            // bound.
-            //
-            // Let's work through a few examples. For these, imagine
-            // that we have 3 non-local regions (I'll denote them as
-            // `'static`, `'a`, and `'b`, though of course in the code
-            // they would be represented with indices) where:
-            //
-            // - `'static: 'a`
-            // - `'static: 'b`
-            //
-            // First, let's assume that `r` is some existential
-            // variable with an inferred value `{'a, 'static}` (plus
-            // some CFG nodes). In this case, the non-local upper
-            // bound is `'static`, since that outlives `'a`. `'static`
-            // is also a member of `r` and hence we consider `r`
-            // equivalent to `'static` (and replace it with
-            // `'static`).
-            //
-            // Now let's consider the inferred value `{'a, 'b}`. This
-            // means `r` is effectively `'a | 'b`. I'm not sure if
-            // this can come about, actually, but assuming it did, we
-            // would get a non-local upper bound of `'static`. Since
-            // `'static` is not contained in `r`, we would fail to
-            // find an equivalent.
-            let upper_bound = self.non_local_universal_upper_bound(region_vid);
-            if self.region_contains(region_vid, upper_bound) {
-                tcx.mk_re_var(upper_bound)
-            } else {
+            // To do so, we simply check every candidate `u_r` for equality.
+            self.scc_values
+                .universal_regions_outlived_by(r_scc)
+                .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
+                .find(|&u_r| self.eval_equal(u_r, r_vid))
+                .map(|u_r| tcx.mk_re_var(u_r))
                 // In the case of a failure, use `ReErased`. We will eventually
                 // return `None` in this case.
-                tcx.lifetimes.re_erased
-            }
+                .unwrap_or(tcx.lifetimes.re_erased)
         });
 
         debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
@@ -1155,35 +1126,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::new(tcx, ty)))
     }
 
-    /// Given some universal or existential region `r`, finds a
-    /// non-local, universal region `r+` that outlives `r` at entry to (and
-    /// exit from) the closure. In the worst case, this will be
-    /// `'static`.
-    ///
-    /// This is used for two purposes. First, if we are propagated
-    /// some requirement `T: r`, we can use this method to enlarge `r`
-    /// to something we can encode for our creator (which only knows
-    /// about non-local, universal regions). It is also used when
-    /// encoding `T` as part of `try_promote_type_test_subject` (see
-    /// that fn for details).
-    ///
-    /// This is based on the result `'y` of `universal_upper_bound`,
-    /// except that it converts further takes the non-local upper
-    /// bound of `'y`, so that the final result is non-local.
-    fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
-        debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
-
-        let lub = self.universal_upper_bound(r);
-
-        // Grow further to get smallest universal region known to
-        // creator.
-        let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
-
-        debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub);
-
-        non_local_lub
-    }
-
     /// Returns a universally quantified region that outlives the
     /// value of `r` (`r` may be existentially or universally
     /// quantified).
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index e2f897a89e8..4004966c40a 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -93,31 +93,6 @@ impl UniversalRegionRelations<'_> {
         res
     }
 
-    /// Returns the "postdominating" bound of the set of
-    /// `non_local_upper_bounds` for the given region.
-    pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
-        let upper_bounds = self.non_local_upper_bounds(fr);
-
-        // In case we find more than one, reduce to one for
-        // convenience. This is to prevent us from generating more
-        // complex constraints, but it will cause spurious errors.
-        let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
-
-        debug!("non_local_bound: post_dom={:?}", post_dom);
-
-        post_dom
-            .and_then(|post_dom| {
-                // If the mutual immediate postdom is not local, then
-                // there is no non-local result we can return.
-                if !self.universal_regions.is_local_free_region(post_dom) {
-                    Some(post_dom)
-                } else {
-                    None
-                }
-            })
-            .unwrap_or(self.universal_regions.fr_static)
-    }
-
     /// Finds a "lower bound" for `fr` that is not local. In other
     /// words, returns the largest (*) known region `fr1` that (a) is
     /// outlived by `fr` and (b) is not local.
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs b/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs
index 623e5e1a71f..d8772e86894 100644
--- a/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs
+++ b/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs
@@ -1,5 +1,5 @@
-// chek-fail
-// known-bug: #108639
+// See #108639 for description.
+// check-pass
 
 trait Trait {
     type Item<'a>: 'a;
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.stderr b/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.stderr
deleted file mode 100644
index 83f0b64d5a7..00000000000
--- a/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0310]: the associated type `<I as Trait>::Item<'_>` may not live long enough
-  --> $DIR/type-test-subject-non-trivial-region.rs:14:9
-   |
-LL |         assert_static(a);
-   |         ^^^^^^^^^^^^^^^^
-   |
-   = help: consider adding an explicit lifetime bound `<I as Trait>::Item<'_>: 'static`...
-   = note: ...so that the type `<I as Trait>::Item<'_>` will meet its required lifetime bounds
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0310`.