about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-07-13 20:43:29 +0000
committerMichael Goulet <michael@errs.io>2025-07-15 16:02:26 +0000
commite3f643c70670a3e1567b0816502ab247565305f8 (patch)
tree6184ddb319b840211b847d94c09b63d28c2ab201
parent3e7dfaa51027d33f3613ed0203df495784b21f19 (diff)
downloadrust-e3f643c70670a3e1567b0816502ab247565305f8.tar.gz
rust-e3f643c70670a3e1567b0816502ab247565305f8.zip
Consider outlives assumptions when proving auto traits for coroutine interiors
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs27
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs5
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs28
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs15
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs13
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs19
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs22
-rw-r--r--compiler/rustc_infer/src/infer/snapshot/undo_log.rs4
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs11
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs73
-rw-r--r--compiler/rustc_traits/src/coroutine_witnesses.rs2
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs51
-rw-r--r--src/tools/tidy/src/issues.txt2
-rw-r--r--tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs3
-rw-r--r--tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr29
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.rs2
-rw-r--r--tests/ui/async-await/return-type-notation/issue-110963-early.stderr31
-rw-r--r--tests/ui/generic-associated-types/bugs/issue-100013.stderr48
-rw-r--r--tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs (renamed from tests/ui/generic-associated-types/bugs/issue-100013.rs)15
-rw-r--r--tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs21
-rw-r--r--tests/ui/generic-associated-types/issue-92096.rs28
-rw-r--r--tests/ui/generic-associated-types/issue-92096.stderr8
29 files changed, 310 insertions, 204 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index ca636a8c999..fec3e415f75 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
@@ -7,7 +8,7 @@ use rustc_infer::infer::{InferCtxt, SubregionOrigin};
 use rustc_infer::traits::query::type_op::DeeplyNormalize;
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
+    self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions,
 };
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -70,10 +71,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
-        let QueryRegionConstraints { outlives } = query_constraints;
+        let QueryRegionConstraints { outlives, assumptions } = query_constraints;
+        let assumptions =
+            elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
 
         for &(predicate, constraint_category) in outlives {
-            self.convert(predicate, constraint_category);
+            self.convert(predicate, constraint_category, &assumptions);
         }
     }
 
@@ -112,7 +115,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
 
             self.category = outlives_requirement.category;
             self.span = outlives_requirement.blame_span;
-            self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category);
+            self.convert(
+                ty::OutlivesPredicate(subject, outlived_region),
+                self.category,
+                &Default::default(),
+            );
         }
         (self.category, self.span, self.from_closure) = backup;
     }
@@ -121,6 +128,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         &mut self,
         predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
         constraint_category: ConstraintCategory<'tcx>,
+        higher_ranked_assumptions: &FxHashSet<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
     ) {
         let tcx = self.infcx.tcx;
         debug!("generate: constraints at: {:#?}", self.locations);
@@ -150,7 +158,13 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             }
 
             let mut next_outlives_predicates = vec![];
-            for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates {
+            for (pred, constraint_category) in outlives_predicates {
+                // Constraint is implied by a coroutine's well-formedness.
+                if higher_ranked_assumptions.contains(&pred) {
+                    continue;
+                }
+
+                let ty::OutlivesPredicate(k1, r2) = pred;
                 match k1.kind() {
                     GenericArgKind::Lifetime(r1) => {
                         let r1_vid = self.to_region_vid(r1);
@@ -273,7 +287,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
         {
             Ok(TypeOpOutput { output: ty, constraints, .. }) => {
-                if let Some(QueryRegionConstraints { outlives }) = constraints {
+                // FIXME(higher_ranked_auto): What should we do with the assumptions here?
+                if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
                     next_outlives_predicates.extend(outlives.iter().copied());
                 }
                 ty
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index f877e5eaadb..d500088c259 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -131,6 +131,11 @@ pub(crate) fn type_check<'tcx>(
         pre_obligations.is_empty(),
         "there should be no incoming region obligations = {pre_obligations:#?}",
     );
+    let pre_assumptions = infcx.take_registered_region_assumptions();
+    assert!(
+        pre_assumptions.is_empty(),
+        "there should be no incoming region assumptions = {pre_assumptions:#?}",
+    );
 
     debug!(?normalized_inputs_and_output);
 
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index d5d49e3188a..fed56976128 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -116,9 +116,15 @@ impl<'tcx> InferCtxt<'tcx> {
         }
 
         let region_obligations = self.take_registered_region_obligations();
+        let region_assumptions = self.take_registered_region_assumptions();
         debug!(?region_obligations);
         let region_constraints = self.with_region_constraints(|region_constraints| {
-            make_query_region_constraints(tcx, region_obligations, region_constraints)
+            make_query_region_constraints(
+                tcx,
+                region_obligations,
+                region_constraints,
+                region_assumptions,
+            )
         });
         debug!(?region_constraints);
 
@@ -169,6 +175,11 @@ impl<'tcx> InferCtxt<'tcx> {
             self.register_outlives_constraint(predicate, cause);
         }
 
+        for assumption in &query_response.value.region_constraints.assumptions {
+            let assumption = instantiate_value(self.tcx, &result_args, *assumption);
+            self.register_region_assumption(assumption);
+        }
+
         let user_result: R =
             query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
 
@@ -292,6 +303,18 @@ impl<'tcx> InferCtxt<'tcx> {
             }),
         );
 
+        // FIXME(higher_ranked_auto): Optimize this to instantiate all assumptions
+        // at once, rather than calling `instantiate_value` repeatedly which may
+        // create more universes.
+        output_query_region_constraints.assumptions.extend(
+            query_response
+                .value
+                .region_constraints
+                .assumptions
+                .iter()
+                .map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)),
+        );
+
         let user_result: R =
             query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone());
 
@@ -567,6 +590,7 @@ pub fn make_query_region_constraints<'tcx>(
     tcx: TyCtxt<'tcx>,
     outlives_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
     region_constraints: &RegionConstraintData<'tcx>,
+    assumptions: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
 ) -> QueryRegionConstraints<'tcx> {
     let RegionConstraintData { constraints, verifys } = region_constraints;
 
@@ -602,5 +626,5 @@ pub fn make_query_region_constraints<'tcx>(
         }))
         .collect();
 
-    QueryRegionConstraints { outlives }
+    QueryRegionConstraints { outlives, assumptions }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index cc3ad921489..458b21da6ce 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -149,6 +149,13 @@ pub struct InferCtxtInner<'tcx> {
     /// that all type inference variables have been bound and so forth.
     region_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
 
+    /// The outlives bounds that we assume must hold about placeholders that
+    /// come from instantiating the binder of coroutine-witnesses. These bounds
+    /// are deduced from the well-formedness of the witness's types, and are
+    /// necessary because of the way we anonymize the regions in a coroutine,
+    /// which may cause types to no longer be considered well-formed.
+    region_assumptions: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
+
     /// Caches for opaque type inference.
     opaque_type_storage: OpaqueTypeStorage<'tcx>,
 }
@@ -164,7 +171,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
             int_unification_storage: Default::default(),
             float_unification_storage: Default::default(),
             region_constraint_storage: Some(Default::default()),
-            region_obligations: vec![],
+            region_obligations: Default::default(),
+            region_assumptions: Default::default(),
             opaque_type_storage: Default::default(),
         }
     }
@@ -175,6 +183,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
+    pub fn region_assumptions(&self) -> &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>] {
+        &self.region_assumptions
+    }
+
+    #[inline]
     pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> {
         self.projection_cache.with_log(&mut self.undo_log)
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index cb5a33c5c97..2175ff1b4ae 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
 use rustc_middle::{bug, ty};
 use tracing::debug;
@@ -39,6 +39,9 @@ pub struct OutlivesEnvironment<'tcx> {
     /// optimized in the future, though.
     region_bound_pairs: RegionBoundPairs<'tcx>,
     known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
+    /// Assumptions that come from the well-formedness of coroutines that we prove
+    /// auto trait bounds for during the type checking of this body.
+    higher_ranked_assumptions: FxHashSet<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
 }
 
 /// "Region-bound pairs" tracks outlives relations that are known to
@@ -52,6 +55,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         known_type_outlives: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
         extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
+        higher_ranked_assumptions: FxHashSet<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
     ) -> Self {
         let mut region_relation = TransitiveRelationBuilder::default();
         let mut region_bound_pairs = RegionBoundPairs::default();
@@ -88,6 +92,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
             known_type_outlives,
             free_region_map: FreeRegionMap { relation: region_relation.freeze() },
             region_bound_pairs,
+            higher_ranked_assumptions,
         }
     }
 
@@ -102,4 +107,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
     pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] {
         &self.known_type_outlives
     }
+
+    pub fn higher_ranked_assumptions(
+        &self,
+    ) -> &FxHashSet<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
+        &self.higher_ranked_assumptions
+    }
 }
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 2a4544c1140..db668032f1f 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -10,6 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog};
 use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
 use crate::infer::free_regions::RegionRelations;
 use crate::infer::lexical_region_resolve;
+use crate::infer::region_constraints::Constraint;
 
 pub mod env;
 pub mod for_liveness;
@@ -54,18 +55,27 @@ impl<'tcx> InferCtxt<'tcx> {
             }
         };
 
-        let storage = {
+        let mut storage = {
             let mut inner = self.inner.borrow_mut();
             let inner = &mut *inner;
             assert!(
                 self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
                 "region_obligations not empty: {:#?}",
-                inner.region_obligations
+                inner.region_obligations,
             );
             assert!(!UndoLogs::<UndoLog<'_>>::in_snapshot(&inner.undo_log));
             inner.region_constraint_storage.take().expect("regions already resolved")
         };
 
+        // Filter out any region-region outlives assumptions that are implied by
+        // coroutine well-formedness.
+        storage.data.constraints.retain(|(constraint, _)| match *constraint {
+            Constraint::RegSubReg(r1, r2) => !outlives_env
+                .higher_ranked_assumptions()
+                .contains(&ty::OutlivesPredicate(r2.into(), r1)),
+            _ => true,
+        });
+
         let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
 
         let (lexical_region_resolutions, errors) =
@@ -93,6 +103,11 @@ impl<'tcx> InferCtxt<'tcx> {
             "region_obligations not empty: {:#?}",
             self.inner.borrow().region_obligations
         );
+        assert!(
+            self.inner.borrow().region_assumptions.is_empty(),
+            "region_assumptions not empty: {:#?}",
+            self.inner.borrow().region_assumptions
+        );
 
         self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 43504bd77c1..2066cdd717e 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -170,6 +170,21 @@ impl<'tcx> InferCtxt<'tcx> {
         std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
+    pub fn register_region_assumption(
+        &self,
+        assumption: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
+    ) {
+        let mut inner = self.inner.borrow_mut();
+        inner.undo_log.push(UndoLog::PushRegionAssumption);
+        inner.region_assumptions.push(assumption);
+    }
+
+    pub fn take_registered_region_assumptions(
+        &self,
+    ) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
+        std::mem::take(&mut self.inner.borrow_mut().region_assumptions)
+    }
+
     /// Process the region obligations that must be proven (during
     /// `regionck`) for the given `body_id`, given information about
     /// the region bounds in scope and so forth.
@@ -220,6 +235,13 @@ impl<'tcx> InferCtxt<'tcx> {
                 let (sup_type, sub_region) =
                     (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self));
 
+                if outlives_env
+                    .higher_ranked_assumptions()
+                    .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region))
+                {
+                    continue;
+                }
+
                 debug!(?sup_type, ?sub_region, ?origin);
 
                 let outlives = &mut TypeOutlives::new(
diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
index 34e649afedc..40e4c329446 100644
--- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs
@@ -28,6 +28,7 @@ pub(crate) enum UndoLog<'tcx> {
     RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
     PushTypeOutlivesConstraint,
+    PushRegionAssumption,
 }
 
 macro_rules! impl_from {
@@ -77,6 +78,9 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
                 let popped = self.region_obligations.pop();
                 assert_matches!(popped, Some(_), "pushed region constraint but could not pop it");
             }
+            UndoLog::PushRegionAssumption => {
+                self.region_assumptions.pop();
+            }
         }
     }
 }
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 2bbc48b633c..8ce2789cb8e 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -81,13 +81,18 @@ pub struct QueryResponse<'tcx, R> {
 #[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct QueryRegionConstraints<'tcx> {
     pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
+    pub assumptions: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
 }
 
 impl QueryRegionConstraints<'_> {
-    /// Represents an empty (trivially true) set of region
-    /// constraints.
+    /// Represents an empty (trivially true) set of region constraints.
+    ///
+    /// FIXME(higher_ranked_auto): This could still just be true if there are only assumptions?
+    /// Because I don't expect for us to get cases where an assumption from one query would
+    /// discharge a requirement from another query, which is a potential problem if we did throw
+    /// away these assumptions because there were no constraints.
     pub fn is_empty(&self) -> bool {
-        self.outlives.is_empty()
+        self.outlives.is_empty() && self.assumptions.is_empty()
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 068e90b00b8..2b33b8ac9f8 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError};
 use rustc_macros::extension;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, elaborate};
 
 use crate::traits::ScrubbedTraitError;
 use crate::traits::outlives_bounds::InferCtxtExt;
@@ -46,6 +46,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
             }
         }
 
+        // FIXME(-Znext-trait-solver): Normalize these.
+        let higher_ranked_assumptions = infcx.take_registered_region_assumptions();
+        let higher_ranked_assumptions =
+            elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions);
+
         // FIXME: This needs to be modified so that we normalize the known type
         // outlives obligations then elaborate them into their region/type components.
         // Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
@@ -59,6 +64,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
                 assumed_wf_tys,
                 disable_implied_bounds_hack,
             ),
+            higher_ranked_assumptions,
         )
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 1a24254d57f..670589faf9c 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -212,8 +212,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         // Cannot use `take_registered_region_obligations` as we may compute the response
         // inside of a `probe` whenever we have multiple choices inside of the solver.
         let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
+        let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned();
         let region_constraints = self.0.with_region_constraints(|region_constraints| {
-            make_query_region_constraints(self.tcx, region_obligations, region_constraints)
+            make_query_region_constraints(
+                self.tcx,
+                region_obligations,
+                region_constraints,
+                region_assumptions,
+            )
         });
 
         let mut seen = FxHashSet::default();
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index ce5a4edeaaa..f50f01a285b 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -461,6 +461,7 @@ fn impl_intersection_has_negative_obligation(
     // requirements, when proving the negated where clauses below.
     drop(equate_obligations);
     drop(infcx.take_registered_region_obligations());
+    drop(infcx.take_registered_region_assumptions());
     drop(infcx.take_and_reset_region_constraints());
 
     plug_infer_with_placeholders(
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 59d3ac21387..53518038f8d 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -78,7 +78,10 @@ fn implied_outlives_bounds<'a, 'tcx>(
     bounds.retain(|bound| !bound.has_placeholders());
 
     if !constraints.is_empty() {
-        let QueryRegionConstraints { outlives } = constraints;
+        // FIXME(higher_ranked_auto): Should we register assumptions here?
+        // We otherwise would get spurious errors if normalizing an implied
+        // outlives bound required proving some higher-ranked coroutine obl.
+        let QueryRegionConstraints { outlives, assumptions: _ } = constraints;
         let cause = ObligationCause::misc(span, body_id);
         for &(predicate, _) in &outlives {
             infcx.register_outlives_constraint(predicate, &cause);
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 3b549244431..f027ba1c5cb 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -80,6 +80,11 @@ where
         pre_obligations.is_empty(),
         "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}",
     );
+    let pre_assumptions = infcx.take_registered_region_assumptions();
+    assert!(
+        pre_assumptions.is_empty(),
+        "scrape_region_constraints: incoming region assumptions = {pre_assumptions:#?}",
+    );
 
     let value = infcx.commit_if_ok(|_| {
         let ocx = ObligationCtxt::new(infcx);
@@ -100,11 +105,13 @@ where
     let value = infcx.resolve_vars_if_possible(value);
 
     let region_obligations = infcx.take_registered_region_obligations();
+    let region_assumptions = infcx.take_registered_region_assumptions();
     let region_constraint_data = infcx.take_and_reset_region_constraints();
     let region_constraints = query_response::make_query_region_constraints(
         infcx.tcx,
         region_obligations,
         &region_constraint_data,
+        region_assumptions,
     );
 
     if region_constraints.is_empty() {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 4bdf04311a0..018e9748cf0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -180,8 +180,9 @@ where
             span,
         )?;
         output.error_info = error_info;
-        if let Some(QueryRegionConstraints { outlives }) = output.constraints {
+        if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints {
             region_constraints.outlives.extend(outlives.iter().cloned());
+            region_constraints.assumptions.extend(assumptions.iter().cloned());
         }
         output.constraints = if region_constraints.is_empty() {
             None
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index ee8cef20279..488094b15ac 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -411,18 +411,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
             let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty);
 
-            let types = self.constituent_types_for_ty(self_ty)?;
-            let types = self.infcx.enter_forall_and_leak_universe(types);
+            let constituents = self.constituent_types_for_auto_trait(self_ty)?;
+            let constituents = self.infcx.enter_forall_and_leak_universe(constituents);
 
             let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
-            let obligations = self.collect_predicates_for_types(
+            let mut obligations = self.collect_predicates_for_types(
                 obligation.param_env,
-                cause,
+                cause.clone(),
                 obligation.recursion_depth + 1,
                 obligation.predicate.def_id(),
-                types,
+                constituents.types,
             );
 
+            // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types`
+            // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really
+            // matter yet.
+            for assumption in constituents.assumptions {
+                let assumption = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    cause.clone(),
+                    obligation.recursion_depth + 1,
+                    assumption,
+                    &mut obligations,
+                );
+                self.infcx.register_region_assumption(assumption);
+            }
+
             Ok(obligations)
         })
     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 2e65750db25..b46fa9a44d3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -20,6 +20,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::traits::{PredicateObligations, TraitObligation};
+use rustc_macros::{TypeFoldable, TypeVisitable};
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
 pub use rustc_middle::traits::select::*;
@@ -2247,10 +2248,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
     /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
     /// ```
     #[instrument(level = "debug", skip(self), ret)]
-    fn constituent_types_for_ty(
+    fn constituent_types_for_auto_trait(
         &self,
         t: Ty<'tcx>,
-    ) -> Result<ty::Binder<'tcx, Vec<Ty<'tcx>>>, SelectionError<'tcx>> {
+    ) -> Result<ty::Binder<'tcx, AutoImplConstituents<'tcx>>, SelectionError<'tcx>> {
         Ok(match *t.kind() {
             ty::Uint(_)
             | ty::Int(_)
@@ -2261,17 +2262,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Error(_)
             | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Never
-            | ty::Char => ty::Binder::dummy(Vec::new()),
+            | ty::Char => {
+                ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] })
+            }
 
             // This branch is only for `experimental_default_bounds`.
             // Other foreign types were rejected earlier in
             // `assemble_candidates_from_auto_impls`.
-            ty::Foreign(..) => ty::Binder::dummy(Vec::new()),
+            ty::Foreign(..) => {
+                ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] })
+            }
 
-            ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]),
+            ty::UnsafeBinder(ty) => {
+                ty.map_bound(|ty| AutoImplConstituents { types: vec![ty], assumptions: vec![] })
+            }
 
             // Treat this like `struct str([u8]);`
-            ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]),
+            ty::Str => ty::Binder::dummy(AutoImplConstituents {
+                types: vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)],
+                assumptions: vec![],
+            }),
 
             ty::Placeholder(..)
             | ty::Dynamic(..)
@@ -2283,30 +2293,41 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             }
 
             ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
-                ty::Binder::dummy(vec![element_ty])
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: vec![element_ty],
+                    assumptions: vec![],
+                })
             }
 
-            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]),
+            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => {
+                ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
+            }
 
             ty::Tuple(tys) => {
                 // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-                ty::Binder::dummy(tys.iter().collect())
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: tys.iter().collect(),
+                    assumptions: vec![],
+                })
             }
 
             ty::Closure(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
-                ty::Binder::dummy(vec![ty])
+                ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
             }
 
             ty::CoroutineClosure(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
-                ty::Binder::dummy(vec![ty])
+                ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] })
             }
 
             ty::Coroutine(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                 let witness = args.as_coroutine().witness();
-                ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect())
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: [ty].into_iter().chain(iter::once(witness)).collect(),
+                    assumptions: vec![],
+                })
             }
 
             ty::CoroutineWitness(def_id, args) => self
@@ -2314,16 +2335,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 .tcx
                 .coroutine_hidden_types(def_id)
                 .instantiate(self.infcx.tcx, args)
-                .map_bound(|witness| witness.types.to_vec()),
+                .map_bound(|witness| AutoImplConstituents {
+                    types: witness.types.to_vec(),
+                    assumptions: witness.assumptions.to_vec(),
+                }),
 
             // For `PhantomData<T>`, we pass `T`.
             ty::Adt(def, args) if def.is_phantom_data() => {
-                ty::Binder::dummy(args.types().collect())
+                ty::Binder::dummy(AutoImplConstituents {
+                    types: args.types().collect(),
+                    assumptions: vec![],
+                })
             }
 
-            ty::Adt(def, args) => {
-                ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect())
-            }
+            ty::Adt(def, args) => ty::Binder::dummy(AutoImplConstituents {
+                types: def.all_fields().map(|f| f.ty(self.tcx(), args)).collect(),
+                assumptions: vec![],
+            }),
 
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
                 if self.infcx.can_define_opaque_ty(def_id) {
@@ -2333,7 +2361,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     // which enforces a DAG between the functions requiring
                     // the auto trait bounds in question.
                     match self.tcx().type_of_opaque(def_id) {
-                        Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]),
+                        Ok(ty) => ty::Binder::dummy(AutoImplConstituents {
+                            types: vec![ty.instantiate(self.tcx(), args)],
+                            assumptions: vec![],
+                        }),
                         Err(_) => {
                             return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
                         }
@@ -3113,3 +3144,9 @@ pub(crate) enum ProjectionMatchesProjection {
     Ambiguous,
     No,
 }
+
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
+pub(crate) struct AutoImplConstituents<'tcx> {
+    pub types: Vec<Ty<'tcx>>,
+    pub assumptions: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>>,
+}
diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs
index d79777437e6..9e487e380a9 100644
--- a/compiler/rustc_traits/src/coroutine_witnesses.rs
+++ b/compiler/rustc_traits/src/coroutine_witnesses.rs
@@ -66,12 +66,14 @@ fn compute_assumptions<'tcx>(
         let _errors = ocx.select_all_or_error();
 
         let region_obligations = infcx.take_registered_region_obligations();
+        let region_assumptions = infcx.take_registered_region_assumptions();
         let region_constraints = infcx.take_and_reset_region_constraints();
 
         let outlives = make_query_region_constraints(
             tcx,
             region_obligations,
             &region_constraints,
+            region_assumptions,
         )
         .outlives
         .fold_with(&mut OpportunisticRegionResolver::new(&infcx));
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 7ffcf7b5d96..d3c95147649 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -368,3 +368,54 @@ impl<I: Interner, It: Iterator<Item = I::Clause>> Iterator for FilterToTraits<I,
         (0, upper)
     }
 }
+
+pub fn elaborate_outlives_assumptions<I: Interner>(
+    cx: I,
+    assumptions: impl IntoIterator<Item = ty::OutlivesPredicate<I, I::GenericArg>>,
+) -> HashSet<ty::OutlivesPredicate<I, I::GenericArg>> {
+    let mut collected = HashSet::default();
+
+    for ty::OutlivesPredicate(arg1, r2) in assumptions {
+        collected.insert(ty::OutlivesPredicate(arg1, r2));
+        match arg1.kind() {
+            // Elaborate the components of an type, since we may have substituted a
+            // generic coroutine with a more specific type.
+            ty::GenericArgKind::Type(ty1) => {
+                let mut components = smallvec![];
+                push_outlives_components(cx, ty1, &mut components);
+                for c in components {
+                    match c {
+                        Component::Region(r1) => {
+                            if !r1.is_bound() {
+                                collected.insert(ty::OutlivesPredicate(r1.into(), r2));
+                            }
+                        }
+
+                        Component::Param(p) => {
+                            let ty = Ty::new_param(cx, p);
+                            collected.insert(ty::OutlivesPredicate(ty.into(), r2));
+                        }
+
+                        Component::Placeholder(p) => {
+                            let ty = Ty::new_placeholder(cx, p);
+                            collected.insert(ty::OutlivesPredicate(ty.into(), r2));
+                        }
+
+                        Component::Alias(alias_ty) => {
+                            collected.insert(ty::OutlivesPredicate(alias_ty.to_ty(cx).into(), r2));
+                        }
+
+                        Component::UnresolvedInferenceVariable(_) | Component::EscapingAlias(_) => {
+                        }
+                    }
+                }
+            }
+            // Nothing to elaborate for a region.
+            ty::GenericArgKind::Lifetime(_) => {}
+            // Consts don't really participate in outlives.
+            ty::GenericArgKind::Const(_) => {}
+        }
+    }
+
+    collected
+}
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 8b57db23d01..77414bec82d 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1021,7 +1021,6 @@ ui/foreign/issue-91370-foreign-fn-block-impl.rs
 ui/foreign/issue-99276-same-type-lifetimes.rs
 ui/function-pointer/issue-102289.rs
 ui/functions-closures/closure-expected-type/issue-38714.rs
-ui/generic-associated-types/bugs/issue-100013.rs
 ui/generic-associated-types/bugs/issue-80626.rs
 ui/generic-associated-types/bugs/issue-87735.rs
 ui/generic-associated-types/bugs/issue-87755.rs
@@ -1099,7 +1098,6 @@ ui/generic-associated-types/issue-90729.rs
 ui/generic-associated-types/issue-91139.rs
 ui/generic-associated-types/issue-91883.rs
 ui/generic-associated-types/issue-92033.rs
-ui/generic-associated-types/issue-92096.rs
 ui/generic-associated-types/issue-92280.rs
 ui/generic-associated-types/issue-92954.rs
 ui/generic-associated-types/issue-93141.rs
diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs
index e6c295405e2..51945e02352 100644
--- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs
+++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs
@@ -1,5 +1,6 @@
 //@ incremental
 //@ edition: 2021
+//@ check-pass
 
 use std::future::*;
 use std::marker::PhantomData;
@@ -96,8 +97,6 @@ impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> {
 
 fn main() {
     send(async {
-        //~^ ERROR implementation of `FnOnce` is not general enough
-        //~| ERROR implementation of `FnOnce` is not general enough
         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
     });
 }
diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
deleted file mode 100644
index 0d3ee8a9377..00000000000
--- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error: implementation of `FnOnce` is not general enough
-  --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5
-   |
-LL | /     send(async {
-LL | |
-LL | |
-LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
-LL | |     });
-   | |______^ implementation of `FnOnce` is not general enough
-   |
-   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but it actually implements `FnOnce<(&(),)>`
-
-error: implementation of `FnOnce` is not general enough
-  --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5
-   |
-LL | /     send(async {
-LL | |
-LL | |
-LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
-LL | |     });
-   | |______^ implementation of `FnOnce` is not general enough
-   |
-   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
-   = note: ...but it actually implements `FnOnce<(&(),)>`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
index 46b8fbf6f86..7985f2e2de1 100644
--- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs
+++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs
@@ -1,5 +1,5 @@
 //@ edition: 2021
-//@ known-bug: #110963
+//@ check-pass
 
 #![feature(return_type_notation)]
 
diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
deleted file mode 100644
index d6c3bd12aee..00000000000
--- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: implementation of `Send` is not general enough
-  --> $DIR/issue-110963-early.rs:14:5
-   |
-LL | /     spawn(async move {
-LL | |         let mut hc = hc;
-LL | |         if !hc.check().await {
-LL | |             log_health_check_failure().await;
-LL | |         }
-LL | |     });
-   | |______^ implementation of `Send` is not general enough
-   |
-   = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>(..) }`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>(..) }`, for some specific lifetime `'2`
-
-error: implementation of `Send` is not general enough
-  --> $DIR/issue-110963-early.rs:14:5
-   |
-LL | /     spawn(async move {
-LL | |         let mut hc = hc;
-LL | |         if !hc.check().await {
-LL | |             log_health_check_failure().await;
-LL | |         }
-LL | |     });
-   | |______^ implementation of `Send` is not general enough
-   |
-   = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>(..) }`, for any two lifetimes `'0` and `'1`...
-   = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>(..) }`, for some specific lifetime `'2`
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr
deleted file mode 100644
index ff82aebfef9..00000000000
--- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr
+++ /dev/null
@@ -1,48 +0,0 @@
-error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:15:5
-   |
-LL | /     async { // a coroutine checked for autotrait impl `Send`
-LL | |         let x = None::<I::Future<'_, '_>>; // a type referencing GAT
-LL | |         async {}.await; // a yield point
-LL | |     }
-   | |_____^
-   |
-   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:22:5
-   |
-LL | /     async { // a coroutine checked for autotrait impl `Send`
-LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-LL | |         async {}.await; // a yield point
-LL | |     }
-   | |_____^
-   |
-   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-error: lifetime may not live long enough
-  --> $DIR/issue-100013.rs:23:17
-   |
-LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
-   |          --  -- lifetime `'b` defined here
-   |          |
-   |          lifetime `'a` defined here
-LL |     async { // a coroutine checked for autotrait impl `Send`
-LL |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
-   |
-   = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime bound not satisfied
-  --> $DIR/issue-100013.rs:29:5
-   |
-LL | /     async { // a coroutine checked for autotrait impl `Send`
-LL | |         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-LL | |         async {}.await; // a yield point
-LL | |     }
-   | |_____^
-   |
-   = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
-
-error: aborting due to 4 previous errors
-
diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs
index ac72c29c03b..f7762600165 100644
--- a/tests/ui/generic-associated-types/bugs/issue-100013.rs
+++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs
@@ -1,10 +1,6 @@
-//@ check-fail
-//@ known-bug: #100013
+//@ check-pass
 //@ edition: 2021
 
-// We really should accept this, but we need implied bounds between the regions
-// in a coroutine interior.
-
 pub trait FutureIterator {
     type Future<'s, 'cx>: Send
     where
@@ -18,14 +14,7 @@ fn call<I: FutureIterator>() -> impl Send {
     }
 }
 
-fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
-    async { // a coroutine checked for autotrait impl `Send`
-        let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
-        async {}.await; // a yield point
-    }
-}
-
-fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+fn call2<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
     async { // a coroutine checked for autotrait impl `Send`
         let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
         async {}.await; // a yield point
diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs
new file mode 100644
index 00000000000..33a085ad26b
--- /dev/null
+++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs
@@ -0,0 +1,21 @@
+//@ edition:2018
+//@ check-pass
+
+use std::future::Future;
+
+trait Client {
+    type Connecting<'a>: Future + Send
+    where
+        Self: 'a;
+
+    fn connect(&'_ self) -> Self::Connecting<'_>;
+}
+
+fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+where
+    C: Client + Send + Sync,
+{
+    async move { c.connect().await }
+}
+
+fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-92096.rs b/tests/ui/generic-associated-types/issue-92096.rs
deleted file mode 100644
index a34c4179584..00000000000
--- a/tests/ui/generic-associated-types/issue-92096.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//@ edition:2018
-
-use std::future::Future;
-
-trait Client {
-    type Connecting<'a>: Future + Send
-    where
-        Self: 'a;
-
-    fn connect(&'_ self) -> Self::Connecting<'_>;
-}
-
-fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
-where
-    C: Client + Send + Sync,
-{
-    async move { c.connect().await }
-    //~^ ERROR `C` does not live long enough
-    //
-    // FIXME(#71723). This is because we infer at some point a value of
-    //
-    // impl Future<Output = <C as Client>::Connection<'_>>
-    //
-    // and then we somehow fail the WF check because `where C: 'a` is not known,
-    // but I'm not entirely sure how that comes about.
-}
-
-fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-92096.stderr b/tests/ui/generic-associated-types/issue-92096.stderr
deleted file mode 100644
index b9a16cf184e..00000000000
--- a/tests/ui/generic-associated-types/issue-92096.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `C` does not live long enough
-  --> $DIR/issue-92096.rs:17:5
-   |
-LL |     async move { c.connect().await }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-