about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2025-01-03 22:12:43 +0100
committerGitHub <noreply@github.com>2025-01-03 22:12:43 +0100
commitcdfe3d7f4ac5485bb490c5a7f805e9e88c4d1742 (patch)
tree9cd798ee9aa2562aad13d1d7adc3a7f6be88a723
parentd1c7ad081fc27b1e50324955a4cc634ab4b44063 (diff)
parentdd210eca43bbada8835789f85f83fb106d70c637 (diff)
downloadrust-cdfe3d7f4ac5485bb490c5a7f805e9e88c4d1742.tar.gz
rust-cdfe3d7f4ac5485bb490c5a7f805e9e88c4d1742.zip
Rollup merge of #135007 - compiler-errors:outlives-tweaks, r=oli-obk
Some type-outlives computation tweaks

Some tweaks that I wrote when investigating https://github.com/rust-lang/rust/issues/135006.

The only commit that's probably interesting here is f3646748cd9d3cf5a6834f299acd10af1fe99c1b (the first commit). For some reason it was concerned with filtering out param-env outlives clauses when they matched item-bound outlives clauses. However, if you look at the rest of the control flow for that function, not filtering out those bounds doesn't actually affect the behavior materially.
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs28
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs55
2 files changed, 32 insertions, 51 deletions
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index b1d5d688295..0383c81f2af 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -363,6 +363,13 @@ where
             return;
         }
 
+        if alias_ty.has_non_region_infer() {
+            self.tcx
+                .dcx()
+                .span_delayed_bug(origin.span(), "an alias has infers during region solving");
+            return;
+        }
+
         // This case is thorny for inference. The fundamental problem is
         // that there are many cases where we have choice, and inference
         // doesn't like choice (the current region inference in
@@ -388,26 +395,9 @@ where
         // Compute the bounds we can derive from the environment. This
         // is an "approximate" match -- in some cases, these bounds
         // may not apply.
-        let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty);
+        let approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(alias_ty);
         debug!(?approx_env_bounds);
 
-        // Remove outlives bounds that we get from the environment but
-        // which are also deducible from the trait. This arises (cc
-        // #55756) in cases where you have e.g., `<T as Foo<'a>>::Item:
-        // 'a` in the environment but `trait Foo<'b> { type Item: 'b
-        // }` in the trait definition.
-        approx_env_bounds.retain(|bound_outlives| {
-            // OK to skip binder because we only manipulate and compare against other values from
-            // the same binder. e.g. if we have (e.g.) `for<'a> <T as Trait<'a>>::Item: 'a` in
-            // `bound`, the `'a` will be a `^1` (bound, debruijn index == innermost) region. If the
-            // declaration is `trait Trait<'b> { type Item: 'b; }`, then
-            // `projection_declared_bounds_from_trait` will be invoked with `['b => ^1]` and so we
-            // will get `^1` returned.
-            let bound = bound_outlives.skip_binder();
-            let ty::Alias(_, alias_ty) = bound.0.kind() else { bug!("expected AliasTy") };
-            self.verify_bound.declared_bounds_from_definition(*alias_ty).all(|r| r != bound.1)
-        });
-
         // If declared bounds list is empty, the only applicable rule is
         // OutlivesProjectionComponent. If there are inference variables,
         // then, we can break down the outlives into more primitive
@@ -425,7 +415,7 @@ where
         let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque;
         if approx_env_bounds.is_empty()
             && trait_bounds.is_empty()
-            && (alias_ty.has_infer() || is_opaque)
+            && (alias_ty.has_infer_regions() || is_opaque)
         {
             debug!("no declared bounds");
             let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id));
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 247fbc25965..7a21c2883d1 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -192,7 +192,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// Obviously these must be approximate -- they are in fact both *over* and
     /// and *under* approximated:
     ///
-    /// * Over-approximated because we erase regions, so
+    /// * Over-approximated because we don't consider equality of regions.
     /// * Under-approximated because we look for syntactic equality and so for complex types
     ///   like `<T as Foo<fn(&u32, &u32)>>::Item` or whatever we may fail to figure out
     ///   all the subtleties.
@@ -205,13 +205,14 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         erased_ty: Ty<'tcx>,
     ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         let tcx = self.tcx;
+        let mut bounds = vec![];
 
         // To start, collect bounds from user environment. Note that
         // parameter environments are already elaborated, so we don't
         // have to worry about that.
-        let param_bounds = self.caller_bounds.iter().copied().filter(move |outlives_predicate| {
+        bounds.extend(self.caller_bounds.iter().copied().filter(move |outlives_predicate| {
             super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty)
-        });
+        }));
 
         // Next, collect regions we scraped from the well-formedness
         // constraints in the fn signature. To do that, we walk the list
@@ -224,37 +225,27 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         // The problem is that the type of `x` is `&'a A`. To be
         // well-formed, then, A must outlive `'a`, but we don't know that
         // this holds from first principles.
-        let from_region_bound_pairs =
-            self.region_bound_pairs.iter().filter_map(|&OutlivesPredicate(p, r)| {
-                debug!(
-                    "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
-                    (r, p)
-                );
-                // Fast path for the common case.
-                match (&p, erased_ty.kind()) {
-                    // In outlive routines, all types are expected to be fully normalized.
-                    // And therefore we can safely use structural equality for alias types.
-                    (GenericKind::Param(p1), ty::Param(p2)) if p1 == p2 => {}
-                    (GenericKind::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => {}
-                    (GenericKind::Alias(a1), ty::Alias(_, a2)) if a1.def_id == a2.def_id => {}
-                    _ => return None,
-                }
+        bounds.extend(self.region_bound_pairs.iter().filter_map(|&OutlivesPredicate(p, r)| {
+            debug!(
+                "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
+                (r, p)
+            );
+            // Fast path for the common case.
+            match (&p, erased_ty.kind()) {
+                // In outlive routines, all types are expected to be fully normalized.
+                // And therefore we can safely use structural equality for alias types.
+                (GenericKind::Param(p1), ty::Param(p2)) if p1 == p2 => {}
+                (GenericKind::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => {}
+                (GenericKind::Alias(a1), ty::Alias(_, a2)) if a1.def_id == a2.def_id => {}
+                _ => return None,
+            }
 
-                let p_ty = p.to_ty(tcx);
-                let erased_p_ty = self.tcx.erase_regions(p_ty);
-                (erased_p_ty == erased_ty)
-                    .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
-            });
+            let p_ty = p.to_ty(tcx);
+            let erased_p_ty = self.tcx.erase_regions(p_ty);
+            (erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
+        }));
 
-        param_bounds
-            .chain(from_region_bound_pairs)
-            .inspect(|bound| {
-                debug!(
-                    "declared_generic_bounds_from_env_for_erased_ty: result predicate = {:?}",
-                    bound
-                )
-            })
-            .collect()
+        bounds
     }
 
     /// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds