about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2022-06-30 10:26:17 -0400
committerMark Rousskov <mark.simulacrum@gmail.com>2022-07-15 18:50:33 -0400
commit44b476eb2bc9adddd3a247180d57782d8d07f788 (patch)
tree3f6a267be8c10077dc667a041aa107848a98e728 /compiler
parentbcb9c2352bc8f45a5f4e5d57fdb68cfbc6161b24 (diff)
downloadrust-44b476eb2bc9adddd3a247180d57782d8d07f788.tar.gz
rust-44b476eb2bc9adddd3a247180d57782d8d07f788.zip
promote placeholder bounds to 'static obligations
In NLL, when we are promoting a bound out from a closure,
if we have a requirement that `T: 'a` where `'a` is in a
higher universe, we were previously ignoring that, which is
totally wrong. We should be promoting those constraints to `'static`,
since universes are not expressible across closure boundaries.
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs38
-rw-r--r--compiler/rustc_typeck/src/check/intrinsicck.rs2
2 files changed, 34 insertions, 6 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 0fe3b45bc7c..44a0e6205b4 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -916,6 +916,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// The idea then is to lower the `T: 'X` constraint into multiple
     /// bounds -- e.g., if `'X` is the union of two free lifetimes,
     /// `'1` and `'2`, then we would create `T: '1` and `T: '2`.
+    #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
     fn try_promote_type_test(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -933,11 +934,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             return false;
         };
 
+        debug!("subject = {:?}", subject);
+
+        let r_scc = self.constraint_sccs.scc(*lower_bound);
+
+        debug!(
+            "lower_bound = {:?} r_scc={:?} universe={:?}",
+            lower_bound, r_scc, self.scc_universes[r_scc]
+        );
+
+        // If the type test requires that `T: 'a` where `'a` is a
+        // placeholder from another universe, that effectively requires
+        // `T: 'static`, so we have to propagate that requirement.
+        //
+        // It doesn't matter *what* universe because the promoted `T` will
+        // always be in the root universe.
+        if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
+            debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
+            let static_r = self.universal_regions.fr_static;
+            propagated_outlives_requirements.push(ClosureOutlivesRequirement {
+                subject,
+                outlived_free_region: static_r,
+                blame_span: locations.span(body),
+                category: ConstraintCategory::Boring,
+            });
+
+            // we can return here -- the code below might push add'l constraints
+            // but they would all be weaker than this one.
+            return true;
+        }
+
         // For each region outlived by lower_bound find a non-local,
         // universal region (it may be the same region) and add it to
         // `ClosureOutlivesRequirement`.
-        let r_scc = self.constraint_sccs.scc(*lower_bound);
         for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
+            debug!("universal_region_outlived_by ur={:?}", ur);
             // Check whether we can already prove that the "subject" outlives `ur`.
             // If so, we don't have to propagate this requirement to our caller.
             //
@@ -962,8 +993,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 continue;
             }
 
-            debug!("try_promote_type_test: ur={:?}", ur);
-
             let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
             debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
 
@@ -1000,6 +1029,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// will use it's *external name*, which will be a `RegionKind`
     /// variant that can be used in query responses such as
     /// `ReEarlyBound`.
+    #[instrument(level = "debug", skip(self, infcx))]
     fn try_promote_type_test_subject(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -1007,8 +1037,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> Option<ClosureOutlivesSubject<'tcx>> {
         let tcx = infcx.tcx;
 
-        debug!("try_promote_type_test_subject(ty = {:?})", ty);
-
         let ty = tcx.fold_regions(ty, &mut false, |r, _depth| {
             let region_vid = self.to_region_vid(r);
 
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs
index 9ff012f1993..99a9863aabb 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_typeck/src/check/intrinsicck.rs
@@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
-use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
 use rustc_session::lint;
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};